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

« 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-04-17 14:50:28 UTC
  • mfrom: (3.1.59 sid)
  • Revision ID: package-import@ubuntu.com-20140417145028-j3p3dwvp8ggpzvaf
Tags: 3.5.1-1
ImportedĀ upstreamĀ releaseĀ 3.5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
describe 'The type calculator' do
5
5
  let(:calculator) {  Puppet::Pops::Types::TypeCalculator.new() }
6
6
 
 
7
  def range_t(from, to)
 
8
   t = Puppet::Pops::Types::PIntegerType.new
 
9
   t.from = from
 
10
   t.to = to
 
11
   t
 
12
  end
 
13
 
 
14
  def pattern_t(*patterns)
 
15
    Puppet::Pops::Types::TypeFactory.pattern(*patterns)
 
16
  end
 
17
 
 
18
  def regexp_t(pattern)
 
19
    Puppet::Pops::Types::TypeFactory.regexp(pattern)
 
20
  end
 
21
 
 
22
  def string_t(*strings)
 
23
    Puppet::Pops::Types::TypeFactory.string(*strings)
 
24
  end
 
25
 
 
26
  def enum_t(*strings)
 
27
    Puppet::Pops::Types::TypeFactory.enum(*strings)
 
28
  end
 
29
 
 
30
  def variant_t(*types)
 
31
    Puppet::Pops::Types::TypeFactory.variant(*types)
 
32
  end
 
33
 
 
34
  def integer_t()
 
35
    Puppet::Pops::Types::TypeFactory.integer()
 
36
  end
 
37
 
 
38
  def array_t(t)
 
39
    Puppet::Pops::Types::TypeFactory.array_of(t)
 
40
  end
 
41
 
 
42
  def hash_t(k,v)
 
43
    Puppet::Pops::Types::TypeFactory.hash_of(v, k)
 
44
  end
 
45
 
 
46
  def data_t()
 
47
    Puppet::Pops::Types::TypeFactory.data()
 
48
  end
 
49
 
 
50
  def factory()
 
51
    Puppet::Pops::Types::TypeFactory
 
52
  end
 
53
 
 
54
  def collection_t()
 
55
    Puppet::Pops::Types::TypeFactory.collection()
 
56
  end
 
57
 
 
58
  def tuple_t(*types)
 
59
    Puppet::Pops::Types::TypeFactory.tuple(*types)
 
60
  end
 
61
 
 
62
  def struct_t(type_hash)
 
63
    Puppet::Pops::Types::TypeFactory.struct(type_hash)
 
64
  end
 
65
 
 
66
  def types
 
67
    Puppet::Pops::Types
 
68
  end
 
69
 
 
70
  shared_context "types_setup" do
 
71
 
 
72
    def all_types
 
73
      [ Puppet::Pops::Types::PObjectType,
 
74
        Puppet::Pops::Types::PNilType,
 
75
        Puppet::Pops::Types::PDataType,
 
76
        Puppet::Pops::Types::PScalarType,
 
77
        Puppet::Pops::Types::PStringType,
 
78
        Puppet::Pops::Types::PNumericType,
 
79
        Puppet::Pops::Types::PIntegerType,
 
80
        Puppet::Pops::Types::PFloatType,
 
81
        Puppet::Pops::Types::PRegexpType,
 
82
        Puppet::Pops::Types::PBooleanType,
 
83
        Puppet::Pops::Types::PCollectionType,
 
84
        Puppet::Pops::Types::PArrayType,
 
85
        Puppet::Pops::Types::PHashType,
 
86
        Puppet::Pops::Types::PRubyType,
 
87
        Puppet::Pops::Types::PHostClassType,
 
88
        Puppet::Pops::Types::PResourceType,
 
89
        Puppet::Pops::Types::PPatternType,
 
90
        Puppet::Pops::Types::PEnumType,
 
91
        Puppet::Pops::Types::PVariantType,
 
92
        Puppet::Pops::Types::PStructType,
 
93
        Puppet::Pops::Types::PTupleType,
 
94
      ]
 
95
    end
 
96
 
 
97
    def scalar_types
 
98
      # PVariantType is also scalar, if its types are all Scalar
 
99
      [
 
100
        Puppet::Pops::Types::PScalarType,
 
101
        Puppet::Pops::Types::PStringType,
 
102
        Puppet::Pops::Types::PNumericType,
 
103
        Puppet::Pops::Types::PIntegerType,
 
104
        Puppet::Pops::Types::PFloatType,
 
105
        Puppet::Pops::Types::PRegexpType,
 
106
        Puppet::Pops::Types::PBooleanType,
 
107
        Puppet::Pops::Types::PPatternType,
 
108
        Puppet::Pops::Types::PEnumType,
 
109
      ]
 
110
    end
 
111
 
 
112
    def numeric_types
 
113
      # PVariantType is also numeric, if its types are all numeric
 
114
      [
 
115
        Puppet::Pops::Types::PNumericType,
 
116
        Puppet::Pops::Types::PIntegerType,
 
117
        Puppet::Pops::Types::PFloatType,
 
118
      ]
 
119
    end
 
120
 
 
121
    def string_types
 
122
      # PVariantType is also string type, if its types are all compatible
 
123
      [
 
124
        Puppet::Pops::Types::PStringType,
 
125
        Puppet::Pops::Types::PPatternType,
 
126
        Puppet::Pops::Types::PEnumType,
 
127
      ]
 
128
    end
 
129
 
 
130
    def collection_types
 
131
      # PVariantType is also string type, if its types are all compatible
 
132
      [
 
133
        Puppet::Pops::Types::PCollectionType,
 
134
        Puppet::Pops::Types::PHashType,
 
135
        Puppet::Pops::Types::PArrayType,
 
136
        Puppet::Pops::Types::PStructType,
 
137
        Puppet::Pops::Types::PTupleType,
 
138
      ]
 
139
    end
 
140
 
 
141
    def data_compatible_types
 
142
      result = scalar_types
 
143
      result << Puppet::Pops::Types::PDataType
 
144
      result << array_t(types::PDataType.new)
 
145
      result << types::TypeFactory.hash_of_data
 
146
      result << Puppet::Pops::Types::PNilType
 
147
      tmp = tuple_t(types::PDataType.new)
 
148
      result << (tmp)
 
149
      tmp.size_type = range_t(0, nil)
 
150
      result
 
151
    end
 
152
 
 
153
    def type_from_class(c)
 
154
      c.is_a?(Class) ? c.new : c
 
155
    end
 
156
  end
 
157
 
7
158
  context 'when inferring ruby' do
8
159
 
9
160
    it 'fixnum translates to PIntegerType' do
22
173
      calculator.infer('foo').class.should == Puppet::Pops::Types::PStringType
23
174
    end
24
175
 
 
176
    it 'inferred string type knows the string value' do
 
177
      t = calculator.infer('foo')
 
178
      t.class.should == Puppet::Pops::Types::PStringType
 
179
      t.values.should == ['foo']
 
180
    end
 
181
 
25
182
    it 'boolean true translates to PBooleanType' do
26
183
      calculator.infer(true).class.should == Puppet::Pops::Types::PBooleanType
27
184
    end
30
187
      calculator.infer(false).class.should == Puppet::Pops::Types::PBooleanType
31
188
    end
32
189
 
33
 
    it 'regexp translates to PPatternType' do
34
 
      calculator.infer(/^a regular exception$/).class.should == Puppet::Pops::Types::PPatternType
 
190
    it 'regexp translates to PRegexpType' do
 
191
      calculator.infer(/^a regular expression$/).class.should == Puppet::Pops::Types::PRegexpType
35
192
    end
36
193
 
37
194
    it 'nil translates to PNilType' do
38
195
      calculator.infer(nil).class.should == Puppet::Pops::Types::PNilType
39
196
    end
40
197
 
 
198
    it ':undef translates to PNilType' do
 
199
      calculator.infer(:undef).class.should == Puppet::Pops::Types::PNilType
 
200
    end
 
201
 
41
202
    it 'an instance of class Foo translates to PRubyType[Foo]' do
42
203
      class Foo
43
204
      end
60
221
        calculator.infer([1,2**33]).element_type.class.should == Puppet::Pops::Types::PIntegerType
61
222
      end
62
223
 
 
224
      it 'Range of integer values are computed' do
 
225
        t = calculator.infer([-3,0,42]).element_type
 
226
        t.class.should == Puppet::Pops::Types::PIntegerType
 
227
        t.from.should == -3
 
228
        t.to.should == 42
 
229
      end
 
230
 
 
231
      it "Compound string values are computed" do
 
232
        t = calculator.infer(['a','b', 'c']).element_type
 
233
        t.class.should == Puppet::Pops::Types::PStringType
 
234
        t.values.should == ['a', 'b', 'c']
 
235
      end
 
236
 
63
237
      it 'with fixnum and float values translates to PArrayType[PNumericType]' do
64
238
        calculator.infer([1,2.0]).element_type.class.should == Puppet::Pops::Types::PNumericType
65
239
      end
66
240
 
67
 
      it 'with fixnum and string values translates to PArrayType[PLiteralType]' do
68
 
        calculator.infer([1,'two']).element_type.class.should == Puppet::Pops::Types::PLiteralType
69
 
      end
70
 
 
71
 
      it 'with float and string values translates to PArrayType[PLiteralType]' do
72
 
        calculator.infer([1.0,'two']).element_type.class.should == Puppet::Pops::Types::PLiteralType
73
 
      end
74
 
 
75
 
      it 'with fixnum, float, and string values translates to PArrayType[PLiteralType]' do
76
 
        calculator.infer([1, 2.0,'two']).element_type.class.should == Puppet::Pops::Types::PLiteralType
77
 
      end
78
 
 
79
 
      it 'with fixnum and regexp values translates to PArrayType[PLiteralType]' do
80
 
        calculator.infer([1, /two/]).element_type.class.should == Puppet::Pops::Types::PLiteralType
81
 
      end
82
 
 
83
 
      it 'with string and regexp values translates to PArrayType[PLiteralType]' do
84
 
        calculator.infer(['one', /two/]).element_type.class.should == Puppet::Pops::Types::PLiteralType
 
241
      it 'with fixnum and string values translates to PArrayType[PScalarType]' do
 
242
        calculator.infer([1,'two']).element_type.class.should == Puppet::Pops::Types::PScalarType
 
243
      end
 
244
 
 
245
      it 'with float and string values translates to PArrayType[PScalarType]' do
 
246
        calculator.infer([1.0,'two']).element_type.class.should == Puppet::Pops::Types::PScalarType
 
247
      end
 
248
 
 
249
      it 'with fixnum, float, and string values translates to PArrayType[PScalarType]' do
 
250
        calculator.infer([1, 2.0,'two']).element_type.class.should == Puppet::Pops::Types::PScalarType
 
251
      end
 
