forbidden_imports_test.dart 11.7 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7
import 'package:file/file.dart';
8

9
import '../src/common.dart';
10
import 'test_utils.dart';
11

12
void main() {
13
  final String flutterTools = fileSystem.path.join(getFlutterRoot(), 'packages', 'flutter_tools');
14

15 16
  test('no imports of commands/* or test/* in lib/src/*', () {
    final List<String> skippedPaths = <String> [
17 18
      fileSystem.path.join(flutterTools, 'lib', 'src', 'commands'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'test'),
19 20 21
    ];
    bool _isNotSkipped(FileSystemEntity entity) => skippedPaths.every((String path) => !entity.path.startsWith(path));

22
    final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, 'lib', 'src'))
23 24 25 26
      .listSync(recursive: true)
      .where(_isDartFile)
      .where(_isNotSkipped)
      .map(_asFile);
27 28
    for (final File file in files) {
      for (final String line in file.readAsLinesSync()) {
29 30 31 32 33
        if (line.startsWith(RegExp(r'import.*package:'))) {
          continue;
        }
        if (line.startsWith(RegExp(r'import.*commands/'))
         || line.startsWith(RegExp(r'import.*test/'))) {
34
          final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
35 36 37 38 39 40 41
          fail('$relativePath imports $line. This import introduces a layering violation. '
               'Please find another way to access the information you are using.');
        }
      }
    }
  });

42 43 44 45
  test('no imports of globals without a global prefix', () {
    final List<String> skippedPaths = <String> [];
    bool _isNotSkipped(FileSystemEntity entity) => skippedPaths.every((String path) => !entity.path.startsWith(path));

46
    final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, 'lib', 'src'))
47
      .listSync(recursive: true)
48
      .followedBy(fileSystem.directory(fileSystem.path.join(flutterTools, 'test',)).listSync(recursive: true))
49 50 51
      .where(_isDartFile)
      .where(_isNotSkipped)
      .map(_asFile);
52 53
    for (final File file in files) {
      for (final String line in file.readAsLinesSync()) {
54 55 56
        if ((line.startsWith(RegExp(r'import.*globals.dart')) ||
                line.startsWith(RegExp(r'import.*globals_null_migrated.dart'))) &&
            !line.contains(r'as globals')) {
57
          final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
58
          fail('$relativePath imports globals_null_migrated.dart or globals.dart without a globals prefix.');
59 60 61 62 63
        }
      }
    }
  });

64
  test('no unauthorized imports of dart:io', () {
65
    final List<String> allowedPaths = <String>[
66 67
      // This is a standalone script invoked by xcode, not part of the tool
      fileSystem.path.join(flutterTools, 'bin', 'xcode_backend.dart'),
68 69 70
      fileSystem.path.join(flutterTools, 'lib', 'src', 'base', 'io.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'base', 'platform.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'base', 'error_handling_io.dart'),
71
      fileSystem.path.join(flutterTools, 'lib', 'src', 'base', 'multi_root_file_system.dart'),
72
    ];
73
    bool _isNotAllowed(FileSystemEntity entity) => allowedPaths.every((String path) => path != entity.path);
74

75
    for (final String dirName in <String>['lib', 'bin']) {
76
      final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
77 78
        .listSync(recursive: true)
        .where(_isDartFile)
79
        .where(_isNotAllowed)
80
        .map(_asFile);
81 82
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
83
          if (line.startsWith(RegExp(r'import.*dart:io')) &&
84
              !line.contains('flutter_ignore: dart_io_import')) {
85
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
86
            fail("$relativePath imports 'dart:io'; import 'lib/src/base/io.dart' instead");
87 88
          }
        }
89
      }
90 91 92
    }
  });

93 94 95
  test('no unauthorized imports of package:http', () {
    final List<String> allowedPaths = <String>[
      // Used only for multi-part file uploads, which are non-trivial to reimplement.
96
      fileSystem.path.join(flutterTools, 'lib', 'src', 'reporting', 'crash_reporting.dart'),
97 98 99 100 101 102 103 104 105 106 107 108
    ];
    bool _isNotAllowed(FileSystemEntity entity) => allowedPaths.every((String path) => path != entity.path);

    for (final String dirName in <String>['lib', 'bin']) {
      final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
        .listSync(recursive: true)
        .where(_isDartFile)
        .where(_isNotAllowed)
        .map(_asFile);
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
          if (line.startsWith(RegExp(r'import.*package:http/')) &&
109
              !line.contains('flutter_ignore: package_http_import')) {
110 111 112 113 114 115 116 117
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
            fail("$relativePath imports 'package:http'; import 'lib/src/base/io.dart' instead");
          }
        }
      }
    }
  });

118
  test('no unauthorized imports of test_api', () {
119
    final List<String> allowedPaths = <String>[
120 121 122
      fileSystem.path.join(flutterTools, 'lib', 'src', 'test', 'flutter_platform.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'test', 'flutter_web_platform.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'test', 'test_wrapper.dart'),
123
    ];
124
    bool _isNotAllowed(FileSystemEntity entity) => allowedPaths.every((String path) => path != entity.path);
125

126
    for (final String dirName in <String>['lib']) {
127
      final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
128 129
        .listSync(recursive: true)
        .where(_isDartFile)
130
        .where(_isNotAllowed)
131
        .map(_asFile);
132 133
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
134
          if (line.startsWith(RegExp(r'import.*package:test_api')) &&
135
              !line.contains('flutter_ignore: test_api_import')) {
136
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
137 138 139 140 141 142 143
            fail("$relativePath imports 'package:test_api/test_api.dart';");
          }
        }
      }
    }
  });

