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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:async';
6 import 'dart:io';
7
8 import 'package:front_end/compiler_options.dart';
9 import 'package:front_end/dependency_grapher.dart';
10 import 'package:path/path.dart' as pathos;
11
12 main() async {
13 exit(await new _SubpackageRelationshipsTest().run());
14 }
15
16 /// Map from subpackage name to the rules for what the subpackage is allowed to
17 /// depend directly on.
18 ///
19 /// Each subdirectory of `lib/src` is considered a subpackage. Files in
20 /// `lib/src` but not in a subdirectory are considered to be in the `lib/src`
21 /// subpackage. Files outside of `lib/src` (but still in `lib`) are considered
22 /// to be in the `lib` subpackage.
23 ///
24 /// TODO(paulberry): stuff in lib/src shouldn't depend on lib; lib should just
25 /// re-export stuff in lib/src.
26 /// TODO(paulberry): remove dependencies on analyzer.
27 final subpackageRules = {
Paul Berry 2017/01/12 21:32:16 Note: this describes the dependencies that exist t
28 'lib': new SubpackageRules(
29 mayImportAnalyzer: true,
30 allowedDependencies: ['lib/src', 'lib/src/base']),
31 'lib/src': new SubpackageRules(
32 mayImportAnalyzer: true,
33 allowedDependencies: ['lib', 'lib/src/base', 'lib/src/scanner']),
34 'lib/src/base': new SubpackageRules(
35 mayImportAnalyzer: true, allowedDependencies: ['lib']),
36 'lib/src/scanner': new SubpackageRules(allowedDependencies: ['lib/src/base']),
37 };
38
39 /// Rules for what a subpackage may depend directly on.
40 class SubpackageRules {
41 /// Indicates whether the subpackage may directly depend on analyzer.
42 final bool mayImportAnalyzer;
43
44 /// Indicates which other subpackages a given subpackage may directly depend
45 /// on.
46 final List<String> allowedDependencies;
47
48 SubpackageRules(
49 {this.mayImportAnalyzer: false, this.allowedDependencies: const []});
50 }
51
52 class _SubpackageRelationshipsTest {
53 /// File uri of the root of the front_end package.
54 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
55
56 /// Indicates whether any problems have been reported yet.
57 bool problemsReported = false;
58
59 /// Check for problems resulting from URI [src] having a direct dependency on
60 /// URI [dst].
61 void checkDependency(Uri src, Uri dst) {
62 if (dst.scheme == 'dart') return;
63 if (dst.scheme != 'package') {
64 problem('$src depends on $dst, which is neither a package: or dart: URI');
65 return;
66 }
67 var srcSubpackage = subpackageForUri(src);
68 if (srcSubpackage == null) return;
69 var srcSubpackageRules = subpackageRules[srcSubpackage];
70 if (srcSubpackageRules == null) {
71 problem('$src is in subpackage "$srcSubpackage", which is not found in '
72 'subpackageRules');
73 return;
74 }
75 if (!srcSubpackageRules.mayImportAnalyzer &&
76 dst.pathSegments[0] == 'analyzer') {
77 problem('$src depends on $dst, but subpackage "$srcSubpackage" may not '
78 'import analyzer');
79 }
80 var dstSubPackage = subpackageForUri(dst);
81 if (dstSubPackage == null) return;
82 if (dstSubPackage == srcSubpackage) return;
83 if (!srcSubpackageRules.allowedDependencies.contains(dstSubPackage)) {
84 problem('$src depends on $dst, but subpackage "$srcSubpackage" is not '
85 'allowed to depend on subpackage "$dstSubPackage"');
86 }
87 }
88
89 /// Finds all files in the front_end's "lib" directory and returns their Uris
90 /// (as "package:" URIs).
91 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.
92 var frontEndUris = <Uri>[];
93 var frontEndRootPath = pathos.fromUri(frontEndRootUri);
94 await for (var entity in new Directory(frontEndRootPath)
95 .list(recursive: true, followLinks: false)) {
96 if (entity is File && entity.path.endsWith('.dart')) {
97 var posixRelativePath = pathos
98 .relative(entity.path, from: frontEndRootPath)
99 .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.
100 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.
101 frontEndUris.add(Uri.parse(
102 posixRelativePath.replaceFirst('lib/', 'package:front_end/')));
103 }
104 }
105 return frontEndUris;
106 }
107
108 /// Reports a single problem.
109 void problem(String description) {
110 print(description);
111 problemsReported = true;
112 }
113
114 /// Tests all subpackage relationships in the front end, and returns an
115 /// appropriate exit code.
116 Future<int> run() async {
117 var frontEndUris = await findFrontEndUris();
118 var packagesFileUri = frontEndRootUri.resolve('../../.packages');
119 var graph = await graphForProgram(
120 frontEndUris,
121 new CompilerOptions()
122 ..packagesFileUri = packagesFileUri
123 ..chaseDependencies = true);
124 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
125 for (var library in graph.topologicallySortedCycles[i].libraries.values) {
126 for (var dependency in library.dependencies) {
127 checkDependency(library.uri, dependency.uri);
128 }
129 }
130 }
131 return problemsReported ? 1 : 0;
132 }
133
134 /// Determines which subpackage [src] is in.
135 ///
136 /// If [src] is not part of the front end, `null` is returned.
137 String subpackageForUri(Uri src) {
138 if (src.scheme != 'package') return null;
139 if (src.pathSegments[0] != 'front_end') return null;
140 if (src.pathSegments[1] != 'src') return 'lib';
141 if (src.pathSegments.length == 3) return 'lib/src';
142 return 'lib/src/${src.pathSegments[2]}';
143 }
144 }
OLDNEW
« 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