mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:13:04 +00:00
Tests for analyzer_cli and --summary-deps-output results.
I was not able to find any existing tests, and it looks like an important feature, which we don't want to break. I will need to verify that it continues for work with summary2. R=brianwilkerson@google.com, paulberry@google.com Change-Id: Ied2985ebd7b71e85a4b49ec43bf22360fbdd01cd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110126 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Paul Berry <paulberry@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
4c08c5026d
commit
71cd8a6efa
|
@ -26,6 +26,7 @@ import 'utils.dart';
|
|||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(BuildModeTest);
|
||||
defineReflectiveTests(BuildModeSummaryDependenciesTest);
|
||||
defineReflectiveTests(ExitCodesTest);
|
||||
defineReflectiveTests(ExitCodesTest_PreviewDart2);
|
||||
defineReflectiveTests(LinterTest);
|
||||
|
@ -36,6 +37,86 @@ main() {
|
|||
}, name: 'Driver');
|
||||
}
|
||||
|
||||
class AbstractBuildModeTest extends BaseTest {
|
||||
Future<void> _doDrive(String path,
|
||||
{String uri,
|
||||
List<String> additionalArgs: const [],
|
||||
String dartSdkSummaryPath}) async {
|
||||
path = _p(path);
|
||||
|
||||
var optionsFileName = AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
|
||||
var options = _p('data/options_tests_project/' + optionsFileName);
|
||||
|
||||
List<String> args = <String>[];
|
||||
if (dartSdkSummaryPath != null) {
|
||||
args.add('--dart-sdk-summary');
|
||||
args.add(dartSdkSummaryPath);
|
||||
} else {
|
||||
String sdkPath = _findSdkDirForSummaries();
|
||||
args.add('--dart-sdk');
|
||||
args.add(sdkPath);
|
||||
}
|
||||
args.add('--build-mode');
|
||||
args.add('--format=machine');
|
||||
args.addAll(additionalArgs);
|
||||
|
||||
uri ??= 'file:///test_file.dart';
|
||||
String source = '$uri|$path';
|
||||
|
||||
await drive(source, args: args, options: options);
|
||||
}
|
||||
|
||||
/// Try to find a appropriate directory to pass to "--dart-sdk" that will
|
||||
/// allow summaries to be found.
|
||||
String _findSdkDirForSummaries() {
|
||||
Set<String> triedDirectories = new Set<String>();
|
||||
bool isSuitable(String sdkDir) {
|
||||
triedDirectories.add(sdkDir);
|
||||
return new File(path.join(sdkDir, 'lib', '_internal', 'strong.sum'))
|
||||
.existsSync();
|
||||
}
|
||||
|
||||
String makeAbsoluteAndNormalized(String result) {
|
||||
result = path.absolute(result);
|
||||
result = path.normalize(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Usually the sdk directory is the parent of the parent of the "dart"
|
||||
// executable.
|
||||
Directory executableParent = new File(Platform.executable).parent;
|
||||
Directory executableGrandparent = executableParent.parent;
|
||||
if (isSuitable(executableGrandparent.path)) {
|
||||
return makeAbsoluteAndNormalized(executableGrandparent.path);
|
||||
}
|
||||
// During build bot execution, the sdk directory is simply the parent of the
|
||||
// "dart" executable.
|
||||
if (isSuitable(executableParent.path)) {
|
||||
return makeAbsoluteAndNormalized(executableParent.path);
|
||||
}
|
||||
// If neither of those are suitable, assume we are running locally within the
|
||||
// SDK project (e.g. within an IDE). Find the build output directory and
|
||||
// search all built configurations.
|
||||
Directory sdkRootDir =
|
||||
new File(Platform.script.toFilePath()).parent.parent.parent.parent;
|
||||
for (String outDirName in ['out', 'xcodebuild']) {
|
||||
Directory outDir = new Directory(path.join(sdkRootDir.path, outDirName));
|
||||
if (outDir.existsSync()) {
|
||||
for (FileSystemEntity subdir in outDir.listSync()) {
|
||||
if (subdir is Directory) {
|
||||
String candidateSdkDir = path.join(subdir.path, 'dart-sdk');
|
||||
if (isSuitable(candidateSdkDir)) {
|
||||
return makeAbsoluteAndNormalized(candidateSdkDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception('Could not find an SDK directory containing summaries.'
|
||||
' Tried: ${triedDirectories.toList()}');
|
||||
}
|
||||
}
|
||||
|
||||
class BaseTest {
|
||||
static const emptyOptionsFile = 'data/empty_options.yaml';
|
||||
|
||||
|
@ -135,7 +216,266 @@ class BaseTest {
|
|||
}
|
||||
|
||||
@reflectiveTest
|
||||
class BuildModeTest extends BaseTest {
|
||||
class BuildModeSummaryDependenciesTest extends AbstractBuildModeTest {
|
||||
String tempDir;
|
||||
|
||||
/// Any direct export is a dependency.
|
||||
test_export_direct() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], 'class A {}');
|
||||
await _assertDependencies('c', [a], '''
|
||||
export 'package:a/a.dart';
|
||||
''', [a]);
|
||||
});
|
||||
}
|
||||
|
||||
/// Imports of dependencies are not necessary dependencies.
|
||||
/// Here our dependency does not use its dependency.
|
||||
test_import2_notUsed() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], '');
|
||||
var b = await _buildPackage('b', [a], '''
|
||||
import 'package:a/a.dart';
|
||||
''');
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
''', [b]);
|
||||
});
|
||||
}
|
||||
|
||||
test_import2_usedAsFieldType() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], 'class A {}');
|
||||
var b = await _buildPackage('b', [a], '''
|
||||
import 'package:a/a.dart';
|
||||
class B {
|
||||
A f;
|
||||
}
|
||||
''');
|
||||
|
||||
// We don't use `f`, so don't depend on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
var x = B();
|
||||
''', [b]);
|
||||
|
||||
// We use `f` for type inference.
|
||||
// So, dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
var x = B().f;
|
||||
''', [a, b]);
|
||||
|
||||
// We reference `f` in initializer, but not for type inference.
|
||||
// So, no dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
Object x = B().f;
|
||||
''', [b]);
|
||||
|
||||
// We perform full analysis, so request the type of `f`;
|
||||
// So, dependency on "a".
|
||||
await _assertDependencies(
|
||||
'c',
|
||||
[a, b],
|
||||
'''
|
||||
import 'package:b/b.dart';
|
||||
Object x = B().f;
|
||||
''',
|
||||
[a, b],
|
||||
summaryOnly: false,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_import2_usedAsSupertype() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], 'class A {}');
|
||||
var b = await _buildPackage('b', [a], '''
|
||||
import 'package:a/a.dart';
|
||||
class B extends A {}
|
||||
''');
|
||||
|
||||
// We don't invoke anything on class `B`, so don't ask its supertype.
|
||||
// So, no dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
B x;
|
||||
''', [b]);
|
||||
|
||||
// We infer the type of `x` to `B`.
|
||||
// But we don't ask `B` for its supertype.
|
||||
// So, no dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
var x = B();
|
||||
''', [b]);
|
||||
|
||||
// We perform full analysis, and check that `new B()` is assignable
|
||||
// to `B x`. While doing this, we ask for `B` supertype.
|
||||
// So, dependency on "a".
|
||||
await _assertDependencies(
|
||||
'c',
|
||||
[a, b],
|
||||
'''
|
||||
import 'package:b/b.dart';
|
||||
var x = B();
|
||||
''',
|
||||
[a, b],
|
||||
summaryOnly: false,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_import2_usedAsTopLevelVariableType() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], 'class A {}');
|
||||
var b = await _buildPackage('b', [a], '''
|
||||
import 'package:a/a.dart';
|
||||
A v;
|
||||
''');
|
||||
|
||||
// We don't use `v`.
|
||||
// So, no dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
''', [b]);
|
||||
|
||||
// We use `v` for type inference.
|
||||
// So, dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
var x = v;
|
||||
''', [a, b]);
|
||||
|
||||
// We don't use `v` for type inference.
|
||||
// So, no dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
Object x = v;
|
||||
''', [b]);
|
||||
|
||||
// We perform full analysis, and request the type of `v`.
|
||||
// So, dependency on "a".
|
||||
await _assertDependencies(
|
||||
'c',
|
||||
[a, b],
|
||||
'''
|
||||
import 'package:b/b.dart';
|
||||
Object x = v;
|
||||
''',
|
||||
[a, b],
|
||||
summaryOnly: false,
|
||||
);
|
||||
|
||||
// We use `v` in a method body.
|
||||
// So, no dependency on "a".
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
main() {
|
||||
v;
|
||||
}
|
||||
''', [b]);
|
||||
|
||||
// We perform full analysis, so ask for the type of `v`.
|
||||
// So, dependency on "a".
|
||||
await _assertDependencies(
|
||||
'c',
|
||||
[a, b],
|
||||
'''
|
||||
import 'package:b/b.dart';
|
||||
main() {
|
||||
v;
|
||||
}
|
||||
''',
|
||||
[a, b],
|
||||
summaryOnly: false,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Any direct import is a dependency.
|
||||
test_import_direct() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], '');
|
||||
var b = await _buildPackage('b', [], '');
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:a/a.dart';
|
||||
import 'package:b/b.dart';
|
||||
''', [a, b]);
|
||||
});
|
||||
}
|
||||
|
||||
/// Exports of dependencies are dependencies.
|
||||
test_import_export() async {
|
||||
await _withTempDir(() async {
|
||||
var a = await _buildPackage('a', [], 'class A {}');
|
||||
var b = await _buildPackage('b', [a], '''
|
||||
export 'package:a/a.dart';
|
||||
''');
|
||||
await _assertDependencies('c', [a, b], '''
|
||||
import 'package:b/b.dart';
|
||||
''', [a, b]);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _assertDependencies(
|
||||
String name,
|
||||
List<_DependencyPackage> inputPackages,
|
||||
String content,
|
||||
List<_DependencyPackage> expectedPackages, {
|
||||
bool summaryOnly = true,
|
||||
}) async {
|
||||
var pkg = await _buildPackage(name, inputPackages, content,
|
||||
summaryOnly: summaryOnly);
|
||||
|
||||
var depString = File(pkg.dep).readAsStringSync();
|
||||
var expectedList = expectedPackages.map((p) => p.sum).toList();
|
||||
expect(depString.split('\n'), unorderedEquals(expectedList));
|
||||
}
|
||||
|
||||
Future<_DependencyPackage> _buildPackage(
|
||||
String name,
|
||||
List<_DependencyPackage> inputPackages,
|
||||
String content, {
|
||||
bool summaryOnly = true,
|
||||
}) async {
|
||||
var filePath = path.join(tempDir, '$name.dart');
|
||||
File(filePath).writeAsStringSync(content);
|
||||
var pkg = _DependencyPackage(
|
||||
name: name,
|
||||
path: filePath,
|
||||
uri: 'package:$name/$name.dart',
|
||||
sum: path.join(tempDir, '$name.sum'),
|
||||
dep: path.join(tempDir, '$name.dep'),
|
||||
);
|
||||
|
||||
var args = <String>[];
|
||||
if (summaryOnly) {
|
||||
args.add('--build-summary-only');
|
||||
}
|
||||
for (var input in inputPackages) {
|
||||
args.add('--build-summary-input=${input.sum}');
|
||||
}
|
||||
args.add('--build-summary-output=${pkg.sum}');
|
||||
args.add('--summary-deps-output=${pkg.dep}');
|
||||
|
||||
await _doDrive(pkg.path, uri: pkg.uri, additionalArgs: args);
|
||||
expect(exitCode, 0);
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
Future<void> _withTempDir(Future<void> f()) async {
|
||||
await withTempDirAsync((tempDir) async {
|
||||
this.tempDir = tempDir;
|
||||
await f();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class BuildModeTest extends AbstractBuildModeTest {
|
||||
test_buildLinked() async {
|
||||
await withTempDirAsync((tempDir) async {
|
||||
var outputPath = path.join(tempDir, 'test_file.dart.sum');
|
||||
|
@ -484,84 +824,6 @@ var b = new B();
|
|||
expect(errorSink, isEmpty);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _doDrive(String path,
|
||||
{String uri,
|
||||
List<String> additionalArgs: const [],
|
||||
String dartSdkSummaryPath}) async {
|
||||
path = _p(path);
|
||||
|
||||
var optionsFileName = AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
|
||||
var options = _p('data/options_tests_project/' + optionsFileName);
|
||||
|
||||
List<String> args = <String>[];
|
||||
if (dartSdkSummaryPath != null) {
|
||||
args.add('--dart-sdk-summary');
|
||||
args.add(dartSdkSummaryPath);
|
||||
} else {
|
||||
String sdkPath = _findSdkDirForSummaries();
|
||||
args.add('--dart-sdk');
|
||||
args.add(sdkPath);
|
||||
}
|
||||
args.add('--build-mode');
|
||||
args.add('--format=machine');
|
||||
args.addAll(additionalArgs);
|
||||
|
||||
uri ??= 'file:///test_file.dart';
|
||||
String source = '$uri|$path';
|
||||
|
||||
await drive(source, args: args, options: options);
|
||||
}
|
||||
|
||||
/// Try to find a appropriate directory to pass to "--dart-sdk" that will
|
||||
/// allow summaries to be found.
|
||||
String _findSdkDirForSummaries() {
|
||||
Set<String> triedDirectories = new Set<String>();
|
||||
bool isSuitable(String sdkDir) {
|
||||
triedDirectories.add(sdkDir);
|
||||
return new File(path.join(sdkDir, 'lib', '_internal', 'strong.sum'))
|
||||
.existsSync();
|
||||
}
|
||||
|
||||
String makeAbsoluteAndNormalized(String result) {
|
||||
result = path.absolute(result);
|
||||
result = path.normalize(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Usually the sdk directory is the parent of the parent of the "dart"
|
||||
// executable.
|
||||
Directory executableParent = new File(Platform.executable).parent;
|
||||
Directory executableGrandparent = executableParent.parent;
|
||||
if (isSuitable(executableGrandparent.path)) {
|
||||
return makeAbsoluteAndNormalized(executableGrandparent.path);
|
||||
}
|
||||
// During build bot execution, the sdk directory is simply the parent of the
|
||||
// "dart" executable.
|
||||
if (isSuitable(executableParent.path)) {
|
||||
return makeAbsoluteAndNormalized(executableParent.path);
|
||||
}
|
||||
// If neither of those are suitable, assume we are running locally within the
|
||||
// SDK project (e.g. within an IDE). Find the build output directory and
|
||||
// search all built configurations.
|
||||
Directory sdkRootDir =
|
||||
new File(Platform.script.toFilePath()).parent.parent.parent.parent;
|
||||
for (String outDirName in ['out', 'xcodebuild']) {
|
||||
Directory outDir = new Directory(path.join(sdkRootDir.path, outDirName));
|
||||
if (outDir.existsSync()) {
|
||||
for (FileSystemEntity subdir in outDir.listSync()) {
|
||||
if (subdir is Directory) {
|
||||
String candidateSdkDir = path.join(subdir.path, 'dart-sdk');
|
||||
if (isSuitable(candidateSdkDir)) {
|
||||
return makeAbsoluteAndNormalized(candidateSdkDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception('Could not find an SDK directory containing summaries.'
|
||||
' Tried: ${triedDirectories.toList()}');
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
|
@ -973,3 +1235,13 @@ class TestSource implements Source {
|
|||
@override
|
||||
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _DependencyPackage {
|
||||
final String name;
|
||||
final String path;
|
||||
final String uri;
|
||||
final String sum;
|
||||
final String dep;
|
||||
|
||||
_DependencyPackage({this.name, this.path, this.uri, this.sum, this.dep});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue