blob: 33698c90df721acc1ce5d949c9d196ca330a980a [file] [log] [blame]
// 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';