Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Unified Diff: pkg/front_end/test/subpackage_relationships_test.dart

Issue 2624913004: Test that subpackages of front_end don't have undesired dependencies. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/front_end/test/subpackage_relationships_test.dart
diff --git a/pkg/front_end/test/subpackage_relationships_test.dart b/pkg/front_end/test/subpackage_relationships_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3af7b72eae7923171907e99c98157daa07c42c41
--- /dev/null
+++ b/pkg/front_end/test/subpackage_relationships_test.dart
@@ -0,0 +1,144 @@
+// 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 'dart:io';
+
+import 'package:front_end/compiler_options.dart';
+import 'package:front_end/dependency_grapher.dart';
+import 'package:path/path.dart' as pathos;
+
+main() async {
+ exit(await new _SubpackageRelationshipsTest().run());
+}
+
+/// Map from subpackage name to the rules for what the subpackage is allowed to
+/// depend directly on.
+///
+/// Each subdirectory of `lib/src` is considered a subpackage. Files in
+/// `lib/src` but not in a subdirectory are considered to be in the `lib/src`
+/// subpackage. Files outside of `lib/src` (but still in `lib`) are considered
+/// to be in the `lib` subpackage.
+///
+/// TODO(paulberry): stuff in lib/src shouldn't depend on lib; lib should just
+/// re-export stuff in lib/src.
+/// TODO(paulberry): remove dependencies on analyzer.
+final subpackageRules = {
Paul Berry 2017/01/12 21:32:16 Note: this describes the dependencies that exist t
+ 'lib': new SubpackageRules(
+ mayImportAnalyzer: true,
+ allowedDependencies: ['lib/src', 'lib/src/base']),
+ 'lib/src': new SubpackageRules(
+ mayImportAnalyzer: true,
+ allowedDependencies: ['lib', 'lib/src/base', 'lib/src/scanner']),
+ 'lib/src/base': new SubpackageRules(
+ mayImportAnalyzer: true, allowedDependencies: ['lib']),
+ 'lib/src/scanner': new SubpackageRules(allowedDependencies: ['lib/src/base']),
+};
+
+/// Rules for what a subpackage may depend directly on.
+class SubpackageRules {
+ /// Indicates whether the subpackage may directly depend on analyzer.
+ final bool mayImportAnalyzer;
+
+ /// Indicates which other subpackages a given subpackage may directly depend
+ /// on.
+ final List<String> allowedDependencies;
+
+ SubpackageRules(
+ {this.mayImportAnalyzer: false, this.allowedDependencies: const []});
+}
+
+class _SubpackageRelationshipsTest {
+ /// File uri of the root of the front_end package.
+ final frontEndRootUri = Platform.script.resolve('..');
danrubel 2017/01/12 21:54:54 Will this test fail if run from the wrong director
Paul Berry 2017/01/12 22:25:01 Platform.script is the path to the script file (me
+
+ /// Indicates whether any problems have been reported yet.
+ bool problemsReported = false;
+
+ /// Check for problems resulting from URI [src] having a direct dependency on
+ /// URI [dst].
+ void checkDependency(Uri src, Uri dst) {
+ if (dst.scheme == 'dart') return;
+ if (dst.scheme != 'package') {
+ problem('$src depends on $dst, which is neither a package: or dart: URI');
+ return;
+ }
+ var srcSubpackage = subpackageForUri(src);
+ if (srcSubpackage == null) return;
+ var srcSubpackageRules = subpackageRules[srcSubpackage];
+ if (srcSubpackageRules == null) {
+ problem('$src is in subpackage "$srcSubpackage", which is not found in '
+ 'subpackageRules');
+ return;
+ }
+ if (!srcSubpackageRules.mayImportAnalyzer &&
+ dst.pathSegments[0] == 'analyzer') {
+ problem('$src depends on $dst, but subpackage "$srcSubpackage" may not '
+ 'import analyzer');
+ }
+ var dstSubPackage = subpackageForUri(dst);
+ if (dstSubPackage == null) return;
+ if (dstSubPackage == srcSubpackage) return;
+ if (!srcSubpackageRules.allowedDependencies.contains(dstSubPackage)) {
+ problem('$src depends on $dst, but subpackage "$srcSubpackage" is not '
+ 'allowed to depend on subpackage "$dstSubPackage"');
+ }
+ }
+
+ /// Finds all files in the front_end's "lib" directory and returns their Uris
+ /// (as "package:" URIs).
+ Future<List<Uri>> findFrontEndUris() async {
Siggi Cherem (dart-lang) 2017/01/12 22:39:12 FWIW - for simple unit tests, I'm in favor of keep
Paul Berry 2017/01/12 23:35:57 Fair enough. Done.
+ var frontEndUris = <Uri>[];
+ var frontEndRootPath = pathos.fromUri(frontEndRootUri);
+ await for (var entity in new Directory(frontEndRootPath)
+ .list(recursive: true, followLinks: false)) {
+ if (entity is File && entity.path.endsWith('.dart')) {
+ var posixRelativePath = pathos
+ .relative(entity.path, from: frontEndRootPath)
+ .replaceAll(pathos.separator, '/');
Siggi Cherem (dart-lang) 2017/01/12 22:39:12 alternatively, use the various pathos contexts (in
Paul Berry 2017/01/12 23:35:57 Done.
+ if (!posixRelativePath.startsWith('lib/')) continue;
Siggi Cherem (dart-lang) 2017/01/12 22:39:12 consider making the frontEndRootPath be `Platform.
Paul Berry 2017/01/12 23:35:57 Done.
+ frontEndUris.add(Uri.parse(
+ posixRelativePath.replaceFirst('lib/', 'package:front_end/')));
+ }
+ }
+ return frontEndUris;
+ }
+
+ /// Reports a single problem.
+ void problem(String description) {
+ print(description);
+ problemsReported = true;
+ }
+
+ /// Tests all subpackage relationships in the front end, and returns an
+ /// appropriate exit code.
+ Future<int> run() async {
+ var frontEndUris = await findFrontEndUris();
+ var packagesFileUri = frontEndRootUri.resolve('../../.packages');
+ var graph = await graphForProgram(
+ frontEndUris,
+ new CompilerOptions()
+ ..packagesFileUri = packagesFileUri
+ ..chaseDependencies = true);
+ for (var i = 0; i < graph.topologicallySortedCycles.length; i++) {
Siggi Cherem (dart-lang) 2017/01/12 22:39:12 Do we need to use the graph/walker API and compute
Paul Berry 2017/01/12 23:35:57 Regarding computation of library cycles, I agree t
Siggi Cherem (dart-lang) 2017/01/13 00:02:06 Sounds good, no problem. Last year some unit test
+ for (var library in graph.topologicallySortedCycles[i].libraries.values) {
+ for (var dependency in library.dependencies) {
+ checkDependency(library.uri, dependency.uri);
+ }
+ }
+ }
+ return problemsReported ? 1 : 0;
+ }
+
+ /// Determines which subpackage [src] is in.
+ ///
+ /// If [src] is not part of the front end, `null` is returned.
+ String subpackageForUri(Uri src) {
+ if (src.scheme != 'package') return null;
+ if (src.pathSegments[0] != 'front_end') return null;
+ if (src.pathSegments[1] != 'src') return 'lib';
+ if (src.pathSegments.length == 3) return 'lib/src';
+ return 'lib/src/${src.pathSegments[2]}';
+ }
+}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698