blob: ea2313493efb9f168b61755d36e42501327b3653 [file] [log] [blame]
// Copyright (c) 2017, 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:async';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:front_end/compiler_options.dart';
import 'package:front_end/incremental_kernel_generator.dart';
import 'package:front_end/memory_file_system.dart';
import 'package:kernel/ast.dart';
import 'package:path/path.dart' as pathos;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(IncrementalKernelGeneratorTest);
});
}
final _sdkSummary = _readSdkSummary();
List<int> _readSdkSummary() {
var resourceProvider = PhysicalResourceProvider.INSTANCE;
var sdk = new FolderBasedDartSdk(resourceProvider,
FolderBasedDartSdk.defaultSdkDirectory(resourceProvider))
..useSummary = true;
var path = resourceProvider.pathContext
.join(sdk.directory.path, 'lib', '_internal', 'strong.sum');
return resourceProvider.getFile(path).readAsBytesSync();
}
@reflectiveTest
class IncrementalKernelGeneratorTest {
static final sdkSummaryUri = Uri.parse('special:sdk_summary');
/// Virtual filesystem for testing.
final fileSystem = new MemoryFileSystem(pathos.posix, Uri.parse('file:///'));
/// The object under test.
IncrementalKernelGenerator incrementalKernelGenerator;
Future<Map<Uri, Program>> getInitialState(Uri startingUri) async {
fileSystem.entityForUri(sdkSummaryUri).writeAsBytesSync(_sdkSummary);
incrementalKernelGenerator = new IncrementalKernelGenerator(
startingUri,
new CompilerOptions()
..fileSystem = fileSystem
..chaseDependencies = true
..sdkSummary = sdkSummaryUri
..packagesFileUri = new Uri());
return (await incrementalKernelGenerator.computeDelta()).newState;
}
test_incrementalUpdate_referenceToCore() async {
writeFiles({'/foo.dart': 'main() { print(1); }'});
var fooUri = Uri.parse('file:///foo.dart');
var coreUri = Uri.parse('dart:core');
var initialState = await getInitialState(fooUri);
expect(initialState.keys, unorderedEquals([fooUri]));
void _checkMain(Program program, int expectedArgument) {
expect(_getLibraryUris(program), unorderedEquals([fooUri, coreUri]));
var mainStatements = _getProcedureStatements(
_getProcedure(_getLibrary(program, fooUri), 'main'));
expect(mainStatements, hasLength(1));
_checkPrintLiteralInt(mainStatements[0], expectedArgument);
var coreLibrary = _getLibrary(program, coreUri);
expect(coreLibrary.procedures, hasLength(1));
expect(coreLibrary.procedures[0].name.name, 'print');
expect(coreLibrary.procedures[0].function.body, isNull);
}
_checkMain(initialState[fooUri], 1);
writeFiles({'/foo.dart': 'main() { print(2); }'});
incrementalKernelGenerator.invalidateAll();
var deltaProgram = await incrementalKernelGenerator.computeDelta();
expect(deltaProgram.newState.keys, unorderedEquals([fooUri]));
_checkMain(deltaProgram.newState[fooUri], 2);
}
test_part() async {
writeFiles({
'/foo.dart': 'library foo; part "bar.dart"; main() { print(1); f(); }',
'/bar.dart': 'part of foo; f() { print(2); }'
});
var fooUri = Uri.parse('file:///foo.dart');
var initialState = await getInitialState(fooUri);
expect(initialState.keys, unorderedEquals([fooUri]));
var library = _getLibrary(initialState[fooUri], fooUri);
var mainStatements =
_getProcedureStatements(_getProcedure(library, 'main'));
var fProcedure = _getProcedure(library, 'f');
var fStatements = _getProcedureStatements(fProcedure);
expect(mainStatements, hasLength(2));
_checkPrintLiteralInt(mainStatements[0], 1);
_checkFunctionCall(mainStatements[1], fProcedure);
expect(fStatements, hasLength(1));
_checkPrintLiteralInt(fStatements[0], 2);
// TODO(paulberry): now test incremental updates
}
/// Write the given file contents to the virtual filesystem.
void writeFiles(Map<String, String> contents) {
contents.forEach((path, text) {
fileSystem
.entityForUri(Uri.parse('file://$path'))
.writeAsStringSync(text);
});
}
void _checkFunctionCall(Statement statement, Procedure expectedTarget) {
expect(statement, new isInstanceOf<ExpressionStatement>());
var expressionStatement = statement as ExpressionStatement;
expect(
expressionStatement.expression, new isInstanceOf<StaticInvocation>());
var staticInvocation = expressionStatement.expression as StaticInvocation;
expect(staticInvocation.target, same(expectedTarget));
}
void _checkPrintLiteralInt(Statement statement, int expectedArgument) {
expect(statement, new isInstanceOf<ExpressionStatement>());
var expressionStatement = statement as ExpressionStatement;
expect(
expressionStatement.expression, new isInstanceOf<StaticInvocation>());
var staticInvocation = expressionStatement.expression as StaticInvocation;
expect(staticInvocation.target.name.name, 'print');
expect(staticInvocation.arguments.positional, hasLength(1));
expect(staticInvocation.arguments.positional[0],
new isInstanceOf<IntLiteral>());
var intLiteral = staticInvocation.arguments.positional[0] as IntLiteral;
expect(intLiteral.value, expectedArgument);
}
Library _getLibrary(Program program, Uri uri) {
for (var library in program.libraries) {
if (library.importUri == uri) return library;
}
throw fail('No library found with URI "$uri"');
}
List<Uri> _getLibraryUris(Program program) =>
program.libraries.map((library) => library.importUri).toList();
Procedure _getProcedure(Library library, String name) {
for (var procedure in library.procedures) {
if (procedure.name.name == name) return procedure;
}
throw fail('No function declaration found with name "$name"');
}
List<Statement> _getProcedureStatements(Procedure procedure) {
var body = procedure.function.body;
expect(body, new isInstanceOf<Block>());
return (body as Block).statements;
}
}