252
 
 
253
      it 'with fixnum and regexp values translates to PArrayType[PScalarType]' do
 
254
        calculator.infer([1, /two/]).element_type.class.should == Puppet::Pops::Types::PScalarType
 
255
      end
 
256
 
 
257
      it 'with string and regexp values translates to PArrayType[PScalarType]' do
 
258
        calculator.infer(['one', /two/]).element_type.class.should == Puppet::Pops::Types::PScalarType
85
259
      end
86
260
 
87
261
      it 'with string and symbol values translates to PArrayType[PObjectType]' do
101
275
        et.class.should == Puppet::Pops::Types::PStringType
102
276
      end
103
277
 
104
 
      it 'with array of string values and array of fixnums translates to PArrayType[PArrayType[PLiteralType]]' do
 
278
      it 'with array of string values and array of fixnums translates to PArrayType[PArrayType[PScalarType]]' do
105
279
        et = calculator.infer([['first' 'array'], [1,2]])
106
280
        et.class.should == Puppet::Pops::Types::PArrayType
107
281
        et = et.element_type
108
282
        et.class.should == Puppet::Pops::Types::PArrayType
109
283
        et = et.element_type
110
 
        et.class.should == Puppet::Pops::Types::PLiteralType
 
284
        et.class.should == Puppet::Pops::Types::PScalarType
111
285
      end
112
286
 
113
287
      it 'with hashes of string values translates to PArrayType[PHashType[PStringType]]' do
119
293
        et.class.should == Puppet::Pops::Types::PStringType
120
294
      end
121
295
 
122
 
      it 'with hash of string values and hash of fixnums translates to PArrayType[PHashType[PLiteralType]]' do
 
296
      it 'with hash of string values and hash of fixnums translates to PArrayType[PHashType[PScalarType]]' do
123
297
        et = calculator.infer([{:first => 'first', :second => 'second' }, {:first => 1, :second => 2 }])
124
298
        et.class.should == Puppet::Pops::Types::PArrayType
125
299
        et = et.element_type
126
300
        et.class.should == Puppet::Pops::Types::PHashType
127
301
        et = et.element_type
128
 
        et.class.should == Puppet::Pops::Types::PLiteralType
 
302
        et.class.should == Puppet::Pops::Types::PScalarType
129
303
      end
130
304
    end
131
305
 
148
322
        calculator.infer({:first => 1, :second => 2}).element_type.class.should == Puppet::Pops::Types::PIntegerType
149
323
      end
150
324
    end
151
 
  end
152
 
 
153
 
  context 'when testing if x is assignable to y' do
154
 
    it 'should allow all object types to PObjectType' do
155
 
      t = Puppet::Pops::Types::PObjectType.new()
156
 
      calculator.assignable?(t, t).should() == true
157
 
      calculator.assignable?(t,Puppet::Pops::Types::PNilType.new()).should() == true
158
 
      calculator.assignable?(t,Puppet::Pops::Types::PDataType.new()).should() == true
159
 
      calculator.assignable?(t,Puppet::Pops::Types::PLiteralType.new()).should() == true
160
 
      calculator.assignable?(t,Puppet::Pops::Types::PStringType.new()).should() == true
161
 
      calculator.assignable?(t,Puppet::Pops::Types::PNumericType.new()).should() == true
162
 
      calculator.assignable?(t,Puppet::Pops::Types::PIntegerType.new()).should() == true
163
 
      calculator.assignable?(t,Puppet::Pops::Types::PFloatType.new()).should() == true
164
 
      calculator.assignable?(t,Puppet::Pops::Types::PPatternType.new()).should() == true
165
 
      calculator.assignable?(t,Puppet::Pops::Types::PBooleanType.new()).should() == true
166
 
      calculator.assignable?(t,Puppet::Pops::Types::PCollectionType.new()).should() == true
167
 
      calculator.assignable?(t,Puppet::Pops::Types::PArrayType.new()).should() == true
168
 
      calculator.assignable?(t,Puppet::Pops::Types::PHashType.new()).should() == true
169
 
      calculator.assignable?(t,Puppet::Pops::Types::PRubyType.new()).should() == true
170
 
    end
171
 
 
172
 
    it 'should reject PObjectType to less generic types' do
173
 
      t = Puppet::Pops::Types::PObjectType.new()
174
 
      calculator.assignable?(Puppet::Pops::Types::PDataType.new(), t).should() == false
175
 
      calculator.assignable?(Puppet::Pops::Types::PLiteralType.new(), t).should() == false
176
 
      calculator.assignable?(Puppet::Pops::Types::PStringType.new(), t).should() == false
177
 
      calculator.assignable?(Puppet::Pops::Types::PNumericType.new(), t).should() == false
178
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), t).should() == false
179
 
      calculator.assignable?(Puppet::Pops::Types::PFloatType.new(), t).should() == false
180
 
      calculator.assignable?(Puppet::Pops::Types::PPatternType.new(), t).should() == false
181
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), t).should() == false
182
 
      calculator.assignable?(Puppet::Pops::Types::PCollectionType.new(), t).should() == false
183
 
      calculator.assignable?(Puppet::Pops::Types::PArrayType.new(), t).should() == false
184
 
      calculator.assignable?(Puppet::Pops::Types::PHashType.new(), t).should() == false
185
 
      calculator.assignable?(Puppet::Pops::Types::PRubyType.new(), t).should() == false
186
 
    end
187
 
 
188
 
    it 'should allow all data types, array, and hash to PDataType' do
189
 
      t = Puppet::Pops::Types::PDataType.new()
190
 
      calculator.assignable?(t, t).should() == true
191
 
      calculator.assignable?(t,Puppet::Pops::Types::PLiteralType.new()).should() == true
192
 
      calculator.assignable?(t,Puppet::Pops::Types::PStringType.new()).should() == true
193
 
      calculator.assignable?(t,Puppet::Pops::Types::PNumericType.new()).should() == true
194
 
      calculator.assignable?(t,Puppet::Pops::Types::PIntegerType.new()).should() == true
195
 
      calculator.assignable?(t,Puppet::Pops::Types::PFloatType.new()).should() == true
196
 
      calculator.assignable?(t,Puppet::Pops::Types::PPatternType.new()).should() == true
197
 
      calculator.assignable?(t,Puppet::Pops::Types::PBooleanType.new()).should() == true
198
 
      calculator.assignable?(t,Puppet::Pops::Types::PArrayType.new()).should() == true
199
 
      calculator.assignable?(t,Puppet::Pops::Types::PHashType.new()).should() == true
200
 
    end
201
 
 
202
 
    it 'should reject PDataType to less generic data types' do
203
 
      t = Puppet::Pops::Types::PDataType.new()
204
 
      calculator.assignable?(Puppet::Pops::Types::PLiteralType.new(), t).should() == false
205
 
      calculator.assignable?(Puppet::Pops::Types::PStringType.new(), t).should() == false
206
 
      calculator.assignable?(Puppet::Pops::Types::PNumericType.new(), t).should() == false
207
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), t).should() == false
208
 
      calculator.assignable?(Puppet::Pops::Types::PFloatType.new(), t).should() == false
209
 
      calculator.assignable?(Puppet::Pops::Types::PPatternType.new(), t).should() == false
210
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), t).should() == false
211
 
    end
212
 
 
213
 
    it 'should reject PDataType to non data types' do
214
 
      t = Puppet::Pops::Types::PDataType.new()
215
 
      calculator.assignable?(Puppet::Pops::Types::PCollectionType.new(),t).should() == false
216
 
      calculator.assignable?(Puppet::Pops::Types::PArrayType.new(),t).should() == false
217
 
      calculator.assignable?(Puppet::Pops::Types::PHashType.new(),t).should() == false
218
 
      calculator.assignable?(Puppet::Pops::Types::PRubyType.new(), t).should() == false
219
 
    end
220
 
 
221
 
    it 'should allow all literal types to PLiteralType' do
222
 
      t = Puppet::Pops::Types::PLiteralType.new()
223
 
      calculator.assignable?(t, t).should() == true
224
 
      calculator.assignable?(t,Puppet::Pops::Types::PStringType.new()).should() == true
225
 
      calculator.assignable?(t,Puppet::Pops::Types::PNumericType.new()).should() == true
226
 
      calculator.assignable?(t,Puppet::Pops::Types::PIntegerType.new()).should() == true
227
 
      calculator.assignable?(t,Puppet::Pops::Types::PFloatType.new()).should() == true
228
 
      calculator.assignable?(t,Puppet::Pops::Types::PPatternType.new()).should() == true
229
 
      calculator.assignable?(t,Puppet::Pops::Types::PBooleanType.new()).should() == true
230
 
    end
231
 
 
232
 
    it 'should reject PLiteralType to less generic literal types' do
233
 
      t = Puppet::Pops::Types::PLiteralType.new()
234
 
      calculator.assignable?(Puppet::Pops::Types::PStringType.new(), t).should() == false
235
 
      calculator.assignable?(Puppet::Pops::Types::PNumericType.new(), t).should() == false
236
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), t).should() == false
237
 
      calculator.assignable?(Puppet::Pops::Types::PFloatType.new(), t).should() == false
238
 
      calculator.assignable?(Puppet::Pops::Types::PPatternType.new(), t).should() == false
239
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), t).should() == false
240
 
    end
241
 
 
242
 
    it 'should reject PLiteralType to non literal types' do
243
 
      t = Puppet::Pops::Types::PLiteralType.new()
244
 
      calculator.assignable?(Puppet::Pops::Types::PCollectionType.new(), t).should() == false
245
 
      calculator.assignable?(Puppet::Pops::Types::PArrayType.new(), t).should() == false
246
 
      calculator.assignable?(Puppet::Pops::Types::PHashType.new(), t).should() == false
247
 
      calculator.assignable?(Puppet::Pops::Types::PRubyType.new(), t).should() == false
248
 
    end
249
 
 
250
 
    it 'should allow all numeric types to PNumericType' do
251
 
      t = Puppet::Pops::Types::PNumericType.new()
252
 
      calculator.assignable?(t, t).should() == true
253
 
      calculator.assignable?(t, Puppet::Pops::Types::PIntegerType.new()).should() == true
254
 
      calculator.assignable?(t, Puppet::Pops::Types::PFloatType.new()).should() == true
255
 
    end
256
 
 
257
 
    it 'should reject PNumericType to less generic numeric types' do
258
 
      t = Puppet::Pops::Types::PNumericType.new()
259
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), t).should() == false
260
 
      calculator.assignable?(Puppet::Pops::Types::PFloatType.new(), t).should() == false
261
 
    end
262
 
 
263
 
    it 'should reject PNumericType to non numeric types' do
264
 
      t = Puppet::Pops::Types::PNumericType.new()
265
 
      calculator.assignable?(Puppet::Pops::Types::PStringType.new(), t).should() == false
