mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 20:19:39 +00:00
cac96f7f8d
Change-Id: Ia76aafc6a1190dcdca026097c364270389f2860a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/206565 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
142 lines
5.2 KiB
Dart
142 lines
5.2 KiB
Dart
// Copyright (c) 2020, 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 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
|
import 'package:analyzer/dart/analysis/results.dart';
|
|
import 'package:analyzer/dart/analysis/session.dart';
|
|
import 'package:analyzer/dart/ast/ast.dart';
|
|
import 'package:analyzer/file_system/file_system.dart';
|
|
import 'package:analyzer/file_system/physical_file_system.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:test/test.dart';
|
|
|
|
/// Helper class to test that `test_all.dart` files are properly set up in the
|
|
/// `analyzer` package (and related packages).
|
|
class VerifyTests {
|
|
/// Path to the package's `test` subdirectory.
|
|
final String testDirPath;
|
|
|
|
/// Paths to exclude from analysis completely.
|
|
final List<String>? excludedPaths;
|
|
|
|
VerifyTests(this.testDirPath, {this.excludedPaths});
|
|
|
|
/// Build tests.
|
|
void build() {
|
|
var provider = PhysicalResourceProvider.INSTANCE;
|
|
var collection = AnalysisContextCollection(
|
|
resourceProvider: provider,
|
|
includedPaths: <String>[testDirPath],
|
|
excludedPaths: excludedPaths);
|
|
var contexts = collection.contexts;
|
|
if (contexts.length != 1) {
|
|
fail('The test directory contains multiple analysis contexts.');
|
|
}
|
|
|
|
_buildTestsIn(contexts[0].currentSession, testDirPath,
|
|
provider.getFolder(testDirPath));
|
|
}
|
|
|
|
/// May be overridden in a derived class to indicate whether the test file or
|
|
/// directory indicated by [resource] is so expensive to run that it shouldn't
|
|
/// be included in `test_all.dart` files.
|
|
///
|
|
/// Default behavior is not to consider any test files or directories
|
|
/// expensive.
|
|
bool isExpensive(Resource resource) => false;
|
|
|
|
/// May be overridden in a derived class to indicate whether it is ok for a
|
|
/// `test_all.dart` file in [folder] to import [uri], even if there is no
|
|
/// corresponding test file inside [folder].
|
|
///
|
|
/// Default behavior is to allow imports of test framework URIs.
|
|
bool isOkAsAdditionalTestAllImport(Folder folder, String uri) => const [
|
|
'package:test/test.dart',
|
|
'package:test_reflective_loader/test_reflective_loader.dart'
|
|
].contains(uri);
|
|
|
|
/// May be overridden in a derived class to indicate whether it is ok for
|
|
/// a `test_all.dart` file to be missing from [folder].
|
|
///
|
|
/// Default beahvior is not to allow `test_all.dart` to be missing from any
|
|
/// folder.
|
|
bool isOkForTestAllToBeMissing(Folder folder) => false;
|
|
|
|
void _buildTestsIn(
|
|
AnalysisSession session, String testDirPath, Folder directory) {
|
|
var testFileNames = <String>[];
|
|
File? testAllFile;
|
|
var children = directory.getChildren();
|
|
children
|
|
.sort((first, second) => first.shortName.compareTo(second.shortName));
|
|
for (var child in children) {
|
|
if (child is Folder) {
|
|
if (child.getChildAssumingFile('test_all.dart').exists &&
|
|
!isExpensive(child)) {
|
|
testFileNames.add('${child.shortName}/test_all.dart');
|
|
}
|
|
_buildTestsIn(session, testDirPath, child);
|
|
} else if (child is File) {
|
|
var name = child.shortName;
|
|
if (name == 'test_all.dart') {
|
|
testAllFile = child;
|
|
} else if (name.endsWith('_test.dart') && !isExpensive(child)) {
|
|
testFileNames.add(name);
|
|
}
|
|
}
|
|
}
|
|
var relativePath = path.relative(directory.path, from: testDirPath);
|
|
test(relativePath, () {
|
|
if (testFileNames.isEmpty) {
|
|
return;
|
|
}
|
|
if (testAllFile == null) {
|
|
if (!isOkForTestAllToBeMissing(directory)) {
|
|
fail('Missing "test_all.dart" in $relativePath');
|
|
} else {
|
|
// Ok that the `test_all.dart` file is missing; there's nothing else to
|
|
// check.
|
|
return;
|
|
}
|
|
}
|
|
if (isOkForTestAllToBeMissing(directory)) {
|
|
fail('Found "test_all.dart" in $relativePath but did not expect one');
|
|
}
|
|
var result = session.getParsedUnit(testAllFile.path);
|
|
if (result is! ParsedUnitResult) {
|
|
fail('Could not parse ${testAllFile.path}');
|
|
}
|
|
var importedFiles = <String>[];
|
|
for (var directive in result.unit.directives) {
|
|
if (directive is ImportDirective) {
|
|
var uri = directive.uri.stringValue;
|
|
if (uri == null) {
|
|
fail('Invalid URI: $directive');
|
|
}
|
|
importedFiles.add(uri);
|
|
}
|
|
}
|
|
var missingFiles = <String>[];
|
|
for (var testFileName in testFileNames) {
|
|
if (!importedFiles.contains(testFileName)) {
|
|
missingFiles.add(testFileName);
|
|
}
|
|
}
|
|
if (missingFiles.isNotEmpty) {
|
|
fail('Tests missing from "test_all.dart": ${missingFiles.join(', ')}');
|
|
}
|
|
var extraImports = <String>[];
|
|
for (var importedFile in importedFiles) {
|
|
if (!testFileNames.contains(importedFile) &&
|
|
!isOkAsAdditionalTestAllImport(directory, importedFile)) {
|
|
extraImports.add(importedFile);
|
|
}
|
|
}
|
|
if (extraImports.isNotEmpty) {
|
|
fail('Extra tests in "test_all.dart": ${extraImports.join(', ')}');
|
|
}
|
|
});
|
|
}
|
|
}
|