5285faad67
add isConst to constructors, add const and factory keywords to augmentations, part of https://github.com/dart-lang/sdk/issues/56516 Change-Id: I424031e22636678da5c9c428099100bfac748daf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/382662 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Jake Macdonald <jakemac@google.com>
1284 lines
57 KiB
Dart
1284 lines
57 KiB
Dart
// Copyright (c) 2021, 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.
|
|
|
|
import 'dart:io';
|
|
import 'dart:isolate';
|
|
|
|
import 'package:_macros/src/api.dart';
|
|
import 'package:_macros/src/bootstrap.dart';
|
|
import 'package:_macros/src/executor.dart';
|
|
import 'package:_macros/src/executor/isolated_executor.dart'
|
|
as isolated_executor;
|
|
import 'package:_macros/src/executor/process_executor.dart' as process_executor
|
|
show start;
|
|
import 'package:_macros/src/executor/process_executor.dart' hide start;
|
|
import 'package:_macros/src/executor/serialization.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../util.dart';
|
|
|
|
void main() {
|
|
late MacroExecutor executor;
|
|
late File kernelOutputFile;
|
|
final danglingTaskMacroName = 'DanglingTaskMacro';
|
|
final danglingTimerMacroName = 'DanglingTimerMacro';
|
|
final danglingPeriodicTimerMacroName = 'DanglingPeriodicTimerMacro';
|
|
final diagnosticMacroName = 'DiagnosticMacro';
|
|
final simpleMacroName = 'SimpleMacro';
|
|
late MacroInstanceIdentifier danglingTaskMacroId;
|
|
late MacroInstanceIdentifier danglingTimerMacroId;
|
|
late MacroInstanceIdentifier danglingPeriodicTimerMacroId;
|
|
late MacroInstanceIdentifier diagnosticMacroInstanceId;
|
|
late MacroInstanceIdentifier simpleMacroInstanceId;
|
|
late Uri macroUri;
|
|
late File simpleMacroFile;
|
|
late Directory tmpDir;
|
|
|
|
for (var executorKind in [
|
|
'Isolated',
|
|
'ProcessSocket',
|
|
'ProcessStdio',
|
|
]) {
|
|
group('$executorKind executor', () {
|
|
for (var mode in [SerializationMode.byteData, SerializationMode.json]) {
|
|
group('$mode', () {
|
|
setUpAll(() async {
|
|
simpleMacroFile =
|
|
File(Platform.script.resolve('simple_macro.dart').toFilePath());
|
|
tmpDir = Directory.systemTemp.createTempSync('executor_test');
|
|
macroUri = simpleMacroFile.absolute.uri;
|
|
|
|
var bootstrapContent = bootstrapMacroIsolate({
|
|
macroUri.toString(): {
|
|
simpleMacroName: ['', 'named'],
|
|
danglingTaskMacroName: [''],
|
|
danglingTimerMacroName: [''],
|
|
danglingPeriodicTimerMacroName: [''],
|
|
diagnosticMacroName: [''],
|
|
}
|
|
}, mode);
|
|
var bootstrapFile =
|
|
File(tmpDir.uri.resolve('main.dart').toFilePath())
|
|
..writeAsStringSync(bootstrapContent);
|
|
kernelOutputFile =
|
|
File(tmpDir.uri.resolve('main.dart.dill').toFilePath());
|
|
var packageConfigPath = (await Isolate.packageConfig)!.toFilePath();
|
|
var buildSnapshotResult =
|
|
await Process.run(Platform.resolvedExecutable, [
|
|
if (executorKind == 'Isolated') ...[
|
|
'--snapshot=${kernelOutputFile.uri.toFilePath()}',
|
|
'--snapshot-kind=kernel',
|
|
] else ...[
|
|
'compile',
|
|
'exe',
|
|
'-o',
|
|
kernelOutputFile.uri.toFilePath(),
|
|
],
|
|
'--packages=$packageConfigPath',
|
|
bootstrapFile.uri.toFilePath(),
|
|
]);
|
|
expect(buildSnapshotResult.exitCode, 0,
|
|
reason: 'stdout: ${buildSnapshotResult.stdout}\n'
|
|
'stderr: ${buildSnapshotResult.stderr}');
|
|
|
|
executor = executorKind == 'Isolated'
|
|
? await isolated_executor.start(mode, kernelOutputFile.uri)
|
|
: executorKind == 'ProcessSocket'
|
|
? await process_executor.start(mode,
|
|
CommunicationChannel.socket, kernelOutputFile.path)
|
|
: await process_executor.start(mode,
|
|
CommunicationChannel.stdio, kernelOutputFile.path);
|
|
|
|
simpleMacroInstanceId = await executor.instantiateMacro(
|
|
macroUri, simpleMacroName, '', Arguments([], {}));
|
|
expect(simpleMacroInstanceId, isNotNull,
|
|
reason: 'Can create an instance with no arguments.');
|
|
executor.disposeMacro(simpleMacroInstanceId);
|
|
|
|
simpleMacroInstanceId = await executor.instantiateMacro(
|
|
macroUri, simpleMacroName, '', Arguments([IntArgument(1)], {}));
|
|
expect(simpleMacroInstanceId, isNotNull,
|
|
reason: 'Can create an instance with positional arguments.');
|
|
executor.disposeMacro(simpleMacroInstanceId);
|
|
|
|
simpleMacroInstanceId = await executor.instantiateMacro(
|
|
macroUri,
|
|
simpleMacroName,
|
|
'named',
|
|
Arguments([], {
|
|
'myBool': BoolArgument(true),
|
|
'myDouble': DoubleArgument(1.0),
|
|
'myInt': IntArgument(1),
|
|
'myList': ListArgument([
|
|
IntArgument(1),
|
|
IntArgument(2),
|
|
IntArgument(3),
|
|
], [
|
|
ArgumentKind.nullable,
|
|
ArgumentKind.int
|
|
]),
|
|
'mySet': SetArgument([
|
|
BoolArgument(true),
|
|
NullArgument(),
|
|
MapArgument({StringArgument('a'): DoubleArgument(1.0)},
|
|
[ArgumentKind.string, ArgumentKind.double]),
|
|
], [
|
|
ArgumentKind.nullable,
|
|
ArgumentKind.object,
|
|
]),
|
|
'myMap': MapArgument({
|
|
StringArgument('x'): IntArgument(1),
|
|
}, [
|
|
ArgumentKind.string,
|
|
ArgumentKind.int
|
|
]),
|
|
'myString': StringArgument('a'),
|
|
}));
|
|
expect(simpleMacroInstanceId, isNotNull,
|
|
reason: 'Can create an instance with named arguments.');
|
|
|
|
danglingTaskMacroId = await executor.instantiateMacro(
|
|
macroUri, danglingTaskMacroName, '', Arguments([], {}));
|
|
expect(danglingTaskMacroId, isNotNull);
|
|
|
|
danglingTimerMacroId = await executor.instantiateMacro(
|
|
macroUri, danglingTimerMacroName, '', Arguments([], {}));
|
|
expect(danglingTimerMacroId, isNotNull);
|
|
|
|
danglingPeriodicTimerMacroId = await executor.instantiateMacro(
|
|
macroUri,
|
|
danglingPeriodicTimerMacroName,
|
|
'',
|
|
Arguments([], {}));
|
|
expect(danglingPeriodicTimerMacroId, isNotNull);
|
|
|
|
diagnosticMacroInstanceId = await executor.instantiateMacro(
|
|
macroUri, diagnosticMacroName, '', Arguments([], {}));
|
|
expect(diagnosticMacroInstanceId, isNotNull);
|
|
});
|
|
|
|
tearDownAll(() async {
|
|
executor.disposeMacro(diagnosticMacroInstanceId);
|
|
executor.disposeMacro(danglingTaskMacroId);
|
|
executor.disposeMacro(danglingTimerMacroId);
|
|
executor.disposeMacro(danglingPeriodicTimerMacroId);
|
|
executor.disposeMacro(simpleMacroInstanceId);
|
|
await expectLater(
|
|
() => executor.executeTypesPhase(simpleMacroInstanceId,
|
|
Fixtures.myFunction, TestTypePhaseIntrospector()),
|
|
throwsA(isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('Unrecognized macro instance'))),
|
|
reason: 'Should be able to dispose macro instances',
|
|
skip: 'https://github.com/dart-lang/sdk/issues/55992');
|
|
if (tmpDir.existsSync()) {
|
|
try {
|
|
// Fails flakily on windows if a process still has the file open
|
|
tmpDir.deleteSync(recursive: true);
|
|
} catch (_) {}
|
|
}
|
|
await executor.close();
|
|
});
|
|
|
|
group('run macros', () {
|
|
group('in the types phase', () {
|
|
test('on functions', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myFunction,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('class GeneratedByMyFunction {}'));
|
|
});
|
|
|
|
test('on methods', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myMethod,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('class GeneratedByMyMethod {}'));
|
|
});
|
|
|
|
test('on getters', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariableGetter,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class GeneratedByMyVariableGetter {}'));
|
|
});
|
|
|
|
test('on setters', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariableSetter,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class GeneratedByMyVariableSetter {}'));
|
|
});
|
|
|
|
test('on variables', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariable,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class GeneratedBy_myVariable {}'));
|
|
});
|
|
|
|
test('on constructors', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myConstructor,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class GeneratedByMyConstructor {}'));
|
|
});
|
|
|
|
test('on fields', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myField,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('class GeneratedByMyField {}'));
|
|
});
|
|
|
|
test('on classes', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myClass,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(
|
|
result
|
|
.extendsTypeAugmentations[Fixtures.myClass.identifier]!
|
|
.debugString()
|
|
.toString(),
|
|
equals(Fixtures.mySuperclass.identifier.name));
|
|
expect(
|
|
result.interfaceAugmentations.mapValuesToDebugCodeString(),
|
|
equals({
|
|
Fixtures.myClass.identifier: ['HasX'],
|
|
}));
|
|
expect(
|
|
result.mixinAugmentations.mapValuesToDebugCodeString(),
|
|
equals({
|
|
Fixtures.myClass.identifier: ['GetX'],
|
|
}));
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.mapToDebugCodeString(),
|
|
unorderedEquals([
|
|
equalsIgnoringWhitespace(
|
|
'class MyClassBuilder implements Builder<MyClass> '
|
|
'{}'),
|
|
equalsIgnoringWhitespace('''mixin GetX implements HasX {
|
|
int get x => 1;
|
|
}'''),
|
|
equalsIgnoringWhitespace(
|
|
'''abstract interface class HasX {
|
|
int get x;
|
|
}'''),
|
|
]));
|
|
});
|
|
|
|
test('on enums', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myEnum,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('class GeneratedByMyEnum {}'));
|
|
});
|
|
|
|
test('on enum values', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myEnumValues.first,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('class GeneratedByMyEnum_A {}'));
|
|
});
|
|
|
|
test('on extensions', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myExtension,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('class MyExtensionOnMyClass {}'));
|
|
});
|
|
|
|
test('on extension types', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myExtensionType,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class MyExtensionTypeOnMyClass {}'));
|
|
});
|
|
|
|
test('on type aliases', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myTypeAlias,
|
|
TestTypePhaseIntrospector(),
|
|
);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class MyTypeAliasAliasedTypeMyClass {}',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('on mixins', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myMixin,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'class GeneratedByMyMixinOnMyClass {}'));
|
|
});
|
|
|
|
test('on libraries', () async {
|
|
var result = await executor.executeTypesPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.library,
|
|
TestTypePhaseIntrospector(),
|
|
);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
class LibraryInfo {
|
|
final Uri uri;
|
|
final String languageVersion;
|
|
final List<Type> definedTypes;
|
|
const LibraryInfo(this.uri, this.languageVersion, this.definedTypes);
|
|
}
|
|
'''),
|
|
);
|
|
});
|
|
|
|
test('Cannot leave dangling tasks', () async {
|
|
expect(
|
|
() => executor.executeTypesPhase(danglingTaskMacroId,
|
|
Fixtures.library, TestTypePhaseIntrospector()),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 async tasks still pending')),
|
|
));
|
|
});
|
|
|
|
test('Cannot leave dangling timers', () async {
|
|
expect(
|
|
() => executor.executeTypesPhase(danglingTimerMacroId,
|
|
Fixtures.library, TestTypePhaseIntrospector()),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 active timers')),
|
|
));
|
|
|
|
expect(
|
|
() => executor.executeTypesPhase(
|
|
danglingPeriodicTimerMacroId,
|
|
Fixtures.library,
|
|
TestTypePhaseIntrospector()),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 active timers')),
|
|
));
|
|
});
|
|
});
|
|
|
|
group('in the declaration phase', () {
|
|
test('on functions', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myFunction,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'String delegateMyFunction() => myFunction();'));
|
|
});
|
|
|
|
test('on methods', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myMethod,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'(String, bool? hello, {String world}) '
|
|
'delegateMemberMyMethod() => myMethod();'));
|
|
});
|
|
|
|
test('on constructors', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myConstructor,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result
|
|
.typeAugmentations[Fixtures.myConstructor.definingType]!
|
|
.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
factory MyClass.myConstructorDelegate() => MyClass.myConstructor();
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on getters', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariableGetter,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
String get delegateMyVariable => myVariable;'''));
|
|
});
|
|
|
|
test('on setters', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariableSetter,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
void set delegateMyVariable(String value) => myVariable = value;'''));
|
|
});
|
|
|
|
test('on variables', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariable,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
/*inferred*/String get delegate_myVariable => _myVariable;'''));
|
|
});
|
|
|
|
test('on fields', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myField,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result.typeAugmentations[Fixtures.myField.definingType]!
|
|
.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
String get delegateMyField => myField;
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on classes', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myClass,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result
|
|
.typeAugmentations[Fixtures.myClass.identifier]!.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
static const List<String> fieldNames = ['myField',];
|
|
'''));
|
|
});
|
|
|
|
test('on enums', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myEnum,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result.typeAugmentations[Fixtures.myEnum.identifier]!.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
static const List<String> valuesByName = {'a': a};
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on enum values', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myEnumValues.first,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result.typeAugmentations[Fixtures.myEnum.identifier]!.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
MyEnum aToString() => a.toString();
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on extensions', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myExtension,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result.typeAugmentations[Fixtures.myExtension.identifier]!
|
|
.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
List<String> get onTypeFieldNames;
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on extension types', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myExtensionType,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result
|
|
.typeAugmentations[Fixtures.myExtensionType.identifier]!
|
|
.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
List<String> get onTypeFieldNames;
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on type aliases', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myTypeAlias,
|
|
Fixtures.testDeclarationPhaseIntrospector,
|
|
);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.libraryAugmentations, hasLength(1));
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace(
|
|
'List<String> get aliasedTypeFieldNames;',
|
|
),
|
|
);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on mixins', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myMixin,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, hasLength(1));
|
|
expect(
|
|
result
|
|
.typeAugmentations[Fixtures.myMixin.identifier]!.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace('''
|
|
static const List<String> methodNames = ['myMixinMethod',];
|
|
'''));
|
|
expect(result.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on libraries', () async {
|
|
var result = await executor.executeDeclarationsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.library,
|
|
Fixtures.testDeclarationPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('final LibraryInfo library;'),
|
|
);
|
|
});
|
|
|
|
test('Cannot leave dangling tasks', () async {
|
|
expect(
|
|
() => executor.executeDeclarationsPhase(
|
|
danglingTaskMacroId,
|
|
Fixtures.library,
|
|
Fixtures.testDeclarationPhaseIntrospector),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 async tasks still pending')),
|
|
));
|
|
});
|
|
|
|
test('Cannot leave dangling timers', () async {
|
|
expect(
|
|
() => executor.executeDeclarationsPhase(
|
|
danglingTimerMacroId,
|
|
Fixtures.library,
|
|
Fixtures.testDeclarationPhaseIntrospector),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 active timers')),
|
|
));
|
|
|
|
expect(
|
|
() => executor.executeDeclarationsPhase(
|
|
danglingPeriodicTimerMacroId,
|
|
Fixtures.library,
|
|
Fixtures.testDeclarationPhaseIntrospector),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 active timers')),
|
|
));
|
|
});
|
|
});
|
|
|
|
group('in the definition phase', () {
|
|
test('on functions', () async {
|
|
var result = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myFunction,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
// A comment!
|
|
augment String myFunction() {
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: String');
|
|
return augmented();
|
|
}'''));
|
|
});
|
|
|
|
test('on methods', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myMethod,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
var augmentationStrings = definitionResult
|
|
.typeAugmentations[Fixtures.myMethod.definingType]!
|
|
.mapToDebugCodeString();
|
|
expect(augmentationStrings,
|
|
unorderedEquals(methodDefinitionMatchers));
|
|
expect(definitionResult.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on regular constructors', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myConstructor,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
expect(
|
|
definitionResult
|
|
.typeAugmentations[Fixtures.myConstructor.definingType]!
|
|
.first
|
|
.debugString()
|
|
.toString(),
|
|
constructorDefinitionMatcher);
|
|
expect(definitionResult.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on factory constructors', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myFactoryConstructor,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
expect(
|
|
definitionResult
|
|
.typeAugmentations[
|
|
Fixtures.myFactoryConstructor.definingType]!
|
|
.first
|
|
.debugString()
|
|
.toString(),
|
|
factoryConstructorDefinitionMatcher);
|
|
expect(definitionResult.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on const constructors', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myConstConstructor,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
expect(
|
|
definitionResult
|
|
.typeAugmentations[
|
|
Fixtures.myConstConstructor.definingType]!
|
|
.first
|
|
.debugString()
|
|
.toString(),
|
|
constConstructorDefinitionMatcher);
|
|
expect(definitionResult.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on getters', () async {
|
|
var result = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariableGetter,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
// A comment!
|
|
augment String get myVariable {
|
|
print('isExternal: false');
|
|
print('isGetter: true');
|
|
print('isSetter: false');
|
|
print('returnType: String');
|
|
return augmented;
|
|
}'''));
|
|
});
|
|
|
|
test('on setters', () async {
|
|
var result = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariableSetter,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
// A comment!
|
|
augment void set myVariable(String value, ) {
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: true');
|
|
print('returnType: void');
|
|
print('positionalParam: String value');
|
|
return augmented = value;
|
|
}'''));
|
|
});
|
|
|
|
test('on variables', () async {
|
|
var result = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myVariable,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.mapToDebugCodeString(),
|
|
unorderedEquals([
|
|
equalsIgnoringWhitespace('''
|
|
augment /*inferred*/String get _myVariable {
|
|
print('parentClass: ');
|
|
print('isExternal: false');
|
|
print('isFinal: true');
|
|
print('isLate: false');
|
|
return augmented;
|
|
}'''),
|
|
equalsIgnoringWhitespace('''
|
|
augment set _myVariable(/*inferred*/String value) {
|
|
augmented = value;
|
|
}'''),
|
|
equalsIgnoringWhitespace('''
|
|
augment final /*inferred*/String _myVariable = 'new initial value' + augmented;
|
|
'''),
|
|
]));
|
|
});
|
|
|
|
test('on fields', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myField,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
expect(
|
|
definitionResult
|
|
.typeAugmentations[Fixtures.myField.definingType]!
|
|
.mapToDebugCodeString(),
|
|
unorderedEquals(fieldDefinitionMatchers));
|
|
expect(definitionResult.libraryAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on classes', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myClass,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
var augmentationStrings = definitionResult
|
|
.typeAugmentations[Fixtures.myClass.identifier]!
|
|
.mapToDebugCodeString();
|
|
expect(
|
|
augmentationStrings,
|
|
unorderedEquals([
|
|
...methodDefinitionMatchers,
|
|
constructorDefinitionMatcher,
|
|
constConstructorDefinitionMatcher,
|
|
factoryConstructorDefinitionMatcher,
|
|
...fieldDefinitionMatchers,
|
|
]));
|
|
});
|
|
|
|
test('on enums', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myEnum,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, hasLength(1));
|
|
var entryAugmentationStrings = definitionResult
|
|
.enumValueAugmentations[Fixtures.myEnum.identifier]!
|
|
.mapToDebugCodeString()
|
|
.toList();
|
|
expect(entryAugmentationStrings,
|
|
unorderedEquals(["a('myField', ),"]));
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
var typeAugmentationStrings = definitionResult
|
|
.typeAugmentations[Fixtures.myEnum.identifier]!
|
|
.mapToDebugCodeString();
|
|
expect(
|
|
typeAugmentationStrings,
|
|
unorderedEquals([
|
|
equalsIgnoringWhitespace('''
|
|
augment MyEnum.myEnumConstructor(String this.myField, ) {
|
|
print('definingClass: MyEnum');
|
|
print('isConst: false');
|
|
print('isFactory: false');
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: MyEnum');
|
|
print('positionalParam: String myField');
|
|
return augmented();
|
|
}''')
|
|
]));
|
|
});
|
|
|
|
test('on enum values', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myEnumValues.first,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, hasLength(1));
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
var augmentationStrings = definitionResult
|
|
.enumValueAugmentations[Fixtures.myEnum.identifier]!
|
|
.mapToDebugCodeString();
|
|
expect(
|
|
augmentationStrings, unorderedEquals(["a('myField', ),"]));
|
|
expect(definitionResult.typeAugmentations, isEmpty);
|
|
});
|
|
|
|
test('on extensions', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myExtension,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
expect(
|
|
definitionResult
|
|
.typeAugmentations[Fixtures.myExtension.identifier]!
|
|
.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace(
|
|
"augment List<String> get onTypeFieldNames => "
|
|
"['myField',];"));
|
|
});
|
|
|
|
test('on extension types', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myExtensionType,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
expect(
|
|
definitionResult
|
|
.typeAugmentations[Fixtures.myExtensionType.identifier]!
|
|
.single
|
|
.debugString()
|
|
.toString(),
|
|
equalsIgnoringWhitespace(
|
|
"augment List<String> get onTypeFieldNames => "
|
|
"['myField',];"));
|
|
});
|
|
|
|
test('on mixins', () async {
|
|
var definitionResult = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.myMixin,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
|
expect(definitionResult.interfaceAugmentations, isEmpty);
|
|
expect(definitionResult.mixinAugmentations, isEmpty);
|
|
expect(definitionResult.typeAugmentations, hasLength(1));
|
|
var augmentationStrings = definitionResult
|
|
.typeAugmentations[Fixtures.myMixin.identifier]!
|
|
.mapToDebugCodeString();
|
|
expect(
|
|
augmentationStrings,
|
|
unorderedEquals(
|
|
mixinMethodDefinitionMatchers,
|
|
));
|
|
});
|
|
|
|
test('on libraries', () async {
|
|
var result = await executor.executeDefinitionsPhase(
|
|
simpleMacroInstanceId,
|
|
Fixtures.library,
|
|
Fixtures.testDefinitionPhaseIntrospector);
|
|
expect(result.enumValueAugmentations, isEmpty);
|
|
expect(result.interfaceAugmentations, isEmpty);
|
|
expect(result.mixinAugmentations, isEmpty);
|
|
expect(result.typeAugmentations, isEmpty);
|
|
expect(
|
|
result.libraryAugmentations.single.debugString().toString(),
|
|
equalsIgnoringWhitespace('''
|
|
augment final LibraryInfo library = LibraryInfo(Uri.parse('package:foo/bar.dart'), '3.0', [MyClass, MyEnum, MyMixin, ]);
|
|
'''));
|
|
});
|
|
|
|
test('Cannot leave dangling tasks', () async {
|
|
expect(
|
|
() => executor.executeDefinitionsPhase(
|
|
danglingTaskMacroId,
|
|
Fixtures.library,
|
|
Fixtures.testDefinitionPhaseIntrospector),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 async tasks still pending')),
|
|
));
|
|
});
|
|
|
|
test('Cannot leave dangling timers', () async {
|
|
expect(
|
|
() => executor.executeDefinitionsPhase(
|
|
danglingTimerMacroId,
|
|
Fixtures.library,
|
|
Fixtures.testDefinitionPhaseIntrospector),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 active timers')),
|
|
));
|
|
|
|
expect(
|
|
() => executor.executeDefinitionsPhase(
|
|
danglingPeriodicTimerMacroId,
|
|
Fixtures.library,
|
|
Fixtures.testDefinitionPhaseIntrospector),
|
|
throwsA(
|
|
isA<UnexpectedMacroException>().having((e) => e.message,
|
|
'message', contains('1 active timers')),
|
|
));
|
|
});
|
|
});
|
|
|
|
test('and report diagnostics', () async {
|
|
final result = await executor.executeTypesPhase(
|
|
diagnosticMacroInstanceId,
|
|
Fixtures.myClass,
|
|
TestTypePhaseIntrospector());
|
|
expect(result.diagnostics, [
|
|
predicate<Diagnostic>((d) =>
|
|
d.severity == Severity.info &&
|
|
d.message.message == 'superclass' &&
|
|
(d.message.target as TypeAnnotationDiagnosticTarget)
|
|
.typeAnnotation ==
|
|
Fixtures.mySuperclassType &&
|
|
d.contextMessages.single.message == 'interface' &&
|
|
(d.contextMessages.single.target
|
|
as TypeAnnotationDiagnosticTarget)
|
|
.typeAnnotation ==
|
|
Fixtures.myInterfaceType &&
|
|
d.correctionMessage == 'correct me!'),
|
|
predicate<Diagnostic>((d) =>
|
|
d.severity == Severity.error &&
|
|
d.message.message.contains('bug in the macro') &&
|
|
// Quick test that some stack trace also appears
|
|
d.contextMessages.first.message
|
|
.contains('simple_macro.dart')),
|
|
]);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
final constructorDefinitionMatcher = equalsIgnoringWhitespace('''
|
|
augment MyClass.myConstructor(/*inferred*/String super.myField, ) {
|
|
print('definingClass: MyClass');
|
|
print('isConst: false');
|
|
print('isFactory: false');
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: MyClass');
|
|
print('positionalParam: String (inferred) myField');
|
|
return augmented();
|
|
}''');
|
|
|
|
final constConstructorDefinitionMatcher = equalsIgnoringWhitespace('''
|
|
augment const MyClass.myConstConstructor(/*inferred*/String this.myField, ) {
|
|
print('definingClass: MyClass');
|
|
print('isConst: true');
|
|
print('isFactory: false');
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: MyClass');
|
|
print('positionalParam: String (inferred) myField');
|
|
return augmented();
|
|
}''');
|
|
|
|
final factoryConstructorDefinitionMatcher = equalsIgnoringWhitespace('''
|
|
augment factory MyClass.myFactoryConstructor(/*inferred*/String myField, ) {
|
|
print('definingClass: MyClass');
|
|
print('isConst: false');
|
|
print('isFactory: true');
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: MyClass');
|
|
print('positionalParam: String (inferred) myField');
|
|
return augmented();
|
|
}''');
|
|
|
|
final fieldDefinitionMatchers = [
|
|
equalsIgnoringWhitespace('''
|
|
augment String get myField {
|
|
print('parentClass: MyClass');
|
|
print('isAbstract: false');
|
|
print('isExternal: false');
|
|
print('isFinal: false');
|
|
print('isLate: false');
|
|
return augmented;
|
|
}'''),
|
|
equalsIgnoringWhitespace('''
|
|
augment set myField(String value) {
|
|
augmented = value;
|
|
}'''),
|
|
equalsIgnoringWhitespace('''
|
|
augment String myField = 'new initial value' + augmented;'''),
|
|
];
|
|
|
|
final methodDefinitionMatchers = [
|
|
equalsIgnoringWhitespace('''
|
|
// A comment!
|
|
augment (String, bool? hello, {String world}) myMethod() {
|
|
print('definingClass: MyClass');
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: (String, bool? hello, {String world})');
|
|
return augmented();
|
|
}'''),
|
|
equalsIgnoringWhitespace('''
|
|
augment (String, bool? hello, {String world}) myMethod() {
|
|
print('myBool: true');
|
|
print('myDouble: 1.0');
|
|
print('myInt: 1');
|
|
print('myList: [1, 2, 3]');
|
|
print('mySet: {true, null, {a: 1.0}}');
|
|
print('myMap: {x: 1}');
|
|
print('myString: a');
|
|
print('parentClass: MyClass');
|
|
print('superClass: MySuperclass');
|
|
print('interface: MyInterface');
|
|
print('mixin: MyMixin');
|
|
print('field: myField');
|
|
print('method: myMethod');
|
|
print('constructor: myConstructor');
|
|
print('constructor: myConstConstructor');
|
|
print('constructor: myFactoryConstructor');
|
|
return augmented();
|
|
}'''),
|
|
];
|
|
|
|
final mixinMethodDefinitionMatchers = [
|
|
equalsIgnoringWhitespace('''
|
|
// A comment!
|
|
augment (String, bool? hello, {String world}) myMixinMethod() {
|
|
print('definingClass: MyMixin');
|
|
print('isExternal: false');
|
|
print('isGetter: false');
|
|
print('isSetter: false');
|
|
print('returnType: (String, bool? hello, {String world})');
|
|
return augmented();
|
|
}'''),
|
|
equalsIgnoringWhitespace('''
|
|
augment (String, bool? hello, {String world}) myMixinMethod() {
|
|
print('myBool: true');
|
|
print('myDouble: 1.0');
|
|
print('myInt: 1');
|
|
print('myList: [1, 2, 3]');
|
|
print('mySet: {true, null, {a: 1.0}}');
|
|
print('myMap: {x: 1}');
|
|
print('myString: a');
|
|
print('parentClass: MyMixin');
|
|
print('superClass: null');
|
|
print('method: myMixinMethod');
|
|
return augmented();
|
|
}'''),
|
|
];
|