266
 
      calculator.assignable?(Puppet::Pops::Types::PPatternType.new(), t).should() == false
267
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), t).should() == false
268
 
      calculator.assignable?(Puppet::Pops::Types::PCollectionType.new(), t).should() == false
269
 
      calculator.assignable?(Puppet::Pops::Types::PArrayType.new(), t).should() == false
270
 
      calculator.assignable?(Puppet::Pops::Types::PHashType.new(), t).should() == false
271
 
      calculator.assignable?(Puppet::Pops::Types::PRubyType.new(), t).should() == false
272
 
    end
273
 
 
274
 
    it 'should allow all collection types to PCollectionType' do
275
 
      t = Puppet::Pops::Types::PCollectionType.new()
276
 
      calculator.assignable?(t, t).should() == true
277
 
      calculator.assignable?(t, Puppet::Pops::Types::PArrayType.new()).should() == true
278
 
      calculator.assignable?(t, Puppet::Pops::Types::PHashType.new()).should() == true
279
 
    end
280
 
 
281
 
    it 'should reject PCollectionType to less generic collection types' do
282
 
      t = Puppet::Pops::Types::PCollectionType.new()
283
 
      calculator.assignable?(Puppet::Pops::Types::PArrayType.new(), t).should() == false
284
 
      calculator.assignable?(Puppet::Pops::Types::PHashType.new(), t).should() == false
285
 
    end
286
 
 
287
 
    it 'should reject PCollectionType to non collection types' do
288
 
      t = Puppet::Pops::Types::PCollectionType.new()
289
 
      calculator.assignable?(Puppet::Pops::Types::PDataType.new(), t).should() == false
290
 
      calculator.assignable?(Puppet::Pops::Types::PLiteralType.new(), t).should() == false
291
 
      calculator.assignable?(Puppet::Pops::Types::PStringType.new(), t).should() == false
292
 
      calculator.assignable?(Puppet::Pops::Types::PNumericType.new(), t).should() == false
293
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), t).should() == false
294
 
      calculator.assignable?(Puppet::Pops::Types::PFloatType.new(), t).should() == false
295
 
      calculator.assignable?(Puppet::Pops::Types::PPatternType.new(), t).should() == false
296
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), t).should() == false
297
 
      calculator.assignable?(Puppet::Pops::Types::PRubyType.new(), t).should() == false
298
 
    end
299
 
 
300
 
    it 'should reject PArrayType to non array type collections' do
301
 
      t = Puppet::Pops::Types::PArrayType.new()
302
 
      calculator.assignable?(Puppet::Pops::Types::PHashType.new(), t).should() == false
303
 
    end
304
 
 
305
 
    it 'should reject PHashType to non hash type collections' do
306
 
      t = Puppet::Pops::Types::PHashType.new()
307
 
      calculator.assignable?(Puppet::Pops::Types::PArrayType.new(), t).should() == false
308
 
    end
309
 
 
310
 
    it 'should recognize mapped ruby types' do 
311
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), Integer).should == true
312
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), Fixnum).should == true
313
 
      calculator.assignable?(Puppet::Pops::Types::PIntegerType.new(), Bignum).should == true
314
 
      calculator.assignable?(Puppet::Pops::Types::PFloatType.new(), Float).should == true
315
 
      calculator.assignable?(Puppet::Pops::Types::PNumericType.new(), Numeric).should == true
316
 
      calculator.assignable?(Puppet::Pops::Types::PNilType.new(), NilClass).should == true
317
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), FalseClass).should == true
318
 
      calculator.assignable?(Puppet::Pops::Types::PBooleanType.new(), TrueClass).should == true
319
 
      calculator.assignable?(Puppet::Pops::Types::PStringType.new(), String).should == true
320
 
      calculator.assignable?(Puppet::Pops::Types::PPatternType.new(), Regexp).should == true
321
 
      calculator.assignable?(Puppet::Pops::Types::TypeFactory.array_of_data(), Array).should == true
322
 
      calculator.assignable?(Puppet::Pops::Types::TypeFactory.hash_of_data(), Hash).should == true
 
325
 
 
326
  end
 
327
 
 
328
  context 'patterns' do
 
329
    it "constructs a PPatternType" do
 
330
      t = pattern_t('a(b)c')
 
331
      t.class.should == Puppet::Pops::Types::PPatternType
 
332
      t.patterns.size.should == 1
 
333
      t.patterns[0].class.should == Puppet::Pops::Types::PRegexpType
 
334
      t.patterns[0].pattern.should == 'a(b)c'
 
335
      t.patterns[0].regexp.match('abc')[1].should == 'b'
 
336
    end
 
337
 
 
338
    it "constructs a PStringType with multiple strings" do
 
339
      t = string_t('a', 'b', 'c', 'abc')
 
340
      t.values.should == ['a', 'b', 'c', 'abc']
 
341
    end
 
342
  end
 
343
 
 
344
  # Deal with cases not covered by computing common type
 
345
  context 'when computing common type' do
 
346
    it 'computes given resource type commonality' do
 
347
      r1 = Puppet::Pops::Types::PResourceType.new()
 
348
      r1.type_name = 'File'
 
349
      r2 = Puppet::Pops::Types::PResourceType.new()
 
350
      r2.type_name = 'File'
 
351
      calculator.string(calculator.common_type(r1, r2)).should == "File"
 
352
 
 
353
      r2 = Puppet::Pops::Types::PResourceType.new()
 
354
      r2.type_name = 'File'
 
355
      r2.title = '/tmp/foo'
 
356
      calculator.string(calculator.common_type(r1, r2)).should == "File"
 
357
 
 
358
      r1 = Puppet::Pops::Types::PResourceType.new()
 
359
      r1.type_name = 'File'
 
360
      r1.title = '/tmp/foo'
 
361
      calculator.string(calculator.common_type(r1, r2)).should == "File['/tmp/foo']"
 
362
 
 
363
      r1 = Puppet::Pops::Types::PResourceType.new()
 
364
      r1.type_name = 'File'
 
365
      r1.title = '/tmp/bar'
 
366
      calculator.string(calculator.common_type(r1, r2)).should == "File"
 
367
 
 
368
      r2 = Puppet::Pops::Types::PResourceType.new()
 
369
      r2.type_name = 'Package'
 
370
      r2.title = 'apache'
 
371
      calculator.string(calculator.common_type(r1, r2)).should == "Resource"
 
372
    end
 
373
 
 
374
    it 'computes given hostclass type commonality' do
 
375
      r1 = Puppet::Pops::Types::PHostClassType.new()
 
376
      r1.class_name = 'foo'
 
377
      r2 = Puppet::Pops::Types::PHostClassType.new()
 
378
      r2.class_name = 'foo'
 
379
      calculator.string(calculator.common_type(r1, r2)).should == "Class[foo]"
 
380
 
 
381
      r2 = Puppet::Pops::Types::PHostClassType.new()
 
382
      r2.class_name = 'bar'
 
383
      calculator.string(calculator.common_type(r1, r2)).should == "Class"
 
384
 
 
385
      r2 = Puppet::Pops::Types::PHostClassType.new()
 
386
      calculator.string(calculator.common_type(r1, r2)).should == "Class"
 
387
 
 
388
      r1 = Puppet::Pops::Types::PHostClassType.new()
 
389
      calculator.string(calculator.common_type(r1, r2)).should == "Class"
 
390
    end
 
391
 
 
392
    it 'computes pattern commonality' do
 
393
      t1 = pattern_t('abc')
 
394
      t2 = pattern_t('xyz')
 
395
      common_t = calculator.common_type(t1,t2)
 
396
      common_t.class.should == Puppet::Pops::Types::PPatternType
 
397
      common_t.patterns.map { |pr| pr.pattern }.should == ['abc', 'xyz']
 
398
      calculator.string(common_t).should == "Pattern[/abc/, /xyz/]"
 
399
    end
 
400
 
 
401
    it 'computes enum commonality to value set sum' do
 
402
      t1 = enum_t('a', 'b', 'c')
 
403
      t2 = enum_t('x', 'y', 'z')
 
404
      common_t = calculator.common_type(t1, t2)
 
405
      common_t.should == enum_t('a', 'b', 'c', 'x', 'y', 'z')
 
406
    end
 
407
 
 
408
    it 'computed variant commonality to type union where added types are not sub-types' do
 
409
      a_t1 = integer_t()
 
410
      a_t2 = enum_t('b')
 
411
      v_a = variant_t(a_t1, a_t2)
 
412
      b_t1 = enum_t('a')
 
413
      v_b = variant_t(b_t1)
 
414
      common_t = calculator.common_type(v_a, v_b)
 
415
      common_t.class.should == Puppet::Pops::Types::PVariantType
 
416
      Set.new(common_t.types).should  == Set.new([a_t1, a_t2, b_t1])
 
417
    end
 
418
 
 
419
    it 'computed variant commonality to type union where added types are sub-types' do
 
420
      a_t1 = integer_t()
 
421
      a_t2 = string_t()
 
422
      v_a = variant_t(a_t1, a_t2)
 
423
      b_t1 = enum_t('a')
 
424
      v_b = variant_t(b_t1)
 
425
      common_t = calculator.common_type(v_a, v_b)
 
426
      common_t.class.should == Puppet::Pops::Types::PVariantType
 
427
      Set.new(common_t.types).should  == Set.new([a_t1, a_t2])
 
428
    end
 
429
  end
 
430
 
 
431
  context 'computes assignability' do
 
432
    include_context "types_setup"
 
433
 
 
434
    context "for Object, such that" do
 
435
      it 'all types are assignable to Object' do
 
436
        t = Puppet::Pops::Types::PObjectType.new()
 
437
        all_types.each { |t2| t2.new.should be_assignable_to(t) }
 
438
      end
 
439
 
 
440
      it 'Object is not assignable to anything but Object' do
 
441
        tested_types = all_types() - [Puppet::Pops::Types::PObjectType]
 
442
        t = Puppet::Pops::Types::PObjectType.new()
 
443
        tested_types.each { |t2| t.should_not be_assignable_to(t2.new) }
 
444
      end
 
445
    end
 
446
 
 
447
    context "for Data, such that" do
 
448
      it 'all scalars + array and hash are assignable to Data' do
 
449
        t = Puppet::Pops::Types::PDataType.new()
 
450
        data_compatible_types.each { |t2|
 
451
          type_from_class(t2).should be_assignable_to(t)
 
452
        }
 
453
      end
 
454
 
 
455
      it 'a Variant of scalar, hash, or array is assignable to Data' do
 
456
        t = Puppet::Pops::Types::PDataType.new()
 
457
        data_compatible_types.each { |t2| variant_t(type_from_class(t2)).should be_assignable_to(t) }
 
458
      end
 
459
 
 
460
      it 'Data is not assignable to any of its subtypes' do
 
461
        t = Puppet::Pops::Types::PDataType.new()
 
