Prevent tests from importing other tests. (#27800)

This pattern is problematic when Flutter is ported to build systems
that require each executable end-point to be self-contained (e.g.
Bazel).
diff --git a/.cirrus.yml b/.cirrus.yml
index eead250..83af9d1 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -46,12 +46,12 @@
       test_script: ./dev/bots/deploy_gallery.sh
     - name: analyze
       test_script:
-        - dart ./dev/bots/analyze.dart
+        - dart --enable-asserts ./dev/bots/analyze.dart
     - name: tests-linux
       env:
         SHARD: tests
       test_script:
-        - dart ./dev/bots/test.dart
+        - dart --enable-asserts ./dev/bots/test.dart
       container:
         cpu: 4
         memory: 12G
@@ -59,7 +59,7 @@
       env:
         SHARD: tool_tests
       test_script:
-        - dart ./dev/bots/test.dart
+        - dart --enable-asserts ./dev/bots/test.dart
       container:
         cpu: 4
         memory: 12G
@@ -77,7 +77,7 @@
         - echo "$CIRRUS_COMMIT_MESSAGE" > /tmp/cirrus_commit_message.txt
         - export CIRRUS_CHANGE_MESSAGE=""
         - export CIRRUS_COMMIT_MESSAGE=""
-        - dart ./dev/bots/test.dart
+        - dart --enable-asserts ./dev/bots/test.dart
         - export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt`
         - export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt`
       container:
@@ -192,7 +192,7 @@
     - bin/flutter update-packages
   test_all_script: |
     ulimit -S -n 2048 # https://github.com/flutter/flutter/issues/2976
-    bin/cache/dart-sdk/bin/dart -c dev/bots/test.dart
+    bin/cache/dart-sdk/bin/dart --enable-asserts dev/bots/test.dart
   matrix:
     - name: tests-macos
       env:
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart
index 1d3f475..448ae55 100644
--- a/dev/bots/analyze.dart
+++ b/dev/bots/analyze.dart
@@ -24,6 +24,13 @@
 /// For example:
 /// bin/cache/dart-sdk/bin/dart dev/bots/analyze.dart --dart-sdk=/tmp/dart-sdk
 Future<void> main(List<String> args) async {
+  bool assertsEnabled = false;
+  assert(() { assertsEnabled = true; return true; }());
+  if (!assertsEnabled) {
+    print('The analyze.dart script must be run with --enable-asserts.');
+    exit(1);
+  }
+  await _verifyNoTestImports(flutterRoot);
   await _verifyNoTestPackageImports(flutterRoot);
   await _verifyGeneratedPluginRegistrants(flutterRoot);
   await _verifyNoBadImportsInFlutter(flutterRoot);
@@ -339,8 +346,11 @@
   // Verify that the imports are well-ordered.
   final Map<String, Set<String>> dependencyMap = <String, Set<String>>{};
   for (String directory in directories) {
-    dependencyMap[directory] = _findDependencies(path.join(srcPath, directory), errors, checkForMeta: directory != 'foundation');
+    dependencyMap[directory] = _findFlutterDependencies(path.join(srcPath, directory), errors, checkForMeta: directory != 'foundation');
   }
+  assert(dependencyMap['material'].contains('widgets') &&
+         dependencyMap['widgets'].contains('rendering') &&
+         dependencyMap['rendering'].contains('painting')); // to make sure we're convinced _findFlutterDependencies is finding some
   for (String package in dependencyMap.keys) {
     if (dependencyMap[package].contains(package)) {
       errors.add(
@@ -384,9 +394,9 @@
 }
 
 final RegExp _importPattern = RegExp(r'''^\s*import (['"])package:flutter/([^.]+)\.dart\1''');
-final RegExp _importMetaPattern = RegExp(r'''^\s*import (['"])package:meta/meta.dart\1''');
+final RegExp _importMetaPattern = RegExp(r'''^\s*import (['"])package:meta/meta\.dart\1''');
 
-Set<String> _findDependencies(String srcPath, List<String> errors, { bool checkForMeta = false }) {
+Set<String> _findFlutterDependencies(String srcPath, List<String> errors, { bool checkForMeta = false }) {
   return Directory(srcPath).listSync(recursive: true).where((FileSystemEntity entity) {
     return entity is File && path.extension(entity.path) == '.dart';
   }).map<Set<String>>((FileSystemEntity entity) {
@@ -462,6 +472,37 @@
   }
 }
 
+final RegExp _testImportPattern = RegExp(r'''import (['"])([^'"]+_test\.dart)\1''');
+const Set<String> _exemptTestImports = <String>{
+  'package:flutter_test/flutter_test.dart',
+  'hit_test.dart',
+  'package:test_api/src/backend/live_test.dart',
+};
+
+Future<void> _verifyNoTestImports(String workingDirectory) async {
+  final List<String> errors = <String>[];
+  assert("// foo\nimport 'binding_test.dart' as binding;\n'".contains(_testImportPattern));
+  for (FileSystemEntity entity in Directory(path.join(workingDirectory, 'packages'))
+    .listSync(recursive: true)
+    .where((FileSystemEntity entity) => entity is File && path.extension(entity.path) == '.dart')) {
+    final File file = entity;
+    for (String line in file.readAsLinesSync()) {
+      final Match match = _testImportPattern.firstMatch(line);
+      if (match != null && !_exemptTestImports.contains(match.group(2)))
+        errors.add(file.path);
+    }
+  }
+  // Fail if any errors
+  if (errors.isNotEmpty) {
+    print('$redLine');
+    final String s = errors.length == 1 ? '' : 's';
+    print('${bold}The following file$s import a test directly. Test utilities should be in their own file.$reset\n');
+    print(errors.join('\n'));
+    print('$redLine\n');
+    exit(1);
+  }
+}
+
 Future<void> _verifyGeneratedPluginRegistrants(String flutterRoot) async {
   final Directory flutterRootDir = Directory(flutterRoot);
 
diff --git a/packages/flutter/test/painting/binding_test.dart b/packages/flutter/test/painting/binding_test.dart
index ab24ca0..20f0ccc 100644
--- a/packages/flutter/test/painting/binding_test.dart
+++ b/packages/flutter/test/painting/binding_test.dart
@@ -1,30 +1,15 @@
+// Copyright 2014 The Chromium Authors. 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:typed_data' show Uint8List;
-import 'dart:ui' as ui show instantiateImageCodec, Codec;
 
 import 'package:flutter_test/flutter_test.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter/painting.dart';
-import 'package:flutter/foundation.dart';
-import 'package:flutter/services.dart';
 
-import '../painting/image_data.dart';
-
-class PaintingBindingSpy extends BindingBase with ServicesBinding, PaintingBinding {
-  int counter = 0;
-  int get instantiateImageCodecCalledCount => counter;
-
-  @override
-  Future<ui.Codec> instantiateImageCodec(Uint8List list) {
-    counter++;
-    return ui.instantiateImageCodec(list, decodedCacheRatioCap: decodedCacheRatioCap); // ignore: deprecated_member_use_from_same_package
-  }
-
-  @override
-  void initLicenses() {
-    // Do not include any licenses, because we're a test, and the LICENSE file
-    // doesn't get generated for tests.
-  }
-}
+import 'image_data.dart';
+import 'painting_utils.dart';
 
 void main() {
   final PaintingBindingSpy binding = PaintingBindingSpy();
diff --git a/packages/flutter/test/painting/image_decoder_test.dart b/packages/flutter/test/painting/image_decoder_test.dart
index a80726c..0d3c4a7 100644
--- a/packages/flutter/test/painting/image_decoder_test.dart
+++ b/packages/flutter/test/painting/image_decoder_test.dart
@@ -8,8 +8,8 @@
 import 'package:flutter/painting.dart';
 
 import '../flutter_test_alternative.dart';
-import 'binding_test.dart';
 import 'image_data.dart';
+import 'painting_utils.dart';
 
 void main() {
   final PaintingBindingSpy binding = PaintingBindingSpy();
diff --git a/packages/flutter/test/painting/painting_utils.dart b/packages/flutter/test/painting/painting_utils.dart
new file mode 100644
index 0000000..861c0a2
--- /dev/null
+++ b/packages/flutter/test/painting/painting_utils.dart
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. 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:typed_data';
+import 'dart:ui' as ui;
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/painting.dart';
+import 'package:flutter/services.dart';
+
+class PaintingBindingSpy extends BindingBase with ServicesBinding, PaintingBinding {
+  int counter = 0;
+  int get instantiateImageCodecCalledCount => counter;
+
+  @override
+  Future<ui.Codec> instantiateImageCodec(Uint8List list) {
+    counter++;
+    return ui.instantiateImageCodec(list, decodedCacheRatioCap: decodedCacheRatioCap); // ignore: deprecated_member_use_from_same_package
+  }
+
+  @override
+  void initLicenses() {
+    // Do not include any licenses, because we're a test, and the LICENSE file
+    // doesn't get generated for tests.
+  }
+}
diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart
index 9f5c4a8..d2f7839 100644
--- a/packages/flutter/test/widgets/editable_text_cursor_test.dart
+++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart
@@ -11,7 +11,13 @@
 import 'package:flutter/services.dart';
 
 import '../rendering/mock_canvas.dart';
-import 'editable_text_test.dart';
+import 'editable_text_utils.dart';
+
+final TextEditingController controller = TextEditingController();
+final FocusNode focusNode = FocusNode();
+final FocusScopeNode focusScopeNode = FocusScopeNode();
+const TextStyle textStyle = TextStyle();
+const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00);
 
 void main() {
   testWidgets('cursor has expected width and radius', (WidgetTester tester) async {
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 4a5b4a9..73841fb 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -12,25 +12,9 @@
 import 'package:mockito/mockito.dart';
 import 'package:flutter/foundation.dart';
 
+import 'editable_text_utils.dart';
 import 'semantics_tester.dart';
 
-RenderEditable findRenderEditable(WidgetTester tester) {
-  final RenderObject root = tester.renderObject(find.byType(EditableText));
-  expect(root, isNotNull);
-
-  RenderEditable renderEditable;
-  void recursiveFinder(RenderObject child) {
-    if (child is RenderEditable) {
-      renderEditable = child;
-      return;
-    }
-    child.visitChildren(recursiveFinder);
-  }
-  root.visitChildren(recursiveFinder);
-  expect(renderEditable, isNotNull);
-  return renderEditable;
-}
-
 final TextEditingController controller = TextEditingController();
 final FocusNode focusNode = FocusNode();
 final FocusScopeNode focusScopeNode = FocusScopeNode();
diff --git a/packages/flutter/test/widgets/editable_text_utils.dart b/packages/flutter/test/widgets/editable_text_utils.dart
new file mode 100644
index 0000000..8601f74
--- /dev/null
+++ b/packages/flutter/test/widgets/editable_text_utils.dart
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. 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:flutter/rendering.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+
+RenderEditable findRenderEditable(WidgetTester tester) {
+  final RenderObject root = tester.renderObject(find.byType(EditableText));
+  expect(root, isNotNull);
+
+  RenderEditable renderEditable;
+  void recursiveFinder(RenderObject child) {
+    if (child is RenderEditable) {
+      renderEditable = child;
+      return;
+    }
+    child.visitChildren(recursiveFinder);
+  }
+  root.visitChildren(recursiveFinder);
+  expect(renderEditable, isNotNull);
+  return renderEditable;
+}
diff --git a/packages/flutter_tools/test/runner/flutter_command_runner_test.dart b/packages/flutter_tools/test/runner/flutter_command_runner_test.dart
index f1a366f..563d480 100644
--- a/packages/flutter_tools/test/runner/flutter_command_runner_test.dart
+++ b/packages/flutter_tools/test/runner/flutter_command_runner_test.dart
@@ -17,7 +17,7 @@
 
 import '../src/common.dart';
 import '../src/context.dart';
-import 'flutter_command_test.dart';
+import 'utils.dart';
 
 const String _kFlutterRoot = '/flutter/flutter';
 const String _kEngineRoot = '/flutter/engine';
diff --git a/packages/flutter_tools/test/runner/flutter_command_test.dart b/packages/flutter_tools/test/runner/flutter_command_test.dart
index 4b6499d..3b14447 100644
--- a/packages/flutter_tools/test/runner/flutter_command_test.dart
+++ b/packages/flutter_tools/test/runner/flutter_command_test.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:async';
-
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/base/time.dart';
 import 'package:flutter_tools/src/usage.dart';
@@ -13,19 +11,19 @@
 
 import '../src/common.dart';
 import '../src/context.dart';
+import 'utils.dart';
+
 void main() {
-
   group('Flutter Command', () {
-
-    MockCache cache;
+    MockitoCache cache;
+    MockitoUsage usage;
     MockClock clock;
-    MockUsage usage;
     List<int> mockTimes;
 
     setUp(() {
-      cache = MockCache();
+      cache = MockitoCache();
+      usage = MockitoUsage();
       clock = MockClock();
-      usage = MockUsage();
       when(usage.isFirstRun).thenReturn(false);
       when(clock.now()).thenAnswer(
         (Invocation _) => DateTime.fromMillisecondsSinceEpoch(mockTimes.removeAt(0))
@@ -157,40 +155,4 @@
     });
 
   });
-
 }
-
-typedef CommandFunction = Future<FlutterCommandResult> Function();
-
-class DummyFlutterCommand extends FlutterCommand {
-
-  DummyFlutterCommand({
-    this.shouldUpdateCache  = false,
-    this.noUsagePath  = false,
-    this.commandFunction,
-  });
-
-  final bool noUsagePath;
-  final CommandFunction commandFunction;
-
-  @override
-  final bool shouldUpdateCache;
-
-  @override
-  String get description => 'does nothing';
-
-  @override
-  Future<String> get usagePath => noUsagePath ? null : super.usagePath;
-
-  @override
-  String get name => 'dummy';
-
-  @override
-  Future<FlutterCommandResult> runCommand() async {
-    return commandFunction == null ? null : await commandFunction();
-  }
-}
-
-class MockCache extends Mock implements Cache {}
-
-class MockUsage extends Mock implements Usage {}
diff --git a/packages/flutter_tools/test/runner/utils.dart b/packages/flutter_tools/test/runner/utils.dart
new file mode 100644
index 0000000..b7b1ec1
--- /dev/null
+++ b/packages/flutter_tools/test/runner/utils.dart
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. 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 'package:flutter_tools/src/cache.dart';
+import 'package:flutter_tools/src/usage.dart';
+import 'package:flutter_tools/src/runner/flutter_command.dart';
+import 'package:mockito/mockito.dart';
+
+typedef CommandFunction = Future<FlutterCommandResult> Function();
+
+class DummyFlutterCommand extends FlutterCommand {
+
+  DummyFlutterCommand({
+    this.shouldUpdateCache  = false,
+    this.noUsagePath  = false,
+    this.commandFunction,
+  });
+
+  final bool noUsagePath;
+  final CommandFunction commandFunction;
+
+  @override
+  final bool shouldUpdateCache;
+
+  @override
+  String get description => 'does nothing';
+
+  @override
+  Future<String> get usagePath => noUsagePath ? null : super.usagePath;
+
+  @override
+  String get name => 'dummy';
+
+  @override
+  Future<FlutterCommandResult> runCommand() async {
+    return commandFunction == null ? null : await commandFunction();
+  }
+}
+
+class MockitoCache extends Mock implements Cache {}
+
+class MockitoUsage extends Mock implements Usage {}