OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'package:kernel/ast.dart'; | |
6 import 'package:kernel/class_hierarchy.dart'; | |
7 import 'package:kernel/core_types.dart'; | |
8 import 'package:kernel/testing/mock_sdk_program.dart'; | |
9 import 'package:test/test.dart'; | |
10 | |
11 main() { | |
12 group('ClosedWorldClassHierarchyTest', () { | |
13 _ClassHierarchyTest._runTests(() => new ClosedWorldClassHierarchyTest()); | |
14 }); | |
15 } | |
16 | |
17 class ClosedWorldClassHierarchyTest extends _ClassHierarchyTest { | |
18 ClassHierarchy createClassHierarchy(Program program) { | |
19 return new ClosedWorldClassHierarchy(program); | |
20 } | |
21 } | |
22 | |
23 abstract class _ClassHierarchyTest { | |
24 Program program; | |
25 CoreTypes coreTypes; | |
26 | |
27 /// The test library. | |
28 Library library; | |
29 | |
30 ClassHierarchy _hierarchy; | |
31 | |
32 /// Return the new or existing instance of [ClassHierarchy]. | |
33 ClassHierarchy get hierarchy { | |
34 return _hierarchy ??= createClassHierarchy(program); | |
35 } | |
36 | |
37 Class get objectClass => coreTypes.objectClass; | |
38 | |
39 Supertype get objectSuper => coreTypes.objectClass.asThisSupertype; | |
40 | |
41 Class addClass(Class c) { | |
42 if (_hierarchy != null) { | |
43 fail('The class hierarchy has already been created.'); | |
44 } | |
45 library.addClass(c); | |
46 return c; | |
47 } | |
48 | |
49 /// Add a new generic class with the given [name] and [typeParameterNames]. | |
50 /// The [TypeParameterType]s corresponding to [typeParameterNames] are | |
51 /// passed to optional [extends_] and [implements_] callbacks. | |
52 Class addGenericClass(String name, List<String> typeParameterNames, | |
53 {Supertype extends_(List<DartType> typeParameterTypes), | |
54 List<Supertype> implements_(List<DartType> typeParameterTypes)}) { | |
55 var typeParameters = typeParameterNames | |
56 .map((name) => new TypeParameter(name, objectClass.rawType)) | |
57 .toList(); | |
58 var typeParameterTypes = typeParameters | |
59 .map((parameter) => new TypeParameterType(parameter)) | |
60 .toList(); | |
61 var supertype = | |
62 extends_ != null ? extends_(typeParameterTypes) : objectSuper; | |
63 var implementedTypes = | |
64 implements_ != null ? implements_(typeParameterTypes) : []; | |
65 return addClass(new Class( | |
66 name: name, | |
67 typeParameters: typeParameters, | |
68 supertype: supertype, | |
69 implementedTypes: implementedTypes)); | |
70 } | |
71 | |
72 /// Add a new class with the given [name] that extends `Object` and | |
73 /// [implements_] the given classes. | |
74 Class addImplementsClass(String name, List<Class> implements_) { | |
75 return addClass(new Class( | |
76 name: name, | |
77 supertype: objectSuper, | |
78 implementedTypes: implements_.map((c) => c.asThisSupertype).toList())); | |
79 } | |
80 | |
81 ClassHierarchy createClassHierarchy(Program program); | |
82 | |
83 Procedure newEmptyMethod(String name, {bool abstract: false}) { | |
84 var body = abstract ? null : new Block([]); | |
85 return new Procedure( | |
86 new Name(name), ProcedureKind.Method, new FunctionNode(body)); | |
87 } | |
88 | |
89 Procedure newEmptySetter(String name) { | |
90 return new Procedure( | |
91 new Name(name), | |
92 ProcedureKind.Setter, | |
93 new FunctionNode(new Block([]), | |
94 positionalParameters: [new VariableDeclaration('_')])); | |
95 } | |
96 | |
97 void setUp() { | |
98 // Start with mock SDK libraries. | |
99 program = createMockSdkProgram(); | |
100 coreTypes = new CoreTypes(program); | |
101 | |
102 // Add the test library. | |
103 library = new Library(Uri.parse('org-dartlang:///test.dart'), name: 'test'); | |
104 library.parent = program; | |
105 program.libraries.add(library); | |
106 } | |
107 | |
108 void tearDown() {} | |
109 | |
110 void test_forEachOverridePair_overrideSupertype() { | |
111 // Create the class hierarchy: | |
112 // | |
113 // abstract class A extends Object { | |
114 // foo() {} | |
115 // bar() {} | |
116 // } | |
117 // class B extends A { | |
118 // foo() {} | |
119 // } | |
120 // class C extends B { | |
121 // bar() {} | |
122 // } | |
123 var aFoo = newEmptyMethod('foo'); | |
124 var aBar = newEmptyMethod('bar'); | |
125 var bFoo = newEmptyMethod('foo'); | |
126 var cBar = newEmptyMethod('bar'); | |
127 var a = addClass( | |
128 new Class(name: 'A', supertype: objectSuper, procedures: [aFoo, aBar])); | |
129 var b = addClass( | |
130 new Class(name: 'B', supertype: a.asThisSupertype, procedures: [bFoo])); | |
131 var c = addClass( | |
132 new Class(name: 'C', supertype: b.asThisSupertype, procedures: [cBar])); | |
133 | |
134 _assertOverridePairs(b, ['test::B::foo overrides test::A::foo']); | |
135 _assertOverridePairs(c, ['test::C::bar overrides test::A::bar']); | |
136 } | |
137 | |
138 void test_getClassAsInstanceOf_generic_extends() { | |
139 // Create the class hierarchy: | |
140 // | |
141 // class A<T, U> extends Object {} | |
142 // class B<T> extends A<T, bool> {} | |
143 // class C extends B<int> {} | |
144 var int = coreTypes.intClass.rawType; | |
145 var bool = coreTypes.boolClass.rawType; | |
146 | |
147 var a = addGenericClass('A', ['T', 'U']); | |
148 | |
149 var bT = new TypeParameter('T', objectClass.rawType); | |
150 var bTT = new TypeParameterType(bT); | |
151 var b = addClass(new Class( | |
152 name: 'B', | |
153 typeParameters: [bT], | |
154 supertype: new Supertype(a, [bTT, bool]))); | |
155 | |
156 var c = addClass(new Class(name: 'C', supertype: new Supertype(b, [int]))); | |
157 | |
158 expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); | |
159 expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); | |
160 expect(hierarchy.getClassAsInstanceOf(b, a), new Supertype(a, [bTT, bool])); | |
161 expect(hierarchy.getClassAsInstanceOf(c, b), new Supertype(b, [int])); | |
162 expect(hierarchy.getClassAsInstanceOf(c, a), new Supertype(a, [int, bool])); | |
163 } | |
164 | |
165 void test_getClassAsInstanceOf_generic_implements() { | |
166 // Create the class hierarchy: | |
167 // | |
168 // class A<T, U> extends Object {} | |
169 // class B<T> extends Object implements A<T, bool> {} | |
170 // class C extends Object implements B<int> {} | |
171 var int = coreTypes.intClass.rawType; | |
172 var bool = coreTypes.boolClass.rawType; | |
173 | |
174 var a = addGenericClass('A', ['T', 'U']); | |
175 | |
176 var bT = new TypeParameter('T', objectClass.rawType); | |
177 var bTT = new TypeParameterType(bT); | |
178 var b = addClass(new Class( | |
179 name: 'B', | |
180 typeParameters: [bT], | |
181 supertype: objectSuper, | |
182 implementedTypes: [ | |
183 new Supertype(a, [bTT, bool]) | |
184 ])); | |
185 | |
186 var c = addClass( | |
187 new Class(name: 'C', supertype: objectSuper, implementedTypes: [ | |
188 new Supertype(b, [int]) | |
189 ])); | |
190 | |
191 expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); | |
192 expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); | |
193 expect(hierarchy.getClassAsInstanceOf(b, a), new Supertype(a, [bTT, bool])); | |
194 expect(hierarchy.getClassAsInstanceOf(c, b), new Supertype(b, [int])); | |
195 expect(hierarchy.getClassAsInstanceOf(c, a), new Supertype(a, [int, bool])); | |
196 } | |
197 | |
198 void test_getClassAsInstanceOf_generic_with() { | |
199 // Create the class hierarchy: | |
200 // | |
201 // class A<T, U> extends Object {} | |
202 // class B<T> extends Object with A<T, bool> {} | |
203 // class C extends Object with B<int> {} | |
ahe
2017/05/31 17:33:49
Instead of all these comments, I'd take advantage
scheglov
2017/05/31 17:53:27
That's an interesting idea.
I will do this in the
| |
204 var int = coreTypes.intClass.rawType; | |
205 var bool = coreTypes.boolClass.rawType; | |
206 | |
207 var a = addGenericClass('A', ['T', 'U']); | |
208 | |
209 var bT = new TypeParameter('T', objectClass.rawType); | |
210 var bTT = new TypeParameterType(bT); | |
211 var b = addClass(new Class( | |
212 name: 'B', | |
213 typeParameters: [bT], | |
214 supertype: objectSuper, | |
215 mixedInType: new Supertype(a, [bTT, bool]))); | |
216 | |
217 var c = addClass(new Class( | |
218 name: 'C', | |
219 supertype: objectSuper, | |
220 mixedInType: new Supertype(b, [int]))); | |
221 | |
222 expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); | |
223 expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); | |
224 expect(hierarchy.getClassAsInstanceOf(b, a), new Supertype(a, [bTT, bool])); | |
225 expect(hierarchy.getClassAsInstanceOf(c, b), new Supertype(b, [int])); | |
226 expect(hierarchy.getClassAsInstanceOf(c, a), new Supertype(a, [int, bool])); | |
227 } | |
228 | |
229 void test_getClassAsInstanceOf_notGeneric_extends() { | |
230 // Create the class hierarchy: | |
231 // | |
232 // class A extends Object {} | |
233 // class B extends A {} | |
234 // class C extends B {} | |
235 // class Z extends Object {} | |
236 var a = addClass(new Class(name: 'A', supertype: objectSuper)); | |
237 var b = addClass(new Class(name: 'B', supertype: a.asThisSupertype)); | |
238 var c = addClass(new Class(name: 'C', supertype: b.asThisSupertype)); | |
239 var z = addClass(new Class(name: 'Z', supertype: objectSuper)); | |
240 | |
241 expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); | |
242 expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); | |
243 expect(hierarchy.getClassAsInstanceOf(b, a), a.asThisSupertype); | |
244 expect(hierarchy.getClassAsInstanceOf(c, a), a.asThisSupertype); | |
245 expect(hierarchy.getClassAsInstanceOf(c, b), b.asThisSupertype); | |
246 expect(hierarchy.getClassAsInstanceOf(z, a), null); | |
247 expect(hierarchy.getClassAsInstanceOf(z, objectClass), objectSuper); | |
248 } | |
249 | |
250 void test_getClassAsInstanceOf_notGeneric_implements() { | |
251 // Create the class hierarchy: | |
252 // | |
253 // class A extends Object {} | |
254 // class B extends Object {} | |
255 // class C extends Object implements A {} | |
256 // class D extends Object implements C {} | |
257 // class E extends A implements B {} | |
258 // class Z extends Object {} | |
259 var a = addClass(new Class(name: 'A', supertype: objectSuper)); | |
260 var b = addClass(new Class(name: 'B', supertype: objectSuper)); | |
261 var c = addClass(new Class( | |
262 name: 'C', | |
263 supertype: objectSuper, | |
264 implementedTypes: [a.asThisSupertype])); | |
265 var d = addClass(new Class( | |
266 name: 'D', | |
267 supertype: objectSuper, | |
268 implementedTypes: [c.asThisSupertype])); | |
269 var e = addClass(new Class( | |
270 name: 'D', | |
271 supertype: a.asThisSupertype, | |
272 implementedTypes: [b.asThisSupertype])); | |
273 var z = addClass(new Class(name: 'Z', supertype: objectSuper)); | |
274 | |
275 expect(hierarchy.getClassAsInstanceOf(c, a), a.asThisSupertype); | |
276 expect(hierarchy.getClassAsInstanceOf(d, a), a.asThisSupertype); | |
277 expect(hierarchy.getClassAsInstanceOf(d, c), c.asThisSupertype); | |
278 expect(hierarchy.getClassAsInstanceOf(e, a), a.asThisSupertype); | |
279 expect(hierarchy.getClassAsInstanceOf(e, b), b.asThisSupertype); | |
280 expect(hierarchy.getClassAsInstanceOf(z, a), null); | |
281 } | |
282 | |
283 void test_getClassAsInstanceOf_notGeneric_with() { | |
284 // Create the class hierarchy: | |
285 // | |
286 // class A extends Object {} | |
287 // class B extends Object with A {} | |
288 // class Z extends Object {} | |
289 var a = addClass(new Class(name: 'A', supertype: objectSuper)); | |
290 var b = addClass(new Class( | |
291 name: 'B', supertype: objectSuper, mixedInType: a.asThisSupertype)); | |
292 var z = addClass(new Class(name: 'Z', supertype: objectSuper)); | |
293 | |
294 expect(hierarchy.getClassAsInstanceOf(b, objectClass), objectSuper); | |
295 expect(hierarchy.getClassAsInstanceOf(b, a), a.asThisSupertype); | |
296 expect(hierarchy.getClassAsInstanceOf(z, a), null); | |
297 } | |
298 | |
299 void test_getClassDepth() { | |
300 var base = addClass(new Class(name: 'base', supertype: objectSuper)); | |
301 var extends_ = | |
302 addClass(new Class(name: 'extends_', supertype: base.asThisSupertype)); | |
303 var with_ = addClass(new Class( | |
304 name: 'with_', | |
305 supertype: objectSuper, | |
306 mixedInType: base.asThisSupertype)); | |
307 var implements_ = addClass(new Class( | |
308 name: 'implements_', | |
309 supertype: objectSuper, | |
310 implementedTypes: [base.asThisSupertype])); | |
311 | |
312 expect(hierarchy.getClassDepth(objectClass), 0); | |
313 expect(hierarchy.getClassDepth(base), 1); | |
314 expect(hierarchy.getClassDepth(extends_), 2); | |
315 expect(hierarchy.getClassDepth(with_), 2); | |
316 expect(hierarchy.getClassDepth(implements_), 2); | |
317 } | |
318 | |
319 void test_getClassicLeastUpperBound_generic() { | |
320 var int = coreTypes.intClass.rawType; | |
321 var double = coreTypes.doubleClass.rawType; | |
322 var bool = coreTypes.boolClass.rawType; | |
323 | |
324 // Create the class hierarchy: | |
325 // | |
326 // Object | |
327 // | | |
328 // A | |
329 // / \ | |
330 // B<T> C<U> | |
331 // \ / | |
332 // D<T,U> | |
333 // / \ | |
334 // E F | |
335 // | |
336 // Where E implements D<int, double> and F implements D<int, bool>. | |
337 var a = addGenericClass('A', []); | |
338 var b = | |
339 addGenericClass('B', ['T'], implements_: (_) => [a.asThisSupertype]); | |
340 var c = | |
341 addGenericClass('C', ['U'], implements_: (_) => [a.asThisSupertype]); | |
342 var d = addGenericClass('D', ['T', 'U'], implements_: (typeParameterTypes) { | |
343 var t = typeParameterTypes[0]; | |
344 var u = typeParameterTypes[1]; | |
345 return [ | |
346 new Supertype(b, [t]), | |
347 new Supertype(c, [u]) | |
348 ]; | |
349 }); | |
350 var e = addGenericClass('E', [], | |
351 implements_: (_) => [ | |
352 new Supertype(d, [int, double]) | |
353 ]); | |
354 var f = addGenericClass('F', [], | |
355 implements_: (_) => [ | |
356 new Supertype(d, [int, bool]) | |
357 ]); | |
358 | |
359 expect( | |
360 hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), | |
361 new InterfaceType(d, [int, double])), | |
362 new InterfaceType(d, [int, double])); | |
363 expect( | |
364 hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), | |
365 new InterfaceType(d, [int, bool])), | |
366 new InterfaceType(b, [int])); | |
367 expect( | |
368 hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), | |
369 new InterfaceType(d, [bool, double])), | |
370 new InterfaceType(c, [double])); | |
371 expect( | |
372 hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), | |
373 new InterfaceType(d, [bool, int])), | |
374 a.rawType); | |
375 expect(hierarchy.getClassicLeastUpperBound(e.rawType, f.rawType), | |
376 new InterfaceType(b, [int])); | |
377 } | |
378 | |
379 void test_getClassicLeastUpperBound_nonGeneric() { | |
380 // Create the class hierarchy: | |
381 // | |
382 // Object | |
383 // / \ | |
384 // A B | |
385 // /|\ | |
386 // C D E | |
387 // |X|/ | |
388 // FG HI | |
389 // | |
390 // (F and G both implement (C, D); H and I both implement (C, D, E). | |
391 var a = addImplementsClass('A', []); | |
392 var b = addImplementsClass('B', []); | |
393 var c = addImplementsClass('C', [a]); | |
394 var d = addImplementsClass('D', [a]); | |
395 var e = addImplementsClass('E', [a]); | |
396 var f = addImplementsClass('F', [c, d]); | |
397 var g = addImplementsClass('G', [c, d]); | |
398 var h = addImplementsClass('H', [c, d, e]); | |
399 var i = addImplementsClass('I', [c, d, e]); | |
400 var hierarchy = new ClassHierarchy(program); | |
401 | |
402 expect(hierarchy.getClassicLeastUpperBound(a.rawType, b.rawType), | |
403 objectClass.rawType); | |
404 expect(hierarchy.getClassicLeastUpperBound(a.rawType, objectClass.rawType), | |
405 objectClass.rawType); | |
406 expect(hierarchy.getClassicLeastUpperBound(objectClass.rawType, b.rawType), | |
407 objectClass.rawType); | |
408 expect( | |
409 hierarchy.getClassicLeastUpperBound(c.rawType, d.rawType), a.rawType); | |
410 expect( | |
411 hierarchy.getClassicLeastUpperBound(c.rawType, a.rawType), a.rawType); | |
412 expect( | |
413 hierarchy.getClassicLeastUpperBound(a.rawType, d.rawType), a.rawType); | |
414 expect( | |
415 hierarchy.getClassicLeastUpperBound(f.rawType, g.rawType), a.rawType); | |
416 expect( | |
417 hierarchy.getClassicLeastUpperBound(h.rawType, i.rawType), a.rawType); | |
418 } | |
419 | |
420 void test_getDispatchTarget() { | |
421 // Create the class hierarchy: | |
422 // | |
423 // class A extends Object { | |
424 // aMethod() {} | |
425 // void set aSetter(_) {} | |
426 // } | |
427 // class B extends A { | |
428 // bMethod() {} | |
429 // void set bSetter(_) {} | |
430 // } | |
431 // class C extends B {} | |
432 var aMethod = newEmptyMethod('aMethod'); | |
433 var aSetter = newEmptySetter('aSetter'); | |
434 var bMethod = newEmptyMethod('bMethod'); | |
435 var bSetter = newEmptySetter('bSetter'); | |
436 var a = addClass(new Class( | |
437 name: 'A', supertype: objectSuper, procedures: [aMethod, aSetter])); | |
438 var b = addClass(new Class( | |
439 name: 'B', | |
440 supertype: a.asThisSupertype, | |
441 procedures: [bMethod, bSetter])); | |
442 var c = addClass(new Class(name: 'C', supertype: b.asThisSupertype)); | |
443 | |
444 var aMethodName = new Name('aMethod'); | |
445 var aSetterName = new Name('aSetter'); | |
446 var bMethodName = new Name('bMethod'); | |
447 var bSetterName = new Name('bSetter'); | |
448 expect(hierarchy.getDispatchTarget(a, aMethodName), aMethod); | |
449 expect(hierarchy.getDispatchTarget(a, bMethodName), isNull); | |
450 expect(hierarchy.getDispatchTarget(a, aSetterName, setter: true), aSetter); | |
451 expect(hierarchy.getDispatchTarget(a, bSetterName, setter: true), isNull); | |
452 expect(hierarchy.getDispatchTarget(b, aMethodName), aMethod); | |
453 expect(hierarchy.getDispatchTarget(b, bMethodName), bMethod); | |
454 expect(hierarchy.getDispatchTarget(b, aSetterName, setter: true), aSetter); | |
455 expect(hierarchy.getDispatchTarget(b, bSetterName, setter: true), bSetter); | |
456 expect(hierarchy.getDispatchTarget(c, aMethodName), aMethod); | |
457 expect(hierarchy.getDispatchTarget(c, bMethodName), bMethod); | |
458 expect(hierarchy.getDispatchTarget(c, aSetterName, setter: true), aSetter); | |
459 expect(hierarchy.getDispatchTarget(c, bSetterName, setter: true), bSetter); | |
460 } | |
461 | |
462 void test_getDispatchTarget_abstract() { | |
463 // Create the class hierarchy: | |
464 // | |
465 // abstract class A extends Object { | |
466 // aMethodAbstract(); | |
467 // aMethodConcrete() {} | |
468 // } | |
469 // abstract class B extends A { | |
470 // aMethodConcrete(); | |
471 // bMethodAbstract(); | |
472 // bMethodConcrete() {} | |
473 // } | |
474 // class C extends B {} | |
475 var aMethodConcrete = newEmptyMethod('aMethodConcrete'); | |
476 var bMethodConcrete = newEmptyMethod('aMethodConcrete'); | |
477 var a = addClass(new Class(name: 'A', supertype: objectSuper, procedures: [ | |
478 newEmptyMethod('aMethodAbstract', abstract: true), | |
479 aMethodConcrete | |
480 ])); | |
481 var b = addClass( | |
482 new Class(name: 'B', supertype: a.asThisSupertype, procedures: [ | |
483 newEmptyMethod('aMethodConcrete', abstract: true), | |
484 newEmptyMethod('bMethodAbstract', abstract: true), | |
485 bMethodConcrete | |
486 ])); | |
487 addClass(new Class(name: 'C', supertype: b.asThisSupertype)); | |
488 | |
489 expect(hierarchy.getDispatchTarget(a, new Name('aMethodConcrete')), | |
490 aMethodConcrete); | |
491 // TODO(scheglov) The next two commented statements verify the behavior | |
ahe
2017/05/31 17:33:49
Add colon after ")".
scheglov
2017/05/31 17:53:27
Done.
| |
492 // documented as "If the class is abstract, abstract members are ignored and | |
493 // the dispatch is resolved if the class was not abstract.". Unfortunately | |
494 // the implementation does not follow the documentation. We need to fix | |
495 // either documentation, or implementation. | |
ahe
2017/05/31 17:33:49
Since Fasta uses this method, it would be interest
scheglov
2017/05/31 17:53:28
I hope that Kevin will able to shed some light.
| |
496 // expect(hierarchy.getDispatchTarget(c, new Name('aMethodConcrete')), | |
497 // aMethodConcrete); | |
498 // expect(hierarchy.getDispatchTarget(b, new Name('aMethodConcrete')), | |
499 // aMethodConcrete); | |
500 } | |
501 | |
502 void test_getInterfaceMember_extends() { | |
503 // Create the class hierarchy: | |
504 // | |
505 // class A extends Object { | |
506 // aMethod() {} | |
507 // void set aSetter(_) {} | |
508 // } | |
509 // class B extends A { | |
510 // bMethod() {} | |
511 // void set bSetter(_) {} | |
512 // } | |
513 // class C extends B {} | |
514 var aMethod = newEmptyMethod('aMethod'); | |
515 var aSetter = newEmptySetter('aSetter'); | |
516 var bMethod = newEmptyMethod('bMethod'); | |
517 var bSetter = newEmptySetter('bSetter'); | |
518 var a = addClass(new Class( | |
519 name: 'A', supertype: objectSuper, procedures: [aMethod, aSetter])); | |
520 var b = addClass(new Class( | |
521 name: 'B', | |
522 supertype: a.asThisSupertype, | |
523 procedures: [bMethod, bSetter])); | |
524 var c = addClass(new Class(name: 'C', supertype: b.asThisSupertype)); | |
525 | |
526 var aMethodName = new Name('aMethod'); | |
527 var aSetterName = new Name('aSetter'); | |
528 var bMethodName = new Name('bMethod'); | |
529 var bSetterName = new Name('bSetter'); | |
530 expect(hierarchy.getInterfaceMember(a, aMethodName), aMethod); | |
531 expect(hierarchy.getInterfaceMember(a, bMethodName), isNull); | |
532 expect(hierarchy.getInterfaceMember(a, aSetterName, setter: true), aSetter); | |
533 expect(hierarchy.getInterfaceMember(a, bSetterName, setter: true), isNull); | |
534 expect(hierarchy.getInterfaceMember(b, aMethodName), aMethod); | |
535 expect(hierarchy.getInterfaceMember(b, bMethodName), bMethod); | |
536 expect(hierarchy.getInterfaceMember(b, aSetterName, setter: true), aSetter); | |
537 expect(hierarchy.getInterfaceMember(b, bSetterName, setter: true), bSetter); | |
538 expect(hierarchy.getInterfaceMember(c, aMethodName), aMethod); | |
539 expect(hierarchy.getInterfaceMember(c, bMethodName), bMethod); | |
540 expect(hierarchy.getInterfaceMember(c, aSetterName, setter: true), aSetter); | |
541 expect(hierarchy.getInterfaceMember(c, bSetterName, setter: true), bSetter); | |
542 } | |
543 | |
544 void test_getInterfaceMember_implements() { | |
545 // Create the class hierarchy: | |
546 // | |
547 // class A extends Object { | |
548 // aMethod() {} | |
549 // void set aSetter(_) {} | |
550 // } | |
551 // class B extends Object implements A { | |
552 // bMethod() {} | |
553 // void set bSetter(_) {} | |
554 // } | |
555 // class C extends Object implements B {} | |
556 var aMethod = newEmptyMethod('aMethod'); | |
557 var aSetter = newEmptySetter('aSetter'); | |
558 var bMethod = newEmptyMethod('bMethod'); | |
559 var bSetter = newEmptySetter('bSetter'); | |
560 var a = addClass(new Class( | |
561 name: 'A', supertype: objectSuper, procedures: [aMethod, aSetter])); | |
562 var b = addClass(new Class( | |
563 name: 'B', | |
564 supertype: objectSuper, | |
565 implementedTypes: [a.asThisSupertype], | |
566 procedures: [bMethod, bSetter])); | |
567 var c = addClass(new Class( | |
568 name: 'C', | |
569 supertype: objectSuper, | |
570 implementedTypes: [b.asThisSupertype])); | |
571 | |
572 var aMethodName = new Name('aMethod'); | |
573 var aSetterName = new Name('aSetter'); | |
574 var bMethodName = new Name('bMethod'); | |
575 var bSetterName = new Name('bSetter'); | |
576 expect(hierarchy.getInterfaceMember(a, aMethodName), aMethod); | |
577 expect(hierarchy.getInterfaceMember(a, bMethodName), isNull); | |
578 expect(hierarchy.getInterfaceMember(a, aSetterName, setter: true), aSetter); | |
579 expect(hierarchy.getInterfaceMember(a, bSetterName, setter: true), isNull); | |
580 expect(hierarchy.getInterfaceMember(b, aMethodName), aMethod); | |
581 expect(hierarchy.getInterfaceMember(b, bMethodName), bMethod); | |
582 expect(hierarchy.getInterfaceMember(b, aSetterName, setter: true), aSetter); | |
583 expect(hierarchy.getInterfaceMember(b, bSetterName, setter: true), bSetter); | |
584 expect(hierarchy.getInterfaceMember(c, aMethodName), aMethod); | |
585 expect(hierarchy.getInterfaceMember(c, bMethodName), bMethod); | |
586 expect(hierarchy.getInterfaceMember(c, aSetterName, setter: true), aSetter); | |
587 expect(hierarchy.getInterfaceMember(c, bSetterName, setter: true), bSetter); | |
588 } | |
589 | |
590 void test_getRankedSuperclasses() { | |
591 // Create the class hierarchy: | |
592 // | |
593 // Object | |
594 // | | |
595 // A | |
596 // / \ | |
597 // B C | |
598 // | | | |
599 // | D | |
600 // \ / | |
601 // E | |
ahe
2017/05/31 17:33:49
I'm thinking it might be a good idea to add more c
scheglov
2017/05/31 17:53:27
Sounds good to me.
Anything specific you have in m
ahe
2017/05/31 18:33:06
I'll discuss it with Johnni tomorrow. I can't reme
| |
602 var a = addImplementsClass('A', []); | |
603 var b = addImplementsClass('B', [a]); | |
604 var c = addImplementsClass('C', [a]); | |
605 var d = addImplementsClass('D', [c]); | |
606 var e = addImplementsClass('E', [b, d]); | |
607 | |
608 expect(hierarchy.getRankedSuperclasses(a), [a, objectClass]); | |
609 expect(hierarchy.getRankedSuperclasses(b), [b, a, objectClass]); | |
610 expect(hierarchy.getRankedSuperclasses(c), [c, a, objectClass]); | |
611 expect(hierarchy.getRankedSuperclasses(d), [d, c, a, objectClass]); | |
612 if (hierarchy.getClassIndex(b) < hierarchy.getClassIndex(c)) { | |
613 expect(hierarchy.getRankedSuperclasses(e), [e, d, b, c, a, objectClass]); | |
614 } else { | |
615 expect(hierarchy.getRankedSuperclasses(e), [e, d, c, b, a, objectClass]); | |
616 } | |
617 } | |
618 | |
619 void test_getTypeAsInstanceOf_generic_extends() { | |
620 // Create the class hierarchy: | |
621 // | |
622 // class A<T, U> extends Object {} | |
623 // class B<T> extends A<T, bool> {} | |
624 var int = coreTypes.intClass.rawType; | |
625 var bool = coreTypes.boolClass.rawType; | |
626 | |
627 var a = addGenericClass('A', ['T', 'U']); | |
628 | |
629 var bT = new TypeParameter('T', objectClass.rawType); | |
630 var bTT = new TypeParameterType(bT); | |
631 var b = addClass(new Class( | |
632 name: 'B', | |
633 typeParameters: [bT], | |
634 supertype: new Supertype(a, [bTT, bool]))); | |
635 | |
636 var b_int = new InterfaceType(b, [int]); | |
637 expect(hierarchy.getTypeAsInstanceOf(b_int, a), | |
638 new InterfaceType(a, [int, bool])); | |
639 expect(hierarchy.getTypeAsInstanceOf(b_int, objectClass), | |
640 new InterfaceType(objectClass)); | |
641 } | |
642 | |
643 void test_rootClass() { | |
644 addClass(new Class(name: 'A', supertype: objectSuper)); | |
645 expect(hierarchy.rootClass, objectClass); | |
646 } | |
647 | |
648 void _assertOverridePairs(Class class_, List<String> expected) { | |
649 List<String> overrideDescriptions = []; | |
650 hierarchy.forEachOverridePair(class_, | |
651 (Member declaredMember, Member interfaceMember, bool isSetter) { | |
652 var desc = '$declaredMember overrides $interfaceMember'; | |
653 overrideDescriptions.add(desc); | |
654 }); | |
655 expect(overrideDescriptions, unorderedEquals(expected)); | |
656 } | |
657 | |
658 /// Create a new [_ClassHierarchyTest] using [newInstance] and run [test] | |
659 /// with the given [description] and [doRun] with the test instance. | |
660 static void _runTest(_ClassHierarchyTest newInstance(), String description, | |
661 void doRun(_ClassHierarchyTest instance)) { | |
662 test(description, () { | |
663 var instance = newInstance(); | |
664 instance.setUp(); | |
665 try { | |
666 doRun(instance); | |
667 } finally { | |
668 instance.tearDown(); | |
669 } | |
670 }); | |
671 } | |
672 | |
673 /// Run all tests declared in [_ClassHierarchyTest]. This method must be | |
674 /// updated when a new `test_XYZ` method is added, renamed or deleted. | |
675 static void _runTests(_ClassHierarchyTest newInstance()) { | |
scheglov
2017/05/31 17:53:27
Given that this is considered as not an optimal so
ahe
2017/05/31 18:33:06
I agree.
| |
676 _runTest(newInstance, 'test_forEachOverridePair_overrideSupertype', | |
677 (i) => i.test_forEachOverridePair_overrideSupertype()); | |
678 _runTest(newInstance, 'test_getClassAsInstanceOf_generic_extends', | |
679 (i) => i.test_getClassAsInstanceOf_generic_extends()); | |
680 _runTest(newInstance, 'test_getClassAsInstanceOf_generic_implements', | |
681 (i) => i.test_getClassAsInstanceOf_generic_implements()); | |
682 _runTest(newInstance, 'test_getClassAsInstanceOf_generic_with', | |
683 (i) => i.test_getClassAsInstanceOf_generic_with()); | |
684 _runTest(newInstance, 'test_getClassAsInstanceOf_notGeneric_extends', | |
685 (i) => i.test_getClassAsInstanceOf_notGeneric_extends()); | |
686 _runTest(newInstance, 'test_getClassAsInstanceOf_notGeneric_implements', | |
687 (i) => i.test_getClassAsInstanceOf_notGeneric_implements()); | |
688 _runTest(newInstance, 'test_getClassAsInstanceOf_notGeneric_with', | |
689 (i) => i.test_getClassAsInstanceOf_notGeneric_with()); | |
690 _runTest(newInstance, 'test_getClassDepth', (i) => i.test_getClassDepth()); | |
691 _runTest(newInstance, 'test_getClassicLeastUpperBound_generic', | |
692 (i) => i.test_getClassicLeastUpperBound_generic()); | |
693 _runTest(newInstance, 'test_getClassicLeastUpperBound_nonGeneric', | |
694 (i) => i.test_getClassicLeastUpperBound_nonGeneric()); | |
695 _runTest(newInstance, 'test_getDispatchTarget', | |
696 (i) => i.test_getDispatchTarget()); | |
697 _runTest(newInstance, 'test_getDispatchTarget_abstract', | |
698 (i) => i.test_getDispatchTarget_abstract()); | |
699 _runTest(newInstance, 'test_getInterfaceMember_extends', | |
700 (i) => i.test_getInterfaceMember_extends()); | |
701 _runTest(newInstance, 'test_getInterfaceMember_implements', | |
702 (i) => i.test_getInterfaceMember_implements()); | |
703 _runTest(newInstance, 'test_getRankedSuperclasses', | |
704 (i) => i.test_getRankedSuperclasses()); | |
705 _runTest(newInstance, 'test_getTypeAsInstanceOf_generic_extends', | |
706 (i) => i.test_getTypeAsInstanceOf_generic_extends()); | |
707 _runTest(newInstance, 'test_rootClass', (i) => i.test_rootClass()); | |
708 } | |
709 } | |
OLD | NEW |