462
        types_to_test = data_compatible_types- [Puppet::Pops::Types::PDataType]
 
463
        types_to_test.each {|t2| t.should_not be_assignable_to(type_from_class(t2)) }
 
464
      end
 
465
 
 
466
      it 'Data is not assignable to a Variant of Data subtype' do
 
467
        t = Puppet::Pops::Types::PDataType.new()
 
468
        types_to_test = data_compatible_types- [Puppet::Pops::Types::PDataType]
 
469
        types_to_test.each { |t2| t.should_not be_assignable_to(variant_t(type_from_class(t2))) }
 
470
      end
 
471
 
 
472
      it 'Data is not assignable to any disjunct type' do
 
473
        tested_types = all_types - [Puppet::Pops::Types::PObjectType, Puppet::Pops::Types::PDataType] - scalar_types
 
474
        t = Puppet::Pops::Types::PDataType.new()
 
475
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
476
      end
 
477
    end
 
478
 
 
479
    context "for Scalar, such that" do
 
480
      it "all scalars are assignable to Scalar" do
 
481
        t = Puppet::Pops::Types::PScalarType.new()
 
482
        scalar_types.each {|t2| t2.new.should be_assignable_to(t) }
 
483
      end
 
484
 
 
485
      it 'Scalar is not assignable to any of its subtypes' do
 
486
        t = Puppet::Pops::Types::PScalarType.new() 
 
487
        types_to_test = scalar_types - [Puppet::Pops::Types::PScalarType]
 
488
        types_to_test.each {|t2| t.should_not be_assignable_to(t2.new) }
 
489
      end
 
490
 
 
491
      it 'Scalar is not assignable to any disjunct type' do
 
492
        tested_types = all_types - [Puppet::Pops::Types::PObjectType, Puppet::Pops::Types::PDataType] - scalar_types
 
493
        t = Puppet::Pops::Types::PScalarType.new()
 
494
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
495
      end
 
496
    end
 
497
 
 
498
    context "for Numeric, such that" do
 
499
      it "all numerics are assignable to Numeric" do
 
500
        t = Puppet::Pops::Types::PNumericType.new()
 
501
        numeric_types.each {|t2| t2.new.should be_assignable_to(t) }
 
502
      end
 
503
 
 
504
      it 'Numeric is not assignable to any of its subtypes' do
 
505
        t = Puppet::Pops::Types::PNumericType.new()
 
506
        types_to_test = numeric_types - [Puppet::Pops::Types::PNumericType]
 
507
        types_to_test.each {|t2| t.should_not be_assignable_to(t2.new) }
 
508
      end
 
509
 
 
510
      it 'Numeric is not assignable to any disjunct type' do
 
511
        tested_types = all_types - [
 
512
          Puppet::Pops::Types::PObjectType,
 
513
          Puppet::Pops::Types::PDataType,
 
514
          Puppet::Pops::Types::PScalarType,
 
515
          ] - numeric_types
 
516
        t = Puppet::Pops::Types::PNumericType.new()
 
517
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
518
      end
 
519
    end
 
520
 
 
521
    context "for Collection, such that" do
 
522
      it "all collections are assignable to Collection" do
 
523
        t = Puppet::Pops::Types::PCollectionType.new()
 
524
        collection_types.each {|t2| t2.new.should be_assignable_to(t) }
 
525
      end
 
526
 
 
527
      it 'Collection is not assignable to any of its subtypes' do
 
528
        t = Puppet::Pops::Types::PCollectionType.new()
 
529
        types_to_test = collection_types - [Puppet::Pops::Types::PCollectionType]
 
530
        types_to_test.each {|t2| t.should_not be_assignable_to(t2.new) }
 
531
      end
 
532
 
 
533
      it 'Collection is not assignable to any disjunct type' do
 
534
        tested_types = all_types - [Puppet::Pops::Types::PObjectType] - collection_types
 
535
        t = Puppet::Pops::Types::PCollectionType.new()
 
536
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
537
      end
 
538
    end
 
539
 
 
540
    context "for Array, such that" do
 
541
      it "Array is not assignable to non Array based Collection type" do
 
542
        t = Puppet::Pops::Types::PArrayType.new()
 
543
        tested_types = collection_types - [
 
544
          Puppet::Pops::Types::PCollectionType,
 
545
          Puppet::Pops::Types::PArrayType,
 
546
          Puppet::Pops::Types::PTupleType]
 
547
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
548
      end
 
549
 
 
550
      it 'Array is not assignable to any disjunct type' do
 
551
        tested_types = all_types - [
 
552
          Puppet::Pops::Types::PObjectType,
 
553
          Puppet::Pops::Types::PDataType] - collection_types
 
554
        t = Puppet::Pops::Types::PArrayType.new()
 
555
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
556
      end
 
557
    end
 
558
 
 
559
    context "for Hash, such that" do
 
560
      it "Hash is not assignable to any other Collection type" do
 
561
        t = Puppet::Pops::Types::PHashType.new()
 
562
        tested_types = collection_types - [
 
563
          Puppet::Pops::Types::PCollectionType,
 
564
          Puppet::Pops::Types::PStructType,
 
565
          Puppet::Pops::Types::PHashType]
 
566
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
567
      end
 
568
 
 
569
      it 'Hash is not assignable to any disjunct type' do
 
570
        tested_types = all_types - [
 
571
          Puppet::Pops::Types::PObjectType,
 
572
          Puppet::Pops::Types::PDataType] - collection_types
 
573
        t = Puppet::Pops::Types::PHashType.new()
 
574
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
575
      end
 
576
    end
 
577
 
 
578
    context "for Tuple, such that" do
 
579
      it "Tuple is not assignable to any other non Array based Collection type" do
 
580
        t = Puppet::Pops::Types::PTupleType.new()
 
581
        tested_types = collection_types - [
 
582
          Puppet::Pops::Types::PCollectionType,
 
583
          Puppet::Pops::Types::PTupleType,
 
584
          Puppet::Pops::Types::PArrayType]
 
585
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
586
      end
 
587
 
 
588
      it 'Tuple is not assignable to any disjunct type' do
 
589
        tested_types = all_types - [
 
590
          Puppet::Pops::Types::PObjectType,
 
591
          Puppet::Pops::Types::PDataType] - collection_types
 
592
        t = Puppet::Pops::Types::PTupleType.new()
 
593
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
594
      end
 
595
    end
 
596
 
 
597
    context "for Struct, such that" do
 
598
      it "Struct is not assignable to any other non Hashed based Collection type" do
 
599
        t = Puppet::Pops::Types::PStructType.new()
 
600
        tested_types = collection_types - [
 
601
          Puppet::Pops::Types::PCollectionType,
 
602
          Puppet::Pops::Types::PStructType,
 
603
          Puppet::Pops::Types::PHashType]
 
604
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
605
      end
 
606
 
 
607
      it 'Struct is not assignable to any disjunct type' do
 
608
        tested_types = all_types - [
 
609
          Puppet::Pops::Types::PObjectType,
 
610
          Puppet::Pops::Types::PDataType] - collection_types
 
611
        t = Puppet::Pops::Types::PStructType.new()
 
612
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
 
613
      end
 
614
    end
 
615
 
 
616
    it 'should recognize mapped ruby types' do
 
617
      { Integer    => Puppet::Pops::Types::PIntegerType.new,
 
618
        Fixnum     => Puppet::Pops::Types::PIntegerType.new,
 
619
        Bignum     => Puppet::Pops::Types::PIntegerType.new,
 
620
        Float      => Puppet::Pops::Types::PFloatType.new,
 
621
        Numeric    => Puppet::Pops::Types::PNumericType.new,
 
622
        NilClass   => Puppet::Pops::Types::PNilType.new,
 
623
        TrueClass  => Puppet::Pops::Types::PBooleanType.new,
 
624
        FalseClass => Puppet::Pops::Types::PBooleanType.new,
 
625
        String     => Puppet::Pops::Types::PStringType.new,
 
626
        Regexp     => Puppet::Pops::Types::PRegexpType.new,
 
627
        Regexp     => Puppet::Pops::Types::PRegexpType.new,
 
628
        Array      => Puppet::Pops::Types::TypeFactory.array_of_data(),
 
629
        Hash       => Puppet::Pops::Types::TypeFactory.hash_of_data()
 
630
      }.each do |ruby_type, puppet_type |
 
631
          ruby_type.should be_assignable_to(puppet_type)
 
632
      end
 
633
    end
 
634
 
 
635
    context 'when dealing with integer ranges' do
 
636
      it 'should accept an equal range' do
 
637
        calculator.assignable?(range_t(2,5), range_t(2,5)).should == true
 
638
      end
 
639
 
 
640
      it 'should accept an equal reverse range' do
 
641
        calculator.assignable?(range_t(2,5), range_t(5,2)).should == true
 
642
      end
 
643
 
 
644
      it 'should accept a narrower range' do
 
645
        calculator.assignable?(range_t(2,10), range_t(3,5)).should == true
 
646
      end
 
647
 
 
648
      it 'should accept a narrower reverse range' do
 
649
        calculator.assignable?(range_t(2,10), range_t(5,3)).should == true
 
650
      end
 
651
 
 
652
      it 'should reject a wider range' do
 
653
        calculator.assignable?(range_t(3,5), range_t(2,10)).should == false
 
654
      end
 
655
 
 
656
      it 'should reject a wider reverse range' do
 
657
        calculator.assignable?(range_t(3,5), range_t(10,2)).should == false
 
658
      end
 
659
 
 
660
      it 'should reject a partially overlapping range' do
 
661
        calculator.assignable?(range_t(3,5), range_t(2,4)).should == false
 
662
        calculator.assignable?(range_t(3,5), range_t(4,6)).should == false
 
663
      end
 
664
 
 
665
      it 'should reject a partially overlapping reverse range' do
 
666
        calculator.assignable?(range_t(3,5), range_t(4,2)).should == false
 
667
        calculator.assignable?(range_t(3,5), range_t(6,4)).should == false
 
668
      end
 
669
    end
 
670
 
 
671
    context 'when dealing with patterns' do
 
672
      it 'should accept a string matching a pattern' do
 
673
        p_t = pattern_t('abc')
 
674
        p_s = string_t('XabcY')
 
675
        calculator.assignable?(p_t, p_s).should == true
 
676
      end
 
677
 
 
678
      it 'should accept a regexp matching a pattern' do
 
679
        p_t = pattern_t(/abc/)
 
680
        p_s = string_t('XabcY')
 
681
        calculator.assignable?(p_t, p_s).should == true
 
682
      end
 
683
 
 
684
      it 'should accept a pattern matching a pattern' do
 
685
        p_t = pattern_t(pattern_t('abc'))
 
686
        p_s = string_t('XabcY')
 
687
        calculator.assignable?(p_t, p_s).should == true
 
688
      end
 
689
 
 
690
      it 'should accept a regexp matching a pattern' do
 
691
        p_t = pattern_t(regexp_t('abc'))
 
692
        p_s = string_t('XabcY')
 
693
        calculator.assignable?(p_t, p_s).should == true
 
694
      end
 
695
 
 
696
      it 'should accept a string matching all patterns' do
 
697
        p_t = pattern_t('abc', 'ab', 'c')
 
698
        p_s = string_t('XabcY')
 
699
        calculator.assignable?(p_t, p_s).should == true
 
700
      end
 
701
 
 
702
      it 'should accept multiple strings if they all match any patterns' do
 
703
        p_t = pattern_t('X', 'Y', 'abc')
 
704
        p_s = string_t('Xa', 'aY', 'abc')
 
705
        calculator.assignable?(p_t, p_s).should == true
 
706
      end
 
707
 
 
708
      it 'should reject a string not matching any patterns' do
 
709
        p_t = pattern_t('abc', 'ab', 'c')
 
710
        p_s = string_t('XqqqY')
 
711
        calculator.assignable?(p_t, p_s).should == false
 
712
      end
 
713
 
 
714
      it 'should reject multiple strings if not all match any patterns' do
 
715
        p_t = pattern_t('abc', 'ab', 'c', 'q')
 
716
        p_s = string_t('X', 'Y', 'Z')
 
717
        calculator.assignable?(p_t, p_s).should == false
 
718
      end
 
719
 
 
720
      it 'should accept enum matching patterns as instanceof' do
 
721
        enum = enum_t('XS', 'S', 'M', 'L' 'XL', 'XXL')
 
722
        pattern = pattern_t('S', 'M', 'L')
 
723
        calculator.assignable?(pattern, enum).should  == true
 
724
      end
 
725
 
 
726
    end
 
727
 
 
728
    context 'when dealing with tuples' do
 
729
      it 'should accept matching tuples' do
 
730
        tuple1 = tuple_t(1,2)
 
731
        tuple2 = tuple_t(Integer,Integer)
 
732
        calculator.assignable?(tuple1, tuple2).should == true
 
733
        calculator.assignable?(tuple2, tuple1).should == true
 
734
      end
 
735
 
 
736
      it 'should accept matching tuples where one is more general than the other' do
 
737
        tuple1 = tuple_t(1,2)
 
738
        tuple2 = tuple_t(Numeric,Numeric)
 
739
        calculator.assignable?(tuple1, tuple2).should == false
 
740
        calculator.assignable?(tuple2, tuple1).should == true
 
741
      end
 
742
 
 
743
      it 'should accept ranged tuples' do
 
744
        tuple1 = tuple_t(1)
 
745
        factory.constrain_size(tuple1, 5, 5)
 
746
        tuple2 = tuple_t(Integer,Integer, Integer, Integer, Integer)
 
747
        calculator.assignable?(tuple1, tuple2).should == true
 
748
        calculator.assignable?(tuple2, tuple1).should == true
 
749
      end
 
750
 
 
751
      it 'should reject ranged tuples when ranges does not match' do
 
752
        tuple1 = tuple_t(1)
 
753
        factory.constrain_size(tuple1, 4, 5)
 
754
        tuple2 = tuple_t(Integer,Integer, Integer, Integer, Integer)
 
755
        calculator.assignable?(tuple1, tuple2).should == true
 
756
        calculator.assignable?(tuple2, tuple1).should == false
 
757
      end
 
758
 
 
759
      it 'should reject ranged tuples when ranges does not match (using infinite upper bound)' do
 
760
        tuple1 = tuple_t(1)
 
761
        factory.constrain_size(tuple1, 4, :default)
 
762
        tuple2 = tuple_t(Integer,Integer, Integer, Integer, Integer)
 
763
        calculator.assignable?(tuple1, tuple2).should == true
 
764
        calculator.assignable?(tuple2, tuple1).should == false
 
765
      end
 
766
 
 
767
      it 'should accept matching tuples with optional entries by repeating last' do
 
768
        tuple1 = tuple_t(1,2)
 
769
        factory.constrain_size(tuple1, 0, :default)
 
770
        tuple2 = tuple_t(Numeric,Numeric)
 
771
        factory.constrain_size(tuple2, 0, :default)
 
772
        calculator.assignable?(tuple1, tuple2).should == false
 
773
        calculator.assignable?(tuple2, tuple1).should == true
 
774
      end
 
775
 
 
776
      it 'should accept matching tuples with optional entries' do
 
777
        tuple1 = tuple_t(Integer, Integer, String)
 
778
        factory.constrain_size(tuple1, 1, 3)
 
779
        array2 = factory.constrain_size(array_t(Integer),2,2)
 
780
        calculator.assignable?(tuple1, array2).should == true
 
781
        factory.constrain_size(tuple1, 3, 3)
 
782
        calculator.assignable?(tuple1, array2).should == false
 
783
      end
 
784
 
 
785
      it 'should accept matching array' do
 
786
        tuple1 = tuple_t(1,2)
 
787
        array = array_t(Integer)
 
788
        factory.constrain_size(array, 2, 2)
 
789
        calculator.assignable?(tuple1, array).should == true
 
790
        calculator.assignable?(array, tuple1).should == true
 
791
      end
 
792
    end
 
793
 
 
794
    context 'when dealing with structs' do
 
795
      it 'should accept matching structs' do
 
796
        struct1 = struct_t({'a'=>Integer, 'b'=>Integer})
 
797
        struct2 = struct_t({'a'=>Integer, 'b'=>Integer})
 
798
        calculator.assignable?(struct1, struct2).should == true
 
799
        calculator.assignable?(struct2, struct1).should == true
 
800
      end
 
801
 
 
802
      it 'should accept matching structs where one is more general than the other' do
 
803
        struct1 = struct_t({'a'=>Integer, 'b'=>Integer})
 
804
        struct2 = struct_t({'a'=>Numeric, 'b'=>Numeric})
 
805
        calculator.assignable?(struct1, struct2).should == false
 
806
        calculator.assignable?(struct2, struct1).should == true
 
807
      end
 
808
 
 
809
      it 'should accept matching hash' do
 
810
        struct1 = struct_t({'a'=>Integer, 'b'=>Integer})
 
811
        non_empty_string = string_t()
 
812
        non_empty_string.size_type = range_t(1, nil)
 
813
        hsh = hash_t(non_empty_string, Integer)
 
814
        factory.constrain_size(hsh, 2, 2)
 
815
        calculator.assignable?(struct1, hsh).should == true
 
816
        calculator.assignable?(hsh, struct1).should == true
 
817
      end
323
818
    end
324
819
 
325
820
    it 'should recognize ruby type inheritance' do
341
836
      calculator.assignable?(barType, fooType).should == false
342
837
      calculator.assignable?(Bar, fooType).should == false
343
838
    end
 
839
 
 
840
    it "should allow host class with same name" do
 
841
      hc1 = Puppet::Pops::Types::TypeFactory.host_class('the_name')
 
842
      hc2 = Puppet::Pops::Types::TypeFactory.host_class('the_name')
 
843
      calculator.assignable?(hc1, hc2).should == true
 
844
    end
 
845
 
 
846
    it "should allow host class with name assigned to hostclass without name" do
 
847
      hc1 = Puppet::Pops::Types::TypeFactory.host_class()
 
848
      hc2 = Puppet::Pops::Types::TypeFactory.host_class('the_name')
 
849
      calculator.assignable?(hc1, hc2).should == true
 
850
    end
 
851
 
 
852
    it "should reject host classes with different names" do
 
853
      hc1 = Puppet::Pops::Types::TypeFactory.host_class('the_name')
 
854
      hc2 = Puppet::Pops::Types::TypeFactory.host_class('another_name')
 
855
      calculator.assignable?(hc1, hc2).should == false
 
856
    end
 
857
 
 
858
    it "should reject host classes without name assigned to host class with name" do
 
859
      hc1 = Puppet::Pops::Types::TypeFactory.host_class('the_name')
 
860
      hc2 = Puppet::Pops::Types::TypeFactory.host_class()
 
861
      calculator.assignable?(hc1, hc2).should == false
 
862
    end
 
863
 
 
864
    it "should allow resource with same type_name and title" do
 
865
      r1 = Puppet::Pops::Types::TypeFactory.resource('file', 'foo')
 
866
      r2 = Puppet::Pops::Types::TypeFactory.resource('file', 'foo')
 
867
      calculator.assignable?(r1, r2).should == true
 
868
    end
 
869
 
 
870
    it "should allow more specific resource assignment" do
 
871
      r1 = Puppet::Pops::Types::TypeFactory.resource()
 
872
      r2 = Puppet::Pops::Types::TypeFactory.resource('file')
 
873
      calculator.assignable?(r1, r2).should == true
 
874
      r2 = Puppet::Pops::Types::TypeFactory.resource('file', '/tmp/foo')
 
875
      calculator.assignable?(r1, r2).should == true
 
876
      r1 = Puppet::Pops::Types::TypeFactory.resource('file')
 
877
      calculator.assignable?(r1, r2).should == true
 
878
    end
 
879
 
 
880
    it "should reject less specific resource assignment" do
 
881
      r1 = Puppet::Pops::Types::TypeFactory.resource('file', '/tmp/foo')
 
882
      r2 = Puppet::Pops::Types::TypeFactory.resource('file')
 
883
      calculator.assignable?(r1, r2).should == false
 
884
      r2 = Puppet::Pops::Types::TypeFactory.resource()
 
885
      calculator.assignable?(r1, r2).should == false
 
886
    end
 
887
 
344
888
  end
345
889
 
346
890
  context 'when testing if x is instance of type t' do
 
891
    include_context "types_setup"
 
892
 
 
893
    it 'should consider undef to be instance of Object and NilType' do
 
894
      calculator.instance?(Puppet::Pops::Types::PNilType.new(), nil).should    == true
 
895
      calculator.instance?(Puppet::Pops::Types::PObjectType.new(), nil).should == true
 
896
    end
 
897
 
 
898
    it 'should not consider undef to be an instance of any other type than Object and NilType and Data' do
 
899
      types_to_test = all_types - [ 
 
900
        Puppet::Pops::Types::PObjectType,
 
901
        Puppet::Pops::Types::PNilType,
 
902
        Puppet::Pops::Types::PDataType]
 
903
 
 
904
      types_to_test.each {|t| calculator.instance?(t.new, nil).should == false }
 
905
      types_to_test.each {|t| calculator.instance?(t.new, :undef).should == false }
 
906
    end
 
907
 
347
908
    it 'should consider fixnum instanceof PIntegerType' do
348
 
      calculator.instance?(Puppet::Pops::Types::PIntegerType.new(), 1)
 
909
      calculator.instance?(Puppet::Pops::Types::PIntegerType.new(), 1).should == true
349
910
    end
350
911
 
