blob: 1f2d810a28a46ac0474e940a2a08014990a47d16 [file] [log] [blame]
// Copyright (c) 2024, 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:isolate';
import 'package:_macro_host/macro_host.dart';
import 'package:dart_model/dart_model.dart';
import 'package:macro_service/macro_service.dart';
import 'package:test/test.dart';
void main() {
final fooTarget = QualifiedName(name: 'Foo', uri: 'package:foo/foo.dart');
final fooModel = Scope.query.run(
() =>
Model()
..uris[fooTarget.uri] =
(Library()
..scopes['Foo'] = Interface(
properties: Properties(isClass: true),
)),
);
for (final protocol in [
Protocol(encoding: ProtocolEncoding.json, version: ProtocolVersion.macros1),
Protocol(
encoding: ProtocolEncoding.binary,
version: ProtocolVersion.macros1,
),
]) {
group('MacroHost using ${protocol.encoding}', () {
test('hosts a macro, receives augmentations', () async {
final macroAnnotation = QualifiedName(
uri: 'package:_test_macros/declare_x_macro.dart',
name: 'DeclareX',
);
final queryService = TestQueryService();
final host = await MacroHost.serve(
protocol: protocol,
packageConfig: Isolate.packageConfigSync!,
queryService: queryService,
);
expect(host.isMacro(macroAnnotation), true);
expect(await host.queryMacroPhases(macroAnnotation), {2});
expect(
await host.augment(
macroAnnotation,
AugmentRequest(phase: 2, target: fooTarget, model: fooModel),
),
Scope.macro.run(
() =>
AugmentResponse(libraryAugmentations: [], newTypeNames: [])
..typeAugmentations!['Foo'] = [
Augmentation(code: [Code.string('int get x => 3;')]),
],
),
);
});
test('hosts a macro, responds to queries', () async {
final macroAnnotation = QualifiedName(
uri: 'package:_test_macros/query_class.dart',
name: 'QueryClass',
);
final queryService = TestQueryService();
final host = await MacroHost.serve(
protocol: protocol,
packageConfig: Isolate.packageConfigSync!,
queryService: queryService,
);
expect(host.isMacro(macroAnnotation), true);
expect(await host.queryMacroPhases(macroAnnotation), {3});
expect(
await host.augment(
macroAnnotation,
AugmentRequest(phase: 3, target: fooTarget, model: fooModel),
),
Scope.macro.run(
() => AugmentResponse(libraryAugmentations: [], newTypeNames: [])
..typeAugmentations!['Foo'] = [
Augmentation(
code: [
Code.string(
'// {"uris":{"package:foo/foo.dart":{"scopes":{"Foo":{'
'"members":{},"properties":{"isClass":true}}}}}}',
),
],
),
],
),
);
});
test('hosts two macros', () async {
final macroNames = [
QualifiedName(
uri: 'package:_test_macros/declare_x_macro.dart',
name: 'DeclareX',
),
QualifiedName(
uri: 'package:_test_macros/query_class.dart',
name: 'QueryClass',
),
];
final queryService = TestQueryService();
final host = await MacroHost.serve(
protocol: protocol,
packageConfig: Isolate.packageConfigSync!,
queryService: queryService,
);
for (final macroName in macroNames) {
await host.augment(
macroName,
AugmentRequest(phase: 3, target: fooTarget, model: fooModel),
);
}
});
group('caching', () {
final macroAnnotation = QualifiedName(
uri: 'package:_test_macros/declare_x_macro.dart',
name: 'DeclareX',
);
late AugmentResponse initialResult;
late MacroHost host;
late TestQueryService queryService;
setUp(() async {
queryService = TestQueryService();
host = await MacroHost.serve(
protocol: protocol,
packageConfig: Isolate.packageConfigSync!,
queryService: queryService,
);
initialResult = await host.augment(
macroAnnotation,
AugmentRequest(phase: 2, target: fooTarget, model: fooModel),
);
});
test('re-uses results if queries don\'t change', () async {
final rerunResult = await host.augment(
macroAnnotation,
AugmentRequest(phase: 2, target: fooTarget, model: fooModel),
);
expect(identical(initialResult, rerunResult), true);
});
test('Invalidates results if queries do change', () async {
queryService.handleRequest = (QueryRequest request) async {
return QueryResponse(
model:
Model()
..uris[request.query.target.uri] =
(Library()
..scopes[request.query.target.name] = Interface(
properties: Properties(isClass: false),
)),
);
};
final rerunResult = await host.augment(
macroAnnotation,
AugmentRequest(phase: 2, target: fooTarget, model: fooModel),
);
expect(identical(initialResult, rerunResult), false);
});
});
});
}
}
final class TestQueryService extends QueryService {
/// Actual implementatin of request handling, can be overwritten.
Future<QueryResponse> Function(QueryRequest request) handleRequest = (
QueryRequest request,
) async {
return QueryResponse(
model:
Model()
..uris[request.query.target.uri] =
(Library()
..scopes[request.query.target.name] = Interface(
properties: Properties(isClass: true),
)),
);
};
@override
Future<QueryResponse> handle(QueryRequest request) => handleRequest(request);
}