| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library smoke.test.codegen.recorder_test; |
| |
| import 'package:analyzer/src/generated/element.dart'; |
| import 'package:smoke/codegen/generator.dart'; |
| import 'package:smoke/codegen/recorder.dart'; |
| import 'package:unittest/unittest.dart'; |
| |
| import 'common.dart' show checkResults; |
| import 'testing_resolver_utils.dart' show initAnalyzer; |
| |
| main() { |
| var provider = initAnalyzer(_SOURCES); |
| var generator; |
| var recorder; |
| setUp(() { |
| generator = new SmokeCodeGenerator(); |
| recorder = new Recorder(generator, resolveImportUrl); |
| }); |
| |
| group('parents', () { |
| test('simple subclassing', () { |
| var lib = provider.libraryFor('/a.dart'); |
| recorder.lookupParent(lib.getType('A')); |
| recorder.lookupParent(lib.getType('C')); |
| |
| checkResults(generator, |
| imports: [ |
| "import '/a.dart' as smoke_0;", |
| "import '/b.dart' as smoke_1;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.A: smoke_1.B,\n' |
| ' smoke_0.C: smoke_0.A,\n' |
| ' }));\n'); |
| }); |
| |
| test('single mixin', () { |
| var lib = provider.libraryFor('/a.dart'); |
| recorder.lookupParent(lib.getType('E')); |
| |
| checkResults(generator, |
| imports: [ |
| "import '/a.dart' as smoke_0;", |
| ], |
| topLevel: 'abstract class _M0 {} // A & D1\n', |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.E: _M0,\n' |
| ' _M0: smoke_0.A,\n' |
| ' }));\n'); |
| }); |
| |
| test('multiple mixins', () { |
| var lib = provider.libraryFor('/a.dart'); |
| recorder.lookupParent(lib.getType('F')); |
| |
| checkResults(generator, |
| imports: [ |
| "import '/a.dart' as smoke_0;", |
| ], |
| topLevel: |
| 'abstract class _M0 {} // A & D1\n' |
| 'abstract class _M1 {} // _M0 & D2\n' |
| 'abstract class _M2 {} // _M1 & D3\n', |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.F: _M2,\n' |
| ' _M0: smoke_0.A,\n' |
| ' _M1: _M0,\n' |
| ' _M2: _M1,\n' |
| ' }));\n'); |
| }); |
| |
| test('same as common_test', () { |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.lookupParent(lib.getType('Annot')); |
| recorder.lookupParent(lib.getType('AnnotB')); |
| recorder.lookupParent(lib.getType('A')); |
| recorder.lookupParent(lib.getType('B')); |
| recorder.lookupParent(lib.getType('C')); |
| recorder.lookupParent(lib.getType('D')); |
| recorder.lookupParent(lib.getType('E')); |
| recorder.lookupParent(lib.getType('E2')); |
| recorder.lookupParent(lib.getType('F')); |
| recorder.lookupParent(lib.getType('F2')); |
| recorder.lookupParent(lib.getType('G')); |
| recorder.lookupParent(lib.getType('H')); |
| var coreLib = lib.visibleLibraries.firstWhere( |
| (l) => l.displayName == 'dart.core'); |
| recorder.lookupParent(coreLib.getType('int')); |
| recorder.lookupParent(coreLib.getType('num')); |
| |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| topLevel: |
| 'abstract class _M0 {} // C & A\n', |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.AnnotB: smoke_0.Annot,\n' |
| ' smoke_0.D: _M0,\n' |
| ' smoke_0.E2: smoke_0.E,\n' |
| ' smoke_0.F2: smoke_0.F,\n' |
| ' smoke_0.H: smoke_0.G,\n' |
| ' int: num,\n' |
| ' _M0: smoke_0.C,\n' |
| ' }));\n'); |
| }); |
| }); |
| |
| group('lookup member', () { |
| var lib; |
| setUp(() { |
| lib = provider.libraryFor('/common.dart'); |
| }); |
| |
| test('missing declaration', () { |
| recorder.lookupMember(lib.getType('A'), 'q'); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: const {},\n' |
| ' }));\n'); |
| }); |
| |
| test('field declaration', () { |
| recorder.lookupMember(lib.getType('A'), 'i'); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #i: const Declaration(#i, int),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('property declaration', () { |
| recorder.lookupMember(lib.getType('A'), 'j2'); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #j2: const Declaration(#j2, int, kind: PROPERTY),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('method declaration', () { |
| recorder.lookupMember(lib.getType('A'), 'inc0'); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #inc0: const Declaration(#inc0, Function, kind: METHOD),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('inherited field - not recursive', () { |
| recorder.lookupMember(lib.getType('D'), 'i'); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.D: const {},\n' |
| ' }));\n'); |
| }); |
| |
| test('inherited field - recursive', () { |
| recorder.lookupMember(lib.getType('D'), 'i', recursive: true); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| topLevel: 'abstract class _M0 {} // C & A\n', |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.D: _M0,\n' |
| ' _M0: smoke_0.C,\n' |
| ' },\n' |
| ' declarations: {\n' |
| ' smoke_0.D: const {},\n' |
| ' _M0: {\n' |
| ' #i: const Declaration(#i, int),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| }); |
| |
| group('query', () { |
| test('default query', () { |
| var options = new QueryOptions(); |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.runQuery(lib.getType('A'), options); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #i: const Declaration(#i, int),\n' |
| ' #j: const Declaration(#j, int),\n' |
| ' #j2: const Declaration(#j2, int, kind: PROPERTY),\n' |
| ' },\n' |
| ' }));\n'); |
| |
| }); |
| |
| test('only fields', () { |
| var options = new QueryOptions(includeProperties: false); |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.runQuery(lib.getType('A'), options); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #i: const Declaration(#i, int),\n' |
| ' #j: const Declaration(#j, int),\n' |
| ' },\n' |
| ' }));\n'); |
| |
| }); |
| |
| test('only properties', () { |
| var options = new QueryOptions(includeFields: false); |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.runQuery(lib.getType('A'), options); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #j2: const Declaration(#j2, int, kind: PROPERTY),\n' |
| ' },\n' |
| ' }));\n'); |
| |
| }); |
| |
| test('fields, properties, and and methods', () { |
| var options = new QueryOptions(includeMethods: true); |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.runQuery(lib.getType('A'), options); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.A: {\n' |
| ' #i: const Declaration(#i, int),\n' |
| ' #inc0: const Declaration(#inc0, Function, kind: METHOD),\n' |
| ' #inc1: const Declaration(#inc1, Function, kind: METHOD),\n' |
| ' #inc2: const Declaration(#inc2, Function, kind: METHOD),\n' |
| ' #j: const Declaration(#j, int),\n' |
| ' #j2: const Declaration(#j2, int, kind: PROPERTY),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('exclude inherited', () { |
| var options = new QueryOptions(includeInherited: false); |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.runQuery(lib.getType('D'), options); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' declarations: {\n' |
| ' smoke_0.D: {\n' |
| ' #i2: const Declaration(#i2, int, kind: PROPERTY, ' |
| 'isFinal: true),\n' |
| ' #x2: const Declaration(#x2, int, kind: PROPERTY, ' |
| 'isFinal: true),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('include inherited', () { |
| var options = new QueryOptions(includeInherited: true); |
| var lib = provider.libraryFor('/common.dart'); |
| recorder.runQuery(lib.getType('D'), options); |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| topLevel: 'abstract class _M0 {} // C & A\n', |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.D: _M0,\n' |
| ' _M0: smoke_0.C,\n' |
| ' },\n' |
| ' declarations: {\n' |
| ' smoke_0.C: {\n' |
| ' #b: const Declaration(#b, smoke_0.B),\n' |
| ' #x: const Declaration(#x, int),\n' |
| ' #y: const Declaration(#y, String),\n' |
| ' },\n' |
| ' smoke_0.D: {\n' |
| ' #i2: const Declaration(#i2, int, kind: PROPERTY, ' |
| 'isFinal: true),\n' |
| ' #x2: const Declaration(#x2, int, kind: PROPERTY, ' |
| 'isFinal: true),\n' |
| ' },\n' |
| ' _M0: {\n' |
| ' #i: const Declaration(#i, int),\n' |
| ' #j: const Declaration(#j, int),\n' |
| ' #j2: const Declaration(#j2, int, kind: PROPERTY),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('exact annotation', () { |
| var lib = provider.libraryFor('/common.dart'); |
| var vars = lib.definingCompilationUnit.topLevelVariables; |
| expect(vars[0].name, 'a1'); |
| var options = new QueryOptions(includeInherited: true, |
| withAnnotations: [vars[0]]); |
| recorder.runQuery(lib.getType('H'), options); |
| final annot = 'annotations: const [smoke_0.a1]'; |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.H: smoke_0.G,\n' |
| ' },\n' |
| ' declarations: {\n' |
| ' smoke_0.G: {\n' |
| ' #b: const Declaration(#b, int, $annot),\n' |
| ' },\n' |
| ' smoke_0.H: {\n' |
| ' #f: const Declaration(#f, int, $annot),\n' |
| ' #g: const Declaration(#g, int, $annot),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| |
| test('type annotation', () { |
| var lib = provider.libraryFor('/common.dart'); |
| var options = new QueryOptions(includeInherited: true, |
| withAnnotations: [lib.getType('Annot')]); |
| recorder.runQuery(lib.getType('H'), options); |
| final a1Annot = 'annotations: const [smoke_0.a1]'; |
| final a3Annot = 'annotations: const [smoke_0.a3]'; |
| final exprAnnot = 'annotations: const [const smoke_0.Annot(1)]'; |
| checkResults(generator, |
| imports: [ |
| "import '/common.dart' as smoke_0;", |
| ], |
| initCall: |
| 'useGeneratedCode(new StaticConfiguration(\n' |
| ' checkedMode: false,\n' |
| ' parents: {\n' |
| ' smoke_0.H: smoke_0.G,\n' |
| ' },\n' |
| ' declarations: {\n' |
| ' smoke_0.G: {\n' |
| ' #b: const Declaration(#b, int, $a1Annot),\n' |
| ' },\n' |
| ' smoke_0.H: {\n' |
| ' #f: const Declaration(#f, int, $a1Annot),\n' |
| ' #g: const Declaration(#g, int, $a1Annot),\n' |
| ' #i: const Declaration(#i, int, $a3Annot),\n' |
| ' #j: const Declaration(#j, int, $exprAnnot),\n' |
| ' },\n' |
| ' }));\n'); |
| }); |
| }); |
| } |
| |
| const _SOURCES = const { |
| '/a.dart': ''' |
| library a; |
| import '/b.dart'; |
| |
| class Annot { const Annot(); } |
| const annot = const Annot(); |
| |
| class A extends B {} |
| class C extends A {} |
| class D1 { |
| int d1; |
| } |
| class D2 { |
| int d2; |
| } |
| class D3 { |
| int d3; |
| } |
| class E extends A with D1 { |
| int e1; |
| } |
| class F extends A with D1, D2, D3 { |
| int f1; |
| } |
| ''', |
| |
| '/b.dart': ''' |
| library b; |
| |
| class B {} |
| ''', |
| '/common.dart': ''' |
| library common; |
| |
| class A { |
| int i = 42; |
| int j = 44; |
| int get j2 => j; |
| void set j2(int v) { j = v; } |
| void inc0() { i++; } |
| void inc1(int v) { i = i + (v == null ? -10 : v); } |
| void inc2([int v]) { i = i + (v == null ? -10 : v); } |
| } |
| |
| class B { |
| final int f = 3; |
| int _w; |
| int get w => _w; |
| set w(int v) { _w = v; } |
| |
| String z; |
| A a; |
| |
| B(this._w, this.z, this.a); |
| } |
| |
| class C { |
| int x; |
| String y; |
| B b; |
| |
| inc(int n) { |
| x = x + n; |
| } |
| dec(int n) { |
| x = x - n; |
| } |
| |
| C(this.x, this.y, this.b); |
| } |
| |
| |
| class D extends C with A { |
| int get x2 => x; |
| int get i2 => i; |
| |
| D(x, y, b) : super(x, y, b); |
| } |
| |
| class E { |
| set x(int v) { } |
| int get y => 1; |
| |
| noSuchMethod(i) => y; |
| } |
| |
| class E2 extends E {} |
| |
| class F { |
| static int staticMethod(A a) => a.i; |
| } |
| |
| class F2 extends F {} |
| |
| class Annot { const Annot(int ignore); } |
| class AnnotB extends Annot { const AnnotB(); } |
| const a1 = const Annot(0); |
| const a2 = 32; |
| const a3 = const AnnotB(); |
| |
| |
| class G { |
| int a; |
| @a1 int b; |
| int c; |
| @a2 int d; |
| } |
| |
| class H extends G { |
| int e; |
| @a1 int f; |
| @a1 int g; |
| @a2 int h; |
| @a3 int i; |
| @Annot(1) int j; |
| } |
| ''' |
| }; |
| |
| resolveImportUrl(LibraryElement lib) => |
| lib.isDartCore ? 'dart:core' : '/${lib.displayName}.dart'; |