351
912
    it 'should consider fixnum instanceof Fixnum' do
352
 
      calculator.instance?(Fixnum, 1)
 
913
      calculator.instance?(Fixnum, 1).should == true
 
914
    end
 
915
 
 
916
    it 'should consider integer in range' do
 
917
      range = range_t(0,10)
 
918
      calculator.instance?(range, 1).should == true
 
919
      calculator.instance?(range, 10).should == true
 
920
      calculator.instance?(range, -1).should == false
 
921
      calculator.instance?(range, 11).should == false
 
922
    end
 
923
 
 
924
    it 'should consider string in length range' do
 
925
      range = factory.constrain_size(string_t, 1,3)
 
926
      calculator.instance?(range, 'a').should    == true
 
927
      calculator.instance?(range, 'abc').should  == true
 
928
      calculator.instance?(range, '').should     == false
 
929
      calculator.instance?(range, 'abcd').should == false
 
930
    end
 
931
 
 
932
    it 'should consider array in length range' do
 
933
      range = factory.constrain_size(array_t(integer_t), 1,3)
 
934
      calculator.instance?(range, [1]).should    == true
 
935
      calculator.instance?(range, [1,2,3]).should  == true
 
936
      calculator.instance?(range, []).should     == false
 
937
      calculator.instance?(range, [1,2,3,4]).should == false
 
938
    end
 
939
 
 
940
    it 'should consider hash in length range' do
 
941
      range = factory.constrain_size(hash_t(integer_t, integer_t), 1,2)
 
942
      calculator.instance?(range, {1=>1}).should             == true
 
943
      calculator.instance?(range, {1=>1, 2=>2}).should       == true
 
944
      calculator.instance?(range, {}).should                 == false
 
945
      calculator.instance?(range, {1=>1, 2=>2, 3=>3}).should == false
 
946
    end
 
947
 
 
948
    it 'should consider collection in length range for array ' do
 
949
      range = factory.constrain_size(collection_t, 1,3)
 
950
      calculator.instance?(range, [1]).should    == true
 
951
      calculator.instance?(range, [1,2,3]).should  == true
 
952
      calculator.instance?(range, []).should     == false
 
953
      calculator.instance?(range, [1,2,3,4]).should == false
 
954
    end
 
955
 
 
956
    it 'should consider collection in length range for hash' do
 
957
      range = factory.constrain_size(collection_t, 1,2)
 
958
      calculator.instance?(range, {1=>1}).should             == true
 
959
      calculator.instance?(range, {1=>1, 2=>2}).should       == true
 
960
      calculator.instance?(range, {}).should                 == false
 
961
      calculator.instance?(range, {1=>1, 2=>2, 3=>3}).should == false
 
962
    end
 
963
 
 
964
    it 'should consider string matching enum as instanceof' do
 
965
      enum = enum_t('XS', 'S', 'M', 'L', 'XL', '0')
 
966
      calculator.instance?(enum, 'XS').should  == true
 
967
      calculator.instance?(enum, 'S').should   == true
 
968
      calculator.instance?(enum, 'XXL').should == false
 
969
      calculator.instance?(enum, '').should    == false
 
970
      calculator.instance?(enum, '0').should   == true
 
971
      calculator.instance?(enum, 0).should     == false
 
972
    end
 
973
 
 
974
    it 'should consider array[string] as instance of Array[Enum] when strings are instance of Enum' do
 
975
      enum = enum_t('XS', 'S', 'M', 'L', 'XL', '0')
 
976
      array = array_t(enum)
 
977
      calculator.instance?(array, ['XS', 'S', 'XL']).should  == true
 
978
      calculator.instance?(array, ['XS', 'S', 'XXL']).should == false
 
979
    end
 
980
 
 
981
    it 'should consider array[mixed] as instance of Variant[mixed] when mixed types are listed in Variant' do
 
982
      enum = enum_t('XS', 'S', 'M', 'L', 'XL')
 
983
      sizes = range_t(30, 50)
 
984
      array = array_t(variant_t(enum, sizes))
 
985
      calculator.instance?(array, ['XS', 'S', 30, 50]).should  == true
 
986
      calculator.instance?(array, ['XS', 'S', 'XXL']).should   == false
 
987
      calculator.instance?(array, ['XS', 'S', 29]).should      == false
 
988
    end
 
989
 
 
990
    it 'should consider array[seq] as instance of Tuple[seq] when elements of seq are instance of' do
 
991
      tuple = tuple_t(Integer, String, Float)
 
992
      calculator.instance?(tuple, [1, 'a', 3.14]).should       == true
 
993
      calculator.instance?(tuple, [1.2, 'a', 3.14]).should     == false
 
994
      calculator.instance?(tuple, [1, 1, 3.14]).should         == false
 
995
      calculator.instance?(tuple, [1, 'a', 1]).should          == false
 
996
    end
 
997
 
 
998
    it 'should consider hash[cont] as instance of Struct[cont-t]' do
 
999
      struct = struct_t({'a'=>Integer, 'b'=>String, 'c'=>Float})
 
1000
      calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>3.14}).should       == true
 
1001
      calculator.instance?(struct, {'a'=>1.2, 'b'=>'a', 'c'=>3.14}).should     == false
 
1002
      calculator.instance?(struct, {'a'=>1, 'b'=>1, 'c'=>3.14}).should         == false
 
1003
      calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>1}).should          == false
 
1004
    end
 
1005
 
 
1006
    context 'and t is Data' do
 
1007
      it 'undef should be considered instance of Data' do
 
1008
        calculator.instance?(data_t, :undef).should == true
 
1009
      end
 
1010
 
 
1011
      it 'other symbols should not be considered instance of Data' do
 
1012
        calculator.instance?(data_t, :love).should == false
 
1013
      end
 
1014
 
 
1015
      it 'an empty array should be considered instance of Data' do
 
1016
        calculator.instance?(data_t, []).should == true
 
1017
      end
 
1018
 
 
1019
      it 'an empty hash should be considered instance of Data' do
 
1020
        calculator.instance?(data_t, {}).should == true
 
1021
      end
 
1022
 
 
1023
      it 'a hash with nil/undef data should be considered instance of Data' do
 
1024
        calculator.instance?(data_t, {'a' => nil}).should == true
 
1025
        calculator.instance?(data_t, {'a' => :undef}).should == true
 
1026
      end
 
1027
 
 
1028
      it 'a hash with nil/undef key should not considered instance of Data' do
 
1029
        calculator.instance?(data_t, {nil => 10}).should == false
 
1030
        calculator.instance?(data_t, {:undef => 10}).should == false
 
1031
      end
 
1032
 
 
1033
      it 'an array with undef entries should be considered instance of Data' do
 
1034
        calculator.instance?(data_t, [:undef]).should == true
 
1035
        calculator.instance?(data_t, [nil]).should == true
 
1036
      end
 
1037
 
 
1038
      it 'an array with undef / data entries should be considered instance of Data' do
 
1039
        calculator.instance?(data_t, [1, :undef, 'a']).should == true
 
1040
        calculator.instance?(data_t, [1, nil, 'a']).should == true
 
1041
      end
353
1042
    end
354
1043
  end
355
1044
 
378
1067
      calculator.type(String).class.should == Puppet::Pops::Types::PStringType
379
1068
    end
380
1069
 
381
 
    it 'should yield \'PPatternType\' for Regexp' do
382
 
      calculator.type(Regexp).class.should == Puppet::Pops::Types::PPatternType
 
1070
    it 'should yield \'PRegexpType\' for Regexp' do
 
1071
      calculator.type(Regexp).class.should == Puppet::Pops::Types::PRegexpType
383
1072
    end
384
1073
 
385
1074
    it 'should yield \'PArrayType[PDataType]\' for Array' do
388
1077
      t.element_type.class.should == Puppet::Pops::Types::PDataType
389
1078
    end
390
1079
 
391
 
    it 'should yield \'PHashType[PLiteralType,PDataType]\' for Hash' do
 
1080
    it 'should yield \'PHashType[PScalarType,PDataType]\' for Hash' do
392
1081
      t = calculator.type(Hash)
393
1082
      t.class.should == Puppet::Pops::Types::PHashType
394
 
      t.key_type.class.should == Puppet::Pops::Types::PLiteralType
 
1083
      t.key_type.class.should == Puppet::Pops::Types::PScalarType
395
1084
      t.element_type.class.should == Puppet::Pops::Types::PDataType
396
1085
    end
397
1086
  end
405
1094
      calculator.string(Puppet::Pops::Types::PObjectType.new()).should == 'Object'
406
1095
    end
407
1096
 
408
 
    it 'should yield \'Literal\' for PLiteralType' do
409
 
      calculator.string(Puppet::Pops::Types::PLiteralType.new()).should == 'Literal'
 
1097
    it 'should yield \'Scalar\' for PScalarType' do
 
1098
      calculator.string(Puppet::Pops::Types::PScalarType.new()).should == 'Scalar'
410
1099
    end
411
1100
 
412
1101
    it 'should yield \'Boolean\' for PBooleanType' do
421
1110
      calculator.string(Puppet::Pops::Types::PNumericType.new()).should == 'Numeric'
422
1111
    end
423
1112
 
424
 
    it 'should yield \'Integer\' for PIntegerType' do
425
 
      calculator.string(Puppet::Pops::Types::PIntegerType.new()).should == 'Integer'
 
1113
    it 'should yield \'Integer\' and from/to for PIntegerType' do
 
1114
      int_T = Puppet::Pops::Types::PIntegerType
 
1115
      calculator.string(int_T.new()).should == 'Integer'
 
1116
      int = int_T.new()
 
1117
      int.from = 1
 
1118
      int.to = 1
 
1119
      calculator.string(int).should == 'Integer[1, 1]'
 
1120
      int = int_T.new()
 
1121
      int.from = 1
 
1122
      int.to = 2
 
1123
      calculator.string(int).should == 'Integer[1, 2]'
 
1124
      int = int_T.new()
 
1125
      int.from = nil
 
1126
      int.to = 2
 
1127
      calculator.string(int).should == 'Integer[default, 2]'
 
1128
      int = int_T.new()
 
1129
      int.from = 2
 
1130
      int.to = nil
 
1131
      calculator.string(int).should == 'Integer[2, default]'
426
1132
    end
427
1133
 
428
1134
    it 'should yield \'Float\' for PFloatType' do
429
1135
      calculator.string(Puppet::Pops::Types::PFloatType.new()).should == 'Float'
430
1136
    end
431
1137
 
432
 
    it 'should yield \'Pattern\' for PPatternType' do
433
 
      calculator.string(Puppet::Pops::Types::PPatternType.new()).should == 'Pattern'
 
1138
    it 'should yield \'Regexp\' for PRegexpType' do
 
1139
      calculator.string(Puppet::Pops::Types::PRegexpType.new()).should == 'Regexp'
 