144
  test('no unauthorized imports of package:path', () {
145
    final List<String> allowedPath = <String>[
146
      fileSystem.path.join(flutterTools, 'lib', 'src', 'isolated', 'web_compilation_delegate.dart'),
147
      fileSystem.path.join(flutterTools, 'test', 'general.shard', 'platform_plugins_test.dart'),
148
    ];
149
    for (final String dirName in <String>['lib', 'bin', 'test']) {
150
      final Iterable<File> files =  fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
151 152
        .listSync(recursive: true)
        .where(_isDartFile)
153
        .where((FileSystemEntity entity) => !allowedPath.contains(entity.path))
154
        .map(_asFile);
155 156
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
157
          if (line.startsWith(RegExp(r'import.*package:path/path.dart')) &&
158
              !line.contains('flutter_ignore: package_path_import')) {
159 160
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
            fail("$relativePath imports 'package:path/path.dart'; use 'fileSystem.path' instead");
161 162
          }
        }
163
      }
164 165
    }
  });
166

167
  test('no unauthorized imports of package:file/local.dart', () {
168
    final List<String> allowedPath = <String>[
169 170
      fileSystem.path.join(flutterTools, 'test', 'integration.shard', 'test_utils.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'base', 'file_system.dart'),
171 172
    ];
    for (final String dirName in <String>['lib', 'bin', 'test']) {
173
      final Iterable<File> files =  fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
174 175
        .listSync(recursive: true)
        .where(_isDartFile)
176
        .where((FileSystemEntity entity) => !allowedPath.contains(entity.path))
177 178 179 180
        .map(_asFile);
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
          if (line.startsWith(RegExp(r'import.*package:file/local.dart'))) {
181
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
182 183 184 185 186 187 188
            fail("$relativePath imports 'package:file/local.dart'; use 'lib/src/base/file_system.dart' instead");
          }
        }
      }
    }
  });

189
  test('no unauthorized imports of dart:convert', () {
190
    final List<String> allowedPaths = <String>[
191 192
      fileSystem.path.join(flutterTools, 'lib', 'src', 'convert.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'base', 'error_handling_io.dart'),
193
    ];
194
    bool _isNotAllowed(FileSystemEntity entity) => allowedPaths.every((String path) => path != entity.path);
195

196
    for (final String dirName in <String>['lib']) {
197
      final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
198 199
        .listSync(recursive: true)
        .where(_isDartFile)
200
        .where(_isNotAllowed)
201
        .map(_asFile);
202 203
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
204
          if (line.startsWith(RegExp(r'import.*dart:convert')) &&
205
              !line.contains('flutter_ignore: dart_convert_import')) {
206
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
207 208 209 210 211 212
            fail("$relativePath imports 'dart:convert'; import 'lib/src/convert.dart' instead");
          }
        }
      }
    }
  });
213

214
  test('no unauthorized imports of build_runner/dwds/devtools', () {
215
    final List<String> allowedPaths = <String>[
216 217
      fileSystem.path.join(flutterTools, 'test', 'src', 'isolated'),
      fileSystem.path.join(flutterTools, 'lib', 'src', 'isolated'),
218 219 220
      fileSystem.path.join(flutterTools, 'lib', 'executable.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'devfs_web.dart'),
      fileSystem.path.join(flutterTools, 'lib', 'resident_web_runner.dart'),
221
    ];
222
    bool _isNotAllowed(FileSystemEntity entity) => allowedPaths.every((String path) => !entity.path.contains(path));
223

224
    for (final String dirName in <String>['lib']) {
225
      final Iterable<File> files = fileSystem.directory(fileSystem.path.join(flutterTools, dirName))
226 227
        .listSync(recursive: true)
        .where(_isDartFile)
228
        .where(_isNotAllowed)
229
        .map(_asFile);
230 231
      for (final File file in files) {
        for (final String line in file.readAsLinesSync()) {
232 233 234
          if (line.startsWith(RegExp(r'import.*package:build_runner_core/build_runner_core.dart')) ||
              line.startsWith(RegExp(r'import.*package:build_runner/build_runner.dart')) ||
              line.startsWith(RegExp(r'import.*package:build_config/build_config.dart')) ||
235
              line.startsWith(RegExp(r'import.*dwds:*.dart')) ||
236
              line.startsWith(RegExp(r'import.*devtools_server:*.dart')) ||
237
              line.startsWith(RegExp(r'import.*build_runner/.*.dart'))) {
238
            final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
239
            fail('$relativePath imports a build_runner/dwds/devtools package');
240 241 242 243 244
          }
        }
      }
    }
  });
245 246

  test('no import of packages in tool_backend.dart', () {
247
    final File file = fileSystem.file(fileSystem.path.join(flutterTools, 'bin', 'tool_backend.dart'));
248 249
    for (final String line in file.readAsLinesSync()) {
      if (line.startsWith(RegExp(r'import.*package:.*'))) {
250
        final String relativePath = fileSystem.path.relative(file.path, from:flutterTools);
251 252 253 254
        fail('$relativePath imports a package');
      }
    }
  });
255
}
256

257
bool _isDartFile(FileSystemEntity entity) => entity is File && entity.path.endsWith('.dart');
258

259
File _asFile(FileSystemEntity entity) => entity as File;