1140
    end
 
1141
 
 
1142
    it 'should yield \'Regexp[/pat/]\' for parameterized PRegexpType' do
 
1143
      t = Puppet::Pops::Types::PRegexpType.new()
 
1144
      t.pattern = ('a/b')
 
1145
      calculator.string(Puppet::Pops::Types::PRegexpType.new()).should == 'Regexp'
434
1146
    end
435
1147
 
436
1148
    it 'should yield \'String\' for PStringType' do
437
1149
      calculator.string(Puppet::Pops::Types::PStringType.new()).should == 'String'
438
1150
    end
439
1151
 
 
1152
    it 'should yield \'String\' for PStringType with multiple values' do
 
1153
      calculator.string(string_t('a', 'b', 'c')).should == 'String'
 
1154
    end
 
1155
 
 
1156
    it 'should yield \'String\' and from/to for PStringType' do
 
1157
      string_T = Puppet::Pops::Types::PStringType
 
1158
      calculator.string(factory.constrain_size(string_T.new(), 1,1)).should == 'String[1, 1]'
 
1159
      calculator.string(factory.constrain_size(string_T.new(), 1,2)).should == 'String[1, 2]'
 
1160
      calculator.string(factory.constrain_size(string_T.new(), :default, 2)).should == 'String[default, 2]'
 
1161
      calculator.string(factory.constrain_size(string_T.new(), 2, :default)).should == 'String[2, default]'
 
1162
    end
 
1163
 
440
1164
    it 'should yield \'Array[Integer]\' for PArrayType[PIntegerType]' do
441
1165
      t = Puppet::Pops::Types::PArrayType.new()
442
1166
      t.element_type = Puppet::Pops::Types::PIntegerType.new()
443
1167
      calculator.string(t).should == 'Array[Integer]'
444
1168
    end
445
1169
 
 
1170
    it 'should yield \'Collection\' and from/to for PCollectionType' do
 
1171
      col = collection_t()
 
1172
      calculator.string(factory.constrain_size(col.copy, 1,1)).should == 'Collection[1, 1]'
 
1173
      calculator.string(factory.constrain_size(col.copy, 1,2)).should == 'Collection[1, 2]'
 
1174
      calculator.string(factory.constrain_size(col.copy, :default, 2)).should == 'Collection[default, 2]'
 
1175
      calculator.string(factory.constrain_size(col.copy, 2, :default)).should == 'Collection[2, default]'
 
1176
    end
 
1177
 
 
1178
    it 'should yield \'Array\' and from/to for PArrayType' do
 
1179
      arr = array_t(string_t)
 
1180
      calculator.string(factory.constrain_size(arr.copy, 1,1)).should == 'Array[String, 1, 1]'
 
1181
      calculator.string(factory.constrain_size(arr.copy, 1,2)).should == 'Array[String, 1, 2]'
 
1182
      calculator.string(factory.constrain_size(arr.copy, :default, 2)).should == 'Array[String, default, 2]'
 
1183
      calculator.string(factory.constrain_size(arr.copy, 2, :default)).should == 'Array[String, 2, default]'
 
1184
    end
 
1185
 
 
1186
    it 'should yield \'Tuple[Integer]\' for PTupleType[PIntegerType]' do
 
1187
      t = Puppet::Pops::Types::PTupleType.new()
 
1188
      t.addTypes(Puppet::Pops::Types::PIntegerType.new())
 
1189
      calculator.string(t).should == 'Tuple[Integer]'
 
1190
    end
 
1191
 
 
1192
    it 'should yield \'Tuple[T, T,..]\' for PTupleType[T, T, ...]' do
 
1193
      t = Puppet::Pops::Types::PTupleType.new()
 
1194
      t.addTypes(Puppet::Pops::Types::PIntegerType.new())
 
1195
      t.addTypes(Puppet::Pops::Types::PIntegerType.new())
 
1196
      t.addTypes(Puppet::Pops::Types::PStringType.new())
 
1197
      calculator.string(t).should == 'Tuple[Integer, Integer, String]'
 
1198
    end
 
1199
 
 
1200
    it 'should yield \'Tuple\' and from/to for PTupleType' do
 
1201
      tuple_t = tuple_t(string_t)
 
1202
      calculator.string(factory.constrain_size(tuple_t.copy, 1,1)).should == 'Tuple[String, 1, 1]'
 
1203
      calculator.string(factory.constrain_size(tuple_t.copy, 1,2)).should == 'Tuple[String, 1, 2]'
 
1204
      calculator.string(factory.constrain_size(tuple_t.copy, :default, 2)).should == 'Tuple[String, default, 2]'
 
1205
      calculator.string(factory.constrain_size(tuple_t.copy, 2, :default)).should == 'Tuple[String, 2, default]'
 
1206
    end
 
1207
 
 
1208
    it 'should yield \'Struct\' and details for PStructType' do
 
1209
      struct_t = struct_t({'a'=>Integer, 'b'=>String})
 
1210
      s = calculator.string(struct_t)
 
1211
      # Ruby 1.8.7 - noone likes you...
 
1212
      (s == "Struct[{'a'=>Integer, 'b'=>String}]" || s == "Struct[{'b'=>String, 'a'=>Integer}]").should == true
 
1213
      struct_t = struct_t({})
 
1214
      calculator.string(struct_t).should == "Struct"
 
1215
    end
 
1216
 
446
1217
    it 'should yield \'Hash[String, Integer]\' for PHashType[PStringType, PIntegerType]' do
447
1218
      t = Puppet::Pops::Types::PHashType.new()
448
1219
      t.key_type = Puppet::Pops::Types::PStringType.new()
449
1220
      t.element_type = Puppet::Pops::Types::PIntegerType.new()
450
1221
      calculator.string(t).should == 'Hash[String, Integer]'
451
1222
    end
 
1223
 
 
1224
    it 'should yield \'Hash\' and from/to for PHashType' do
 
1225
      hsh = hash_t(string_t, string_t)
 
1226
      calculator.string(factory.constrain_size(hsh.copy, 1,1)).should == 'Hash[String, String, 1, 1]'
 
1227
      calculator.string(factory.constrain_size(hsh.copy, 1,2)).should == 'Hash[String, String, 1, 2]'
 
1228
      calculator.string(factory.constrain_size(hsh.copy, :default, 2)).should == 'Hash[String, String, default, 2]'
 
1229
      calculator.string(factory.constrain_size(hsh.copy, 2, :default)).should == 'Hash[String, String, 2, default]'
 
1230
    end
 
1231
 
 
1232
    it "should yield 'Class' for a PHostClassType" do
 
1233
      t = Puppet::Pops::Types::PHostClassType.new()
 
1234
      calculator.string(t).should == 'Class'
 
1235
    end
 
1236
 
 
1237
    it "should yield 'Class[x]' for a PHostClassType[x]" do
 
1238
      t = Puppet::Pops::Types::PHostClassType.new()
 
1239
      t.class_name = 'x'
 
1240
      calculator.string(t).should == 'Class[x]'
 
1241
    end
 
1242
 
 
1243
    it "should yield 'Resource' for a PResourceType" do
 
1244
      t = Puppet::Pops::Types::PResourceType.new()
 
1245
      calculator.string(t).should == 'Resource'
 
1246
    end
 
1247
 
 
1248
    it 'should yield \'File\' for a PResourceType[\'File\']' do
 
1249
      t = Puppet::Pops::Types::PResourceType.new()
 
1250
      t.type_name = 'File'
 
1251
      calculator.string(t).should == 'File'
 
1252
    end
 
1253
 
 
1254
    it "should yield 'File['/tmp/foo']' for a PResourceType['File', '/tmp/foo']" do
 
1255
      t = Puppet::Pops::Types::PResourceType.new()
 
1256
      t.type_name = 'File'
 
1257
      t.title = '/tmp/foo'
 
1258
      calculator.string(t).should == "File['/tmp/foo']"
 
1259
    end
 
1260
 
 
1261
    it "should yield 'Enum[s,...]' for a PEnumType[s,...]" do
 
1262
      t = enum_t('a', 'b', 'c')
 
1263
      calculator.string(t).should == "Enum['a', 'b', 'c']"
 
1264
    end
 
1265
 
 
1266
    it "should yield 'Pattern[/pat/,...]' for a PPatternType['pat',...]" do
 
1267
      t = pattern_t('a')
 
1268
      t2 = pattern_t('a', 'b', 'c')
 
1269
      calculator.string(t).should == "Pattern[/a/]"
 
1270
      calculator.string(t2).should == "Pattern[/a/, /b/, /c/]"
 
1271
    end
 
1272
 
 
1273
    it "should escape special characters in the string for a PPatternType['pat',...]" do
 
1274
      t = pattern_t('a/b')
 
1275
      calculator.string(t).should == "Pattern[/a\\/b/]"
 
1276
    end
 
1277
 
 
1278
    it "should yield 'Variant[t1,t2,...]' for a PVariantType[t1, t2,...]" do
 
1279
      t1 = string_t()
 
1280
      t2 = integer_t()
 
1281
      t3 = pattern_t('a')
 
1282
      t = variant_t(t1, t2, t3)
 
1283
      calculator.string(t).should == "Variant[String, Integer, Pattern[/a/]]"
 
1284
    end
452
1285
  end
453
1286
 
454
1287
  context 'when processing meta type' do
456
1289
      ptype = Puppet::Pops::Types::PType
457
1290
      calculator.infer(Puppet::Pops::Types::PNilType.new()       ).is_a?(ptype).should() == true
458
1291
      calculator.infer(Puppet::Pops::Types::PDataType.new()      ).is_a?(ptype).should() == true
459
 
      calculator.infer(Puppet::Pops::Types::PLiteralType.new()   ).is_a?(ptype).should() == true
 
1292
      calculator.infer(Puppet::Pops::Types::PScalarType.new()   ).is_a?(ptype).should() == true
460
1293
      calculator.infer(Puppet::Pops::Types::PStringType.new()    ).is_a?(ptype).should() == true
461
1294
      calculator.infer(Puppet::Pops::Types::PNumericType.new()   ).is_a?(ptype).should() == true
462
1295
      calculator.infer(Puppet::Pops::Types::PIntegerType.new()   ).is_a?(ptype).should() == true
463
1296
      calculator.infer(Puppet::Pops::Types::PFloatType.new()     ).is_a?(ptype).should() == true
464
 
      calculator.infer(Puppet::Pops::Types::PPatternType.new()   ).is_a?(ptype).should() == true
 
1297
      calculator.infer(Puppet::Pops::Types::PRegexpType.new()   ).is_a?(ptype).should() == true
465
1298
      calculator.infer(Puppet::Pops::Types::PBooleanType.new()   ).is_a?(ptype).should() == true
466
1299
      calculator.infer(Puppet::Pops::Types::PCollectionType.new()).is_a?(ptype).should() == true
467
1300
      calculator.infer(Puppet::Pops::Types::PArrayType.new()     ).is_a?(ptype).should() == true
468
1301
      calculator.infer(Puppet::Pops::Types::PHashType.new()      ).is_a?(ptype).should() == true
469
1302
      calculator.infer(Puppet::Pops::Types::PRubyType.new()      ).is_a?(ptype).should() == true
 
1303
      calculator.infer(Puppet::Pops::Types::PHostClassType.new() ).is_a?(ptype).should() == true
 
1304
      calculator.infer(Puppet::Pops::Types::PResourceType.new()  ).is_a?(ptype).should() == true
 
1305
      calculator.infer(Puppet::Pops::Types::PEnumType.new()      ).is_a?(ptype).should() == true
 
1306
      calculator.infer(Puppet::Pops::Types::PPatternType.new()   ).is_a?(ptype).should() == true
 
1307
      calculator.infer(Puppet::Pops::Types::PVariantType.new()   ).is_a?(ptype).should() == true
 
1308
      calculator.infer(Puppet::Pops::Types::PTupleType.new()     ).is_a?(ptype).should() == true
 
1309
    end
 
1310
 
 
1311
    it 'should infer PType as the type of all other types' do
 
1312
      ptype = Puppet::Pops::Types::PType
 
1313
      calculator.string(calculator.infer(Puppet::Pops::Types::PNilType.new()       )).should == "Type[Undef]"
 
1314
      calculator.string(calculator.infer(Puppet::Pops::Types::PDataType.new()      )).should == "Type[Data]"
 
1315
      calculator.string(calculator.infer(Puppet::Pops::Types::PScalarType.new()   )).should == "Type[Scalar]"
 
1316
      calculator.string(calculator.infer(Puppet::Pops::Types::PStringType.new()    )).should == "Type[String]"
 
1317
      calculator.string(calculator.infer(Puppet::Pops::Types::PNumericType.new()   )).should == "Type[Numeric]"
 
1318
      calculator.string(calculator.infer(Puppet::Pops::Types::PIntegerType.new()   )).should == "Type[Integer]"
 
1319
      calculator.string(calculator.infer(Puppet::Pops::Types::PFloatType.new()     )).should == "Type[Float]"
 
1320
      calculator.string(calculator.infer(Puppet::Pops::Types::PRegexpType.new()    )).should == "Type[Regexp]"
 
1321
      calculator.string(calculator.infer(Puppet::Pops::Types::PBooleanType.new()   )).should == "Type[Boolean]"
 
1322
      calculator.string(calculator.infer(Puppet::Pops::Types::PCollectionType.new())).should == "Type[Collection]"
 
1323
      calculator.string(calculator.infer(Puppet::Pops::Types::PArrayType.new()     )).should == "Type[Array[?]]"
 
1324
      calculator.string(calculator.infer(Puppet::Pops::Types::PHashType.new()      )).should == "Type[Hash[?, ?]]"
 
1325
      calculator.string(calculator.infer(Puppet::Pops::Types::PRubyType.new()      )).should == "Type[Ruby[?]]"
 
1326
      calculator.string(calculator.infer(Puppet::Pops::Types::PHostClassType.new() )).should == "Type[Class]"
 
1327
      calculator.string(calculator.infer(Puppet::Pops::Types::PResourceType.new()  )).should == "Type[Resource]"
 
1328
      calculator.string(calculator.infer(Puppet::Pops::Types::PEnumType.new()      )).should == "Type[Enum]"
 
1329
      calculator.string(calculator.infer(Puppet::Pops::Types::PVariantType.new()   )).should == "Type[Variant]"
 
1330
      calculator.string(calculator.infer(Puppet::Pops::Types::PPatternType.new()   )).should == "Type[Pattern]"
 
1331
      calculator.string(calculator.infer(Puppet::Pops::Types::PTupleType.new()     )).should == "Type[Tuple]"
 
1332
    end
 
1333
 
 
1334
    it "computes the common type of PType's type parameter" do
 
1335
      int_t    = Puppet::Pops::Types::PIntegerType.new()
 
1336
      string_t = Puppet::Pops::Types::PStringType.new()
 
1337
      calculator.string(calculator.infer([int_t])).should == "Array[Type[Integer], 1, 1]"
 
1338
      calculator.string(calculator.infer([int_t, string_t])).should == "Array[Type[Scalar], 2, 2]"
470
1339
    end
471
1340
 
472
1341
    it 'should infer PType as the type of ruby classes' do
480
1349
    it 'should infer PType as the type of PType (meta regression short-circuit)' do
481
1350
      calculator.infer(Puppet::Pops::Types::PType.new()).is_a?(Puppet::Pops::Types::PType).should() == true
482
1351
    end
483
 
  end
 
1352
 
 
1353
    it 'computes instance? to be true if parameterized and type match' do
 
1354
      int_t    = Puppet::Pops::Types::PIntegerType.new()
 
1355
      type_t   = Puppet::Pops::Types::TypeFactory.type_type(int_t)
 
1356
      type_type_t   = Puppet::Pops::Types::TypeFactory.type_type(type_t)
 
1357
      calculator.instance?(type_type_t, type_t).should == true
 
1358
    end
 
1359
 
 
1360
    it 'computes instance? to be false if parameterized and type do not match' do
 
1361
      int_t    = Puppet::Pops::Types::PIntegerType.new()
 
1362
      string_t = Puppet::Pops::Types::PStringType.new()
 
1363
      type_t   = Puppet::Pops::Types::TypeFactory.type_type(int_t)
 
1364
      type_t2   = Puppet::Pops::Types::TypeFactory.type_type(string_t)
 
1365
      type_type_t   = Puppet::Pops::Types::TypeFactory.type_type(type_t)
 
1366
      # i.e. Type[Integer] =~ Type[Type[Integer]] # false
 
1367
      calculator.instance?(type_type_t, type_t2).should == false
 
1368
    end
 
1369
 
 
1370
    it 'computes instance? to be true if unparameterized and matched against a type[?]' do
 
1371
      int_t    = Puppet::Pops::Types::PIntegerType.new()
 
1372
      type_t   = Puppet::Pops::Types::TypeFactory.type_type(int_t)
 
1373
      calculator.instance?(Puppet::Pops::Types::PType.new, type_t).should == true
 
1374
    end
 
1375
  end
 
1376
 
 
1377
  context "when asking for an enumerable " do
 
1378
    it "should produce an enumerable for an Integer range that is not infinite" do
 
1379
      t = Puppet::Pops::Types::PIntegerType.new()
 
1380
      t.from = 1
 
1381
      t.to = 10
 
1382
      calculator.enumerable(t).respond_to?(:each).should == true
 
1383
    end
 
1384
 
 
1385
    it "should not produce an enumerable for an Integer range that has an infinite side" do
 
1386
      t = Puppet::Pops::Types::PIntegerType.new()
 
1387
      t.from = nil
 
1388
      t.to = 10
 
1389
      calculator.enumerable(t).should == nil
 
1390
 
 
1391
      t = Puppet::Pops::Types::PIntegerType.new()
 
1392
      t.from = 1
 
1393
      t.to = nil
 
1394
      calculator.enumerable(t).should == nil
 
1395
    end
 
1396
 
 
1397
    it "all but Integer range are not enumerable" do
 
1398
      [Object, Numeric, Float, String, Regexp, Array, Hash].each do |t|
 
1399
        calculator.enumerable(calculator.type(t)).should == nil
 
1400
      end
 
1401
    end
 
1402
  end
 
1403
 
 
1404
  context "when dealing with different types of inference" do
 
1405
    it "an instance specific inference is produced by infer" do
 
1406
      calculator.infer(['a','b']).element_type.values.should == ['a', 'b']
 
1407
    end
 
1408
 
 
1409
    it "a generic inference is produced using infer_generic" do
 
1410
      calculator.infer_generic(['a','b']).element_type.values.should == []
 
1411
    end
 
1412
 
 
1413
    it "a generic result is created by generalize! given an instance specific result for an Array" do
 
1414
      generic = calculator.infer(['a','b'])
 
1415
      generic.element_type.values.should == ['a', 'b']
 
1416
      calculator.generalize!(generic)
 
1417
      generic.element_type.values.should == []
 
1418
    end
 
1419
 
 
1420
    it "a generic result is created by generalize! given an instance specific result for a Hash" do
 
1421
      generic = calculator.infer({'a' =>1,'b' => 2})
 
1422
      generic.key_type.values.sort.should == ['a', 'b']
 
1423
      generic.element_type.from.should == 1
 
1424
      generic.element_type.to.should == 2
 
1425
      calculator.generalize!(generic)
 
1426
      generic.key_type.values.should == []
 
1427
      generic.element_type.from.should == nil
 
1428
      generic.element_type.to.should == nil
 
1429
    end
 
1430
 
 
1431
    it "does not reduce by combining types when using infer_set" do
 
1432
      element_type = calculator.infer(['a','b',1,2]).element_type
 
1433
      element_type.class.should == Puppet::Pops::Types::PScalarType
 
1434
      element_type = calculator.infer_set(['a','b',1,2]).element_type
 
1435
      element_type.class.should == Puppet::Pops::Types::PVariantType
 
1436
      element_type.types[0].class.should == Puppet::Pops::Types::PStringType
 
1437
      element_type.types[1].class.should == Puppet::Pops::Types::PStringType
 
1438
      element_type.types[2].class.should == Puppet::Pops::Types::PIntegerType
 
1439
      element_type.types[3].class.should == Puppet::Pops::Types::PIntegerType
 
1440
    end
 
1441
 
 
1442
    it "does not reduce by combining types when using infer_set and values are undef" do
 
1443
      element_type = calculator.infer(['a',nil]).element_type
 
1444
      element_type.class.should == Puppet::Pops::Types::PStringType
 
1445
      element_type = calculator.infer_set(['a',nil]).element_type
 
1446
      element_type.class.should == Puppet::Pops::Types::PVariantType
 
1447
      element_type.types[0].class.should == Puppet::Pops::Types::PStringType
 
1448
      element_type.types[1].class.should == Puppet::Pops::Types::PNilType
 
1449
    end
 
1450
  end
 
1451
 
 
1452
  matcher :be_assignable_to do |type|
 
1453
    calc = Puppet::Pops::Types::TypeCalculator.new
 
1454
 
 
1455
    match do |actual|
 
1456
      calc.assignable?(type, actual)
 
1457
    end
 
1458
 
 
1459
    failure_message_for_should do |actual|
 
1460
      "#{calc.string(actual)} should be assignable to #{calc.string(type)}"
 
1461
    end
 
1462
 
 
1463
    failure_message_for_should_not do |actual|
 
1464
      "#{calc.string(actual)} is assignable to #{calc.string(type)} when it should not"
 
1465
    end
 
1466
  end
 
1467
 
484
1468
end