anchor.diff:    }
   }
   
  +class BaseTest {
  +  static const emptyOptionsFile = 'data/empty_options.yaml';
  +
  +  StringSink _savedOutSink, _savedErrorSink;
  +  int _savedExitCode;
  +  ExitHandler _savedExitHandler;
  +
  +  Driver driver;
  +
  +  AnalysisOptions get analysisOptions => driver.analysisDriver.analysisOptions;
  +
  +  bool get usePreviewDart2 => false;
  +
  +  /// Normalize text with bullets.
  +  String bulletToDash(item) => '$item'.replaceAll('•', '-');
  +
  +  /// Start a driver for the given [source], optionally providing additional
  +  /// [args] and an [options] file path. The value of [options] defaults to an
  +  /// empty options file to avoid unwanted configuration from an otherwise
  +  /// discovered options file.
  +  Future<void> drive(
  +    String source, {
  +    String options: emptyOptionsFile,
  +    List<String> args: const <String>[],
  +  }) {
  +    return driveMany([source], options: options, args: args);
  +  }
  +
  +  /// Like [drive], but takes an array of sources.
  +  Future<void> driveMany(
  +    List<String> sources, {
  +    String options: emptyOptionsFile,
  +    List<String> args: const <String>[],
  +  }) async {
  +    options = _p(options);
  +
  +    driver = new Driver(isTesting: true);
  +    var cmd = <String>[];
  +    if (options != null) {
  +      cmd = <String>[
  +        '--options',
  +        path.join(testDirectory, options),
  +      ];
  +    }
  +    cmd..addAll(sources.map(_adjustFileSpec))..addAll(args);
  +    if (usePreviewDart2) {
  +      cmd.insert(0, '--preview-dart-2');
  +    }
  +
  +    await driver.start(cmd);
  +  }
  +
  +  void setUp() {
  +    ansi.runningTests = true;
  +    _savedOutSink = outSink;
  +    _savedErrorSink = errorSink;
  +    _savedExitHandler = exitHandler;
  +    _savedExitCode = exitCode;
  +    exitHandler = (code) => exitCode = code;
  +    outSink = new StringBuffer();
  +    errorSink = new StringBuffer();
  +  }
  +
  +  void tearDown() {
  +    outSink = _savedOutSink;
  +    errorSink = _savedErrorSink;
  +    exitCode = _savedExitCode;
  +    exitHandler = _savedExitHandler;
  +    ansi.runningTests = false;
  +  }
  +
  +  /// Convert a file specification from a relative path to an absolute path.
  +  /// Handles the case where the file specification is of the form "$uri|$path".
  +  String _adjustFileSpec(String fileSpec) {
  +    int uriPrefixLength = fileSpec.indexOf('|') + 1;
  +    String uriPrefix = fileSpec.substring(0, uriPrefixLength);
  +    String relativePath = fileSpec.substring(uriPrefixLength);
  +    return '$uriPrefix${path.join(testDirectory, relativePath)}';
  +  }
  +
  +  /**
  +   * Convert the given posix [filePath] to conform to this provider's path context.
  +   *
  +   * This is a utility method for testing; paths passed in to other methods in
  +   * this class are never converted automatically.
  +   */
  +  String _p(String filePath) {
  +    if (filePath == null) {
  +      return null;
  +    }
  +    if (path.style == path.windows.style) {
  +      filePath =
  +          filePath.replaceAll(path.posix.separator, path.windows.separator);
  +    }
  +    return filePath;
  +  }
  +}
  +
  +@reflectiveTest
  +class BuildModeSummaryDependenciesTest extends AbstractBuildModeTest {
  +  String tempDir;
  +
  +  /// Any direct export is a dependency.
  +  test_export_direct() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], 'class A {}');
  +      await _assertDependencies('c', [a], '''
  +export 'package:a/a.dart';
  +''', [a]);
  +    });
  +  }
  +
  +  /// Imports of dependencies are not necessary dependencies.
  +  /// Here our dependency does not use its dependency.
  +  test_import2_notUsed() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], '');
  +      var b = await _buildPackage('b', [a], '''
  +import 'package:a/a.dart';
  +''');
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +''', [b]);
  +    });
  +  }
  +
  +  test_import2_usedAsFieldType() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], 'class A {}');
  +      var b = await _buildPackage('b', [a], '''
  +import 'package:a/a.dart';
  +class B {
  +  A f;
  +}
  +''');
  +
  +      // We don't use `f`, so don't depend on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +var x = B();
  +''', [b]);
  +
  +      // We use `f` for type inference.
  +      // So, dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +var x = B().f;
  +''', [a, b]);
  +
  +      // We reference `f` in initializer, but not for type inference.
  +      // So, no dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +Object x = B().f;
  +''', [b]);
  +
  +      // We perform full analysis, so request the type of `f`;
  +      // So, dependency on "a".
  +      await _assertDependencies(
  +        'c',
  +        [a, b],
  +        '''
  +import 'package:b/b.dart';
  +Object x = B().f;
  +''',
  +        [a, b],
  +        summaryOnly: false,
  +      );
  +    });
  +  }
  +
  +  test_import2_usedAsSupertype() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], 'class A {}');
  +      var b = await _buildPackage('b', [a], '''
  +import 'package:a/a.dart';
  +class B extends A {}
  +''');
  +
  +      // We don't invoke anything on class `B`, so don't ask its supertype.
  +      // So, no dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +B x;
  +''', [b]);
  +
  +      // We infer the type of `x` to `B`.
  +      // But we don't ask `B` for its supertype.
  +      // So, no dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +var x = B();
  +''', [b]);
  +
  +      // We perform full analysis, and check that `new B()` is assignable
  +      // to `B x`. While doing this, we ask for `B` supertype.
  +      // So, dependency on "a".
  +      await _assertDependencies(
  +        'c',
  +        [a, b],
  +        '''
  +import 'package:b/b.dart';
  +var x = B();
  +''',
  +        [a, b],
  +        summaryOnly: false,
  +      );
  +    });
  +  }
  +
  +  test_import2_usedAsTopLevelVariableType() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], 'class A {}');
  +      var b = await _buildPackage('b', [a], '''
  +import 'package:a/a.dart';
  +A v;
  +''');
  +
  +      // We don't use `v`.
  +      // So, no dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +''', [b]);
  +
  +      // We use `v` for type inference.
  +      // So, dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +var x = v;
  +''', [a, b]);
  +
  +      // We don't use `v` for type inference.
  +      // So, no dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +Object x = v;
  +''', [b]);
  +
  +      // We perform full analysis, and request the type of `v`.
  +      // So, dependency on "a".
  +      await _assertDependencies(
  +        'c',
  +        [a, b],
  +        '''
  +import 'package:b/b.dart';
  +Object x = v;
  +''',
  +        [a, b],
  +        summaryOnly: false,
  +      );
  +
  +      // We use `v` in a method body.
  +      // So, no dependency on "a".
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +main() {
  +  v;
  +}
  +''', [b]);
  +
  +      // We perform full analysis, so ask for the type of `v`.
  +      // So, dependency on "a".
  +      await _assertDependencies(
  +        'c',
  +        [a, b],
  +        '''
  +import 'package:b/b.dart';
  +main() {
  +  v;
  +}
  +''',
  +        [a, b],
  +        summaryOnly: false,
  +      );
  +    });
  +  }
  +
  +  /// Any direct import is a dependency.
  +  test_import_direct() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], '');
  +      var b = await _buildPackage('b', [], '');
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:a/a.dart';
  +import 'package:b/b.dart';
  +''', [a, b]);
  +    });
  +  }
  +
  +  /// Exports of dependencies are dependencies.
  +  test_import_export() async {
  +    await _withTempDir(() async {
  +      var a = await _buildPackage('a', [], 'class A {}');
  +      var b = await _buildPackage('b', [a], '''
  +export 'package:a/a.dart';
  +''');
  +      await _assertDependencies('c', [a, b], '''
  +import 'package:b/b.dart';
  +''', [a, b]);
  +    });
  +  }
  +
  +  Future<void> _assertDependencies(
  +    String name,
  +    List<_DependencyPackage> inputPackages,
  +    String content,
  +    List<_DependencyPackage> expectedPackages, {
  +    bool summaryOnly = true,
  +  }) async {
  +    var pkg = await _buildPackage(name, inputPackages, content,
  +        summaryOnly: summaryOnly);
  +
  +    var depString = File(pkg.dep).readAsStringSync();
  +    var expectedList = expectedPackages.map((p) => p.sum).toList();
  +    expect(depString.split('\n'), unorderedEquals(expectedList));
  +  }
  +
  +  Future<_DependencyPackage> _buildPackage(
  +    String name,
  +    List<_DependencyPackage> inputPackages,
  +    String content, {
  +    bool summaryOnly = true,
  +  }) async {
  +    var filePath = path.join(tempDir, '$name.dart');
  +    File(filePath).writeAsStringSync(content);
  +    var pkg = _DependencyPackage(
  +      name: name,
  +      path: filePath,
  +      uri: 'package:$name/$name.dart',
  +      sum: path.join(tempDir, '$name.sum'),
  +      dep: path.join(tempDir, '$name.dep'),
  +    );
  +
  +    var args = <String>[];
  +    if (summaryOnly) {
  +      args.add('--build-summary-only');
  +    }
  +    for (var input in inputPackages) {
  +      args.add('--build-summary-input=${input.sum}');
  +    }
  +    args.add('--build-summary-output=${pkg.sum}');
  +    args.add('--summary-deps-output=${pkg.dep}');
  +
  +    await _doDrive(pkg.path, uri: pkg.uri, additionalArgs: args);
  +    expect(exitCode, 0);
  +
  +    return pkg;
  +  }
  +
  +  Future<void> _withTempDir(Future<void> f()) async {
  +    await withTempDirAsync((tempDir) async {
  +      this.tempDir = tempDir;
  +      await f();
  +    });
  +  }
  +}
  +
  +@reflectiveTest
  +class BuildModeTest extends AbstractBuildModeTest {
  +  test_buildLinked() async {
  +    await withTempDirAsync((tempDir) async {
  +      var outputPath = path.join(tempDir, 'test_file.dart.sum');
  +      await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
  +        '--build-summary-only',
  +        '--build-summary-output=$outputPath'
  +      ]);
  +      var output = new File(outputPath);
  +      expect(output.existsSync(), isTrue);
  +      PackageBundle bundle =
  +          new PackageBundle.fromBuffer(await output.readAsBytes());
  +      var testFileUri = 'file:///test_file.dart';
  +      expect(bundle.unlinkedUnitUris, equals([testFileUri]));
  +      expect(bundle.linkedLibraryUris, equals([testFileUri]));
  +      expect(exitCode, 0);
  +    });
  +  }
  +
  +  test_buildLinked_buildSummaryOutputSemantic() async {
  +    await withTempDirAsync((tempDir) async {
  +      var testDart = path.join(tempDir, 'test.dart');
  +      var testSumFull = path.join(tempDir, 'test.sum.full');
  +      var testSumSemantic = path.join(tempDir, 'test.sum.sem');
  +
  +      new File(testDart).writeAsStringSync('var v = 42;');
  +
  +      await _doDrive(testDart, additionalArgs: [
  +        '--build-summary-only',
  +        '--build-summary-output=$testSumFull',
  +        '--build-summary-output-semantic=$testSumSemantic',
  +      ]);
  +      expect(exitCode, 0);
  +
  +      // The full summary is produced.
  +      {
  +        var file = new File(testSumFull);
  +        expect(file.existsSync(), isTrue);
  +        var bytes = file.readAsBytesSync();
  +        var bundle = new PackageBundle.fromBuffer(bytes);
  +        var v = bundle.unlinkedUnits[0].variables[0];
  +        expect(v.name, 'v');
  +        expect(v.nameOffset, 4);
  +      }
  +
  +      // The semantic summary is produced.
  +      {
  +        var file = new File(testSumSemantic);
  +        expect(file.existsSync(), isTrue);
  +        var bytes = file.readAsBytesSync();
  +        var bundle = new PackageBundle.fromBuffer(bytes);
  +        var v = bundle.unlinkedUnits[0].variables[0];
  +        expect(v.name, 'v');
  +        expect(v.nameOffset, 0);
  +      }
  +    });
  +  }
  +
  +  test_buildLinked_fromUnlinked() async {
  +    await withTempDirAsync((tempDir) async {
  +      var aDart = path.join(tempDir, 'a.dart');
  +      var bDart = path.join(tempDir, 'b.dart');
  +
  +      var aUri = 'package:aaa/a.dart';
  +      var bUri = 'package:bbb/b.dart';
  +
  +      var aUnlinked = path.join(tempDir, 'a.unlinked');
  +      var bUnlinked = path.join(tempDir, 'b.unlinked');
  +      var abLinked = path.join(tempDir, 'ab.linked');
  +
  +      new File(aDart).writeAsStringSync('var a = 1;');
  +      new File(bDart).writeAsStringSync('''
  +import 'package:aaa/a.dart';
  +var b = a;
  +''');
  +
  +      Future<void> buildUnlinked(String uri, String path, String output) async {
  +        await _doDrive(path, uri: uri, additionalArgs: [
  +          '--build-summary-only',
  +          '--build-summary-only-unlinked',
  +          '--build-summary-output=$output'
  +        ]);
  +        expect(exitCode, 0);
  +        expect(new File(output).existsSync(), isTrue);
  +      }
  +
  +      await buildUnlinked(aUri, aDart, aUnlinked);
  +      await buildUnlinked(bUri, bDart, bUnlinked);
  +
  +      await new Driver(isTesting: true).start([
  +        '--dart-sdk',
  +        _findSdkDirForSummaries(),
  +        '--build-mode',
  +        '--build-summary-unlinked-input=$aUnlinked,$bUnlinked',
  +        '--build-summary-output=$abLinked'
  +      ]);
  +      expect(exitCode, 0);
  +      var bytes = new File(abLinked).readAsBytesSync();
  +      var bundle = new PackageBundle.fromBuffer(bytes);
  +
  +      // Only linked information.
  +      expect(bundle.unlinkedUnitUris, isEmpty);
  +      expect(bundle.linkedLibraryUris, unorderedEquals([aUri, bUri]));
  +
  +      // Strong mode type inference was performed.
  +      expect(bundle.linkedLibraries[0].units[0].types, isNotEmpty);
  +      expect(bundle.linkedLibraries[1].units[0].types, isNotEmpty);
  +    });
  +  }
  +
  +  test_buildSuppressExitCode_fail_whenFileNotFound() async {
  +    await _doDrive(path.join('data', 'non_existent_file.dart'),
  +        additionalArgs: ['--build-suppress-exit-code']);
  +    expect(exitCode, isNot(0));
  +  }
  +
  +  test_buildSuppressExitCode_success_evenIfHasError() async {
  +    await _doDrive(path.join('data', 'file_with_error.dart'),
  +        additionalArgs: ['--build-suppress-exit-code']);
  +    expect(exitCode, 0);
  +  }
  +
  +  test_buildUnlinked() async {
  +    await withTempDirAsync((tempDir) async {
  +      var outputPath = path.join(tempDir, 'test_file.dart.sum');
  +      await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
  +        '--build-summary-only',
  +        '--build-summary-only-unlinked',
  +        '--build-summary-output=$outputPath'
  +      ]);
  +      var output = new File(outputPath);
  +      expect(output.existsSync(), isTrue);
  +      PackageBundle bundle =
  +          new PackageBundle.fromBuffer(await output.readAsBytes());
  +      var testFileUri = 'file:///test_file.dart';
  +      expect(bundle.unlinkedUnits.length, 1);
  +      expect(bundle.unlinkedUnitUris, equals([testFileUri]));
  +      expect(bundle.linkedLibraryUris, isEmpty);
  +      expect(exitCode, 0);
  +    });
  +  }
  +
  +  test_consumeLinked() async {
  +    await withTempDirAsync((tempDir) async {
  +      var aDart = path.join(tempDir, 'a.dart');
  +      var bDart = path.join(tempDir, 'b.dart');
  +      var cDart = path.join(tempDir, 'c.dart');
  +
  +      var aUri = 'package:aaa/a.dart';
  +      var bUri = 'package:bbb/b.dart';
  +      var cUri = 'package:ccc/c.dart';
  +
  +      var aSum = path.join(tempDir, 'a.sum');
  +      var bSum = path.join(tempDir, 'b.sum');
  +      var cSum = path.join(tempDir, 'c.sum');
  +
  +      new File(aDart).writeAsStringSync('class A {}');
  +      new File(bDart).writeAsStringSync('''
  +export 'package:aaa/a.dart';
  +class B {}
  +''');
  +      new File(cDart).writeAsStringSync('''
  +import 'package:bbb/b.dart';
  +var a = new A();
  +var b = new B();
  +''');
  +
  +      // Analyze package:aaa/a.dart and compute summary.
  +      {
  +        await _doDrive(aDart,
  +            uri: aUri, additionalArgs: ['--build-summary-output=$aSum']);
  +        expect(exitCode, 0);
  +        var bytes = new File(aSum).readAsBytesSync();
  +        var bundle = new PackageBundle.fromBuffer(bytes);
  +        expect(bundle.unlinkedUnitUris, equals([aUri]));
  +        expect(bundle.linkedLibraryUris, equals([aUri]));
  +      }
  +
  +      // Analyze package:bbb/b.dart and compute summary.
  +      {
  +        await _doDrive(bDart, uri: bUri, additionalArgs: [
  +          '--build-summary-input=$aSum',
  +          '--build-summary-output=$bSum'
  +        ]);
  +        expect(exitCode, 0);
  +        var bytes = new File(bSum).readAsBytesSync();
  +        var bundle = new PackageBundle.fromBuffer(bytes);
  +        expect(bundle.unlinkedUnitUris, equals([bUri]));
  +        expect(bundle.linkedLibraryUris, equals([bUri]));
  +      }
  +
  +      // Analyze package:ccc/c.dart and compute summary.
  +      {
  +        await _doDrive(cDart, uri: cUri, additionalArgs: [
  +          '--build-summary-input=$aSum,$bSum',
  +          '--build-summary-output=$cSum'
  +        ]);
  +        expect(exitCode, 0);
  +        var bytes = new File(cSum).readAsBytesSync();
  +        var bundle = new PackageBundle.fromBuffer(bytes);
  +        expect(bundle.unlinkedUnitUris, equals([cUri]));
  +        expect(bundle.linkedLibraryUris, equals([cUri]));
  +      }
  +    });
  +  }
  +
  +  test_dartSdkSummaryPath_strong() async {
  +    await withTempDirAsync((tempDir) async {
  +      String sdkPath = _findSdkDirForSummaries();
  +      String strongSummaryPath =
  +          path.join(sdkPath, 'lib', '_internal', 'strong.sum');
  +
  +      var testDart = path.join(tempDir, 'test.dart');
  +      var testSum = path.join(tempDir, 'test.sum');
  +      new File(testDart).writeAsStringSync('var v = 42;');
  +
  +      await _doDrive(testDart,
  +          additionalArgs: [
  +            '--build-summary-only',
  +            '--build-summary-output=$testSum'
  +          ],
  +          dartSdkSummaryPath: strongSummaryPath);
  +      var output = new File(testSum);
  +      expect(output.existsSync(), isTrue);
  +      expect(exitCode, 0);
  +    });
  +  }
  +
  +  test_error_linkedAsUnlinked() async {
  +    await withTempDirAsync((tempDir) async {
  +      var aDart = path.join(tempDir, 'a.dart');
  +      var bDart = path.join(tempDir, 'b.dart');
  +
  +      var aUri = 'package:aaa/a.dart';
  +      var bUri = 'package:bbb/b.dart';
  +
  +      var aSum = path.join(tempDir, 'a.sum');
  +      var bSum = path.join(tempDir, 'b.sum');
  +
  +      new File(aDart).writeAsStringSync('class A {}');
  +
  +      // Build linked a.sum
  +      await _doDrive(aDart, uri: aUri, additionalArgs: [
  +        '--build-summary-only',
  +        '--build-summary-output=$aSum'
  +      ]);
  +      expect(new File(aSum).existsSync(), isTrue);
  +
  +      // Try to consume linked a.sum as unlinked.
  +      try {
  +        await _doDrive(bDart, uri: bUri, additionalArgs: [
  +          '--build-summary-unlinked-input=$aSum',
  +          '--build-summary-output=$bSum'
  +        ]);
  +        fail('ArgumentError expected.');
  +      } on ArgumentError catch (e) {
  +        expect(
  +            e.message,
  +            contains(
  +                'Got a linked summary for --build-summary-input-unlinked'));
  +      }
  +    });
  +  }
  +
  +  test_error_notUriPipePath() async {
  +    await withTempDirAsync((tempDir) async {
  +      var testDart = path.join(tempDir, 'test.dart');
  +      new File(testDart).writeAsStringSync('var v = 42;');
  +
  +      // We pass just path, not "uri|path", this is a fatal error.
  +      await drive(testDart, args: ['--build-mode', '--format=machine']);
  +      expect(exitCode, ErrorSeverity.ERROR.ordinal);
  +    });
  +  }
  +
  +  test_error_unlinkedAsLinked() async {
  +    await withTempDirAsync((tempDir) async {
  +      var aDart = path.join(tempDir, 'a.dart');
  +      var bDart = path.join(tempDir, 'b.dart');
  +
  +      var aUri = 'package:aaa/a.dart';
  +      var bUri = 'package:bbb/b.dart';
  +
  +      var aSum = path.join(tempDir, 'a.sum');
  +      var bSum = path.join(tempDir, 'b.sum');
  +
  +      new File(aDart).writeAsStringSync('class A {}');
  +
  +      // Build unlinked a.sum
  +      await _doDrive(aDart, uri: aUri, additionalArgs: [
  +        '--build-summary-only',
  +        '--build-summary-only-unlinked',
  +        '--build-summary-output=$aSum'
  +      ]);
  +      expect(new File(aSum).existsSync(), isTrue);
  +
  +      // Try to consume unlinked a.sum as linked.
  +      try {
  +        await _doDrive(bDart, uri: bUri, additionalArgs: [
  +          '--build-summary-input=$aSum',
  +          '--build-summary-output=$bSum'
  +        ]);
  +        fail('ArgumentError expected.');
  +      } on ArgumentError catch (e) {
  +        expect(e.message,
  +            contains('Got an unlinked summary for --build-summary-input'));
  +      }
  +    });
  +  }
  +
  +  test_fail_whenHasError() async {
  +    await _doDrive(path.join('data', 'file_with_error.dart'));
  +    expect(exitCode, isNot(0));
  +  }
  +
  +  test_noStatistics() async {
  +    await _doDrive(path.join('data', 'test_file.dart'));
  +    // Should not print statistics summary.
  +    expect(outSink.toString(), isEmpty);
  +    expect(errorSink.toString(), isEmpty);
  +    expect(exitCode, 0);
  +  }
  +
  +  test_onlyErrors_partFirst() async {
  +    await withTempDirAsync((tempDir) async {
  +      var aDart = path.join(tempDir, 'a.dart');
  +      var bDart = path.join(tempDir, 'b.dart');
  +
  +      var aUri = 'package:aaa/a.dart';
  +      var bUri = 'package:aaa/b.dart';
  +
  +      new File(aDart).writeAsStringSync(r'''
  +library lib;
  +part 'b.dart';
  +class A {}
  +''');
  +      new File(bDart).writeAsStringSync('''
  +part of lib;
  +class B {}
  +var a = new A();
  +var b = new B();
  +''');
  +
  +      // Analyze b.dart (part) and then a.dart (its library).
  +      // No errors should be reported - the part should know its library.
  +      await _doDrive(bDart, uri: bUri, additionalArgs: ['$aUri|$aDart']);
  +      expect(errorSink, isEmpty);
  +    });
  +  }
  +}
  +
   @reflectiveTest
   class ExitCodesTest extends BaseTest {
     test_bazelWorkspace_relativePath() async {
  
positive.code:   }, name: 'Driver');
  }
  
  class BaseTest {
    static const emptyOptionsFile = 'data/empty_options.yaml';
  
    StringSink _savedOutSink, _savedErrorSink;
    int _savedExitCode;
    ExitHandler _savedExitHandler;
  
    Driver driver;
  
    AnalysisOptions get analysisOptions => driver.analysisDriver.analysisOptions;
  
    bool get usePreviewDart2 => false;
  
    /// Normalize text with bullets.
    String bulletToDash(item) => '$item'.replaceAll('•', '-');
  
    /// Start a driver for the given [source], optionally providing additional
    /// [args] and an [options] file path. The value of [options] defaults to an
    /// empty options file to avoid unwanted configuration from an otherwise
    /// discovered options file.
    Future<void> drive(
      String source, {
      String options: emptyOptionsFile,
      List<String> args: const <String>[],
    }) {
      return driveMany([source], options: options, args: args);
    }
  
    /// Like [drive], but takes an array of sources.
    Future<void> driveMany(
      List<String> sources, {
      String options: emptyOptionsFile,
      List<String> args: const <String>[],
    }) async {
      options = _p(options);
  
      driver = new Driver(isTesting: true);
      var cmd = <String>[];
      if (options != null) {
        cmd = <String>[
          '--options',
          path.join(testDirectory, options),
        ];
      }
      cmd..addAll(sources.map(_adjustFileSpec))..addAll(args);
      if (usePreviewDart2) {
        cmd.insert(0, '--preview-dart-2');
      }
  
      await driver.start(cmd);
    }
  
    void setUp() {
      ansi.runningTests = true;
      _savedOutSink = outSink;
      _savedErrorSink = errorSink;
      _savedExitHandler = exitHandler;
      _savedExitCode = exitCode;
      exitHandler = (code) => exitCode = code;
      outSink = new StringBuffer();
      errorSink = new StringBuffer();
    }
  
    void tearDown() {
      outSink = _savedOutSink;
      errorSink = _savedErrorSink;
      exitCode = _savedExitCode;
      exitHandler = _savedExitHandler;
      ansi.runningTests = false;
    }
  
    /// Convert a file specification from a relative path to an absolute path.
    /// Handles the case where the file specification is of the form "$uri|$path".
    String _adjustFileSpec(String fileSpec) {
      int uriPrefixLength = fileSpec.indexOf('|') + 1;
      String uriPrefix = fileSpec.substring(0, uriPrefixLength);
      String relativePath = fileSpec.substring(uriPrefixLength);
      return '$uriPrefix${path.join(testDirectory, relativePath)}';
    }
  
    /**
     * Convert the given posix [filePath] to conform to this provider's path context.
     *
     * This is a utility method for testing; paths passed in to other methods in
     * this class are never converted automatically.
     */
    String _p(String filePath) {
      if (filePath == null) {
        return null;
      }
      if (path.style == path.windows.style) {
        filePath =
            filePath.replaceAll(path.posix.separator, path.windows.separator);
      }
      return filePath;
    }
  }
  
  @reflectiveTest
  class BuildModeTest extends BaseTest {
    test_buildLinked() async {
      await withTempDirAsync((tempDir) async {
        var outputPath = path.join(tempDir, 'test_file.dart.sum');
        await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
          '--build-summary-only',
          '--build-summary-output=$outputPath'
        ]);
        var output = new File(outputPath);
        expect(output.existsSync(), isTrue);
        PackageBundle bundle =
            new PackageBundle.fromBuffer(await output.readAsBytes());
        var testFileUri = 'file:///test_file.dart';
        expect(bundle.unlinkedUnitUris, equals([testFileUri]));
        expect(bundle.linkedLibraryUris, equals([testFileUri]));
        expect(exitCode, 0);
      });
    }
  
    test_buildLinked_buildSummaryOutputSemantic() async {
      await withTempDirAsync((tempDir) async {
        var testDart = path.join(tempDir, 'test.dart');
        var testSumFull = path.join(tempDir, 'test.sum.full');
        var testSumSemantic = path.join(tempDir, 'test.sum.sem');
  
        new File(testDart).writeAsStringSync('var v = 42;');
  
        await _doDrive(testDart, additionalArgs: [
          '--build-summary-only',
          '--build-summary-output=$testSumFull',
          '--build-summary-output-semantic=$testSumSemantic',
        ]);
        expect(exitCode, 0);
  
        // The full summary is produced.
        {
          var file = new File(testSumFull);
          expect(file.existsSync(), isTrue);
          var bytes = file.readAsBytesSync();
          var bundle = new PackageBundle.fromBuffer(bytes);
          var v = bundle.unlinkedUnits[0].variables[0];
          expect(v.name, 'v');
          expect(v.nameOffset, 4);
        }
  
        // The semantic summary is produced.
        {
          var file = new File(testSumSemantic);
          expect(file.existsSync(), isTrue);
          var bytes = file.readAsBytesSync();
          var bundle = new PackageBundle.fromBuffer(bytes);
          var v = bundle.unlinkedUnits[0].variables[0];
          expect(v.name, 'v');
          expect(v.nameOffset, 0);
        }
      });
    }
  
    test_buildLinked_fromUnlinked() async {
      await withTempDirAsync((tempDir) async {
        var aDart = path.join(tempDir, 'a.dart');
        var bDart = path.join(tempDir, 'b.dart');
  
        var aUri = 'package:aaa/a.dart';
        var bUri = 'package:bbb/b.dart';
  
        var aUnlinked = path.join(tempDir, 'a.unlinked');
        var bUnlinked = path.join(tempDir, 'b.unlinked');
        var abLinked = path.join(tempDir, 'ab.linked');
  
        new File(aDart).writeAsStringSync('var a = 1;');
        new File(bDart).writeAsStringSync('''
  import 'package:aaa/a.dart';
  var b = a;
  ''');
  
        Future<void> buildUnlinked(String uri, String path, String output) async {
          await _doDrive(path, uri: uri, additionalArgs: [
            '--build-summary-only',
            '--build-summary-only-unlinked',
            '--build-summary-output=$output'
          ]);
          expect(exitCode, 0);
          expect(new File(output).existsSync(), isTrue);
        }
  
        await buildUnlinked(aUri, aDart, aUnlinked);
        await buildUnlinked(bUri, bDart, bUnlinked);
  
        await new Driver(isTesting: true).start([
          '--dart-sdk',
          _findSdkDirForSummaries(),
          '--build-mode',
          '--build-summary-unlinked-input=$aUnlinked,$bUnlinked',
          '--build-summary-output=$abLinked'
        ]);
        expect(exitCode, 0);
        var bytes = new File(abLinked).readAsBytesSync();
        var bundle = new PackageBundle.fromBuffer(bytes);
  
        // Only linked information.
        expect(bundle.unlinkedUnitUris, isEmpty);
        expect(bundle.linkedLibraryUris, unorderedEquals([aUri, bUri]));
  
        // Strong mode type inference was performed.
        expect(bundle.linkedLibraries[0].units[0].types, isNotEmpty);
        expect(bundle.linkedLibraries[1].units[0].types, isNotEmpty);
      });
    }
  
    test_buildSuppressExitCode_fail_whenFileNotFound() async {
      await _doDrive(path.join('data', 'non_existent_file.dart'),
          additionalArgs: ['--build-suppress-exit-code']);
      expect(exitCode, isNot(0));
    }
  
    test_buildSuppressExitCode_success_evenIfHasError() async {
      await _doDrive(path.join('data', 'file_with_error.dart'),
          additionalArgs: ['--build-suppress-exit-code']);
      expect(exitCode, 0);
    }
  
    test_buildUnlinked() async {
      await withTempDirAsync((tempDir) async {
        var outputPath = path.join(tempDir, 'test_file.dart.sum');
        await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
          '--build-summary-only',
          '--build-summary-only-unlinked',
          '--build-summary-output=$outputPath'
        ]);
        var output = new File(outputPath);
        expect(output.existsSync(), isTrue);
        PackageBundle bundle =
            new PackageBundle.fromBuffer(await output.readAsBytes());
        var testFileUri = 'file:///test_file.dart';
        expect(bundle.unlinkedUnits.length, 1);
        expect(bundle.unlinkedUnitUris, equals([testFileUri]));
        expect(bundle.linkedLibraryUris, isEmpty);
        expect(exitCode, 0);
      });
    }
  
    test_consumeLinked() async {
      await withTempDirAsync((tempDir) async {
        var aDart = path.join(tempDir, 'a.dart');
        var bDart = path.join(tempDir, 'b.dart');
        var cDart = path.join(tempDir, 'c.dart');
  
        var aUri = 'package:aaa/a.dart';
        var bUri = 'package:bbb/b.dart';
        var cUri = 'package:ccc/c.dart';
  
        var aSum = path.join(tempDir, 'a.sum');
        var bSum = path.join(tempDir, 'b.sum');
        var cSum = path.join(tempDir, 'c.sum');
  
        new File(aDart).writeAsStringSync('class A {}');
        new File(bDart).writeAsStringSync('''
  export 'package:aaa/a.dart';
  class B {}
  ''');
        new File(cDart).writeAsStringSync('''
  import 'package:bbb/b.dart';
  var a = new A();
  var b = new B();
  ''');
  
        // Analyze package:aaa/a.dart and compute summary.
        {
          await _doDrive(aDart,
              uri: aUri, additionalArgs: ['--build-summary-output=$aSum']);
          expect(exitCode, 0);
          var bytes = new File(aSum).readAsBytesSync();
          var bundle = new PackageBundle.fromBuffer(bytes);
          expect(bundle.unlinkedUnitUris, equals([aUri]));
          expect(bundle.linkedLibraryUris, equals([aUri]));
        }
  
        // Analyze package:bbb/b.dart and compute summary.
        {
          await _doDrive(bDart, uri: bUri, additionalArgs: [
            '--build-summary-input=$aSum',
            '--build-summary-output=$bSum'
          ]);
          expect(exitCode, 0);
          var bytes = new File(bSum).readAsBytesSync();
          var bundle = new PackageBundle.fromBuffer(bytes);
          expect(bundle.unlinkedUnitUris, equals([bUri]));
          expect(bundle.linkedLibraryUris, equals([bUri]));
        }
  
        // Analyze package:ccc/c.dart and compute summary.
        {
          await _doDrive(cDart, uri: cUri, additionalArgs: [
            '--build-summary-input=$aSum,$bSum',
            '--build-summary-output=$cSum'
          ]);
          expect(exitCode, 0);
          var bytes = new File(cSum).readAsBytesSync();
          var bundle = new PackageBundle.fromBuffer(bytes);
          expect(bundle.unlinkedUnitUris, equals([cUri]));
          expect(bundle.linkedLibraryUris, equals([cUri]));
        }
      });
    }
  
    test_dartSdkSummaryPath_strong() async {
      await withTempDirAsync((tempDir) async {
        String sdkPath = _findSdkDirForSummaries();
        String strongSummaryPath =
            path.join(sdkPath, 'lib', '_internal', 'strong.sum');
  
        var testDart = path.join(tempDir, 'test.dart');
        var testSum = path.join(tempDir, 'test.sum');
        new File(testDart).writeAsStringSync('var v = 42;');
  
        await _doDrive(testDart,
            additionalArgs: [
              '--build-summary-only',
              '--build-summary-output=$testSum'
            ],
            dartSdkSummaryPath: strongSummaryPath);
        var output = new File(testSum);
        expect(output.existsSync(), isTrue);
        expect(exitCode, 0);
      });
    }
  
    test_error_linkedAsUnlinked() async {
      await withTempDirAsync((tempDir) async {
        var aDart = path.join(tempDir, 'a.dart');
        var bDart = path.join(tempDir, 'b.dart');
  
        var aUri = 'package:aaa/a.dart';
        var bUri = 'package:bbb/b.dart';
  
        var aSum = path.join(tempDir, 'a.sum');
        var bSum = path.join(tempDir, 'b.sum');
  
        new File(aDart).writeAsStringSync('class A {}');
  
        // Build linked a.sum
        await _doDrive(aDart, uri: aUri, additionalArgs: [
          '--build-summary-only',
          '--build-summary-output=$aSum'
        ]);
        expect(new File(aSum).existsSync(), isTrue);
  
        // Try to consume linked a.sum as unlinked.
        try {
          await _doDrive(bDart, uri: bUri, additionalArgs: [
            '--build-summary-unlinked-input=$aSum',
            '--build-summary-output=$bSum'
          ]);
          fail('ArgumentError expected.');
        } on ArgumentError catch (e) {
          expect(
              e.message,
              contains(
                  'Got a linked summary for --build-summary-input-unlinked'));
        }
      });
    }
  
    test_error_notUriPipePath() async {
      await withTempDirAsync((tempDir) async {
        var testDart = path.join(tempDir, 'test.dart');
        new File(testDart).writeAsStringSync('var v = 42;');
  
        // We pass just path, not "uri|path", this is a fatal error.
        await drive(testDart, args: ['--build-mode', '--format=machine']);
        expect(exitCode, ErrorSeverity.ERROR.ordinal);
      });
    }
  
    test_error_unlinkedAsLinked() async {
      await withTempDirAsync((tempDir) async {
        var aDart = path.join(tempDir, 'a.dart');
        var bDart = path.join(tempDir, 'b.dart');
  
        var aUri = 'package:aaa/a.dart';
        var bUri = 'package:bbb/b.dart';
  
        var aSum = path.join(tempDir, 'a.sum');
        var bSum = path.join(tempDir, 'b.sum');
  
        new File(aDart).writeAsStringSync('class A {}');
  
        // Build unlinked a.sum
        await _doDrive(aDart, uri: aUri, additionalArgs: [
          '--build-summary-only',
          '--build-summary-only-unlinked',
          '--build-summary-output=$aSum'
        ]);
        expect(new File(aSum).existsSync(), isTrue);
  
        // Try to consume unlinked a.sum as linked.
        try {
          await _doDrive(bDart, uri: bUri, additionalArgs: [
            '--build-summary-input=$aSum',
            '--build-summary-output=$bSum'
          ]);
          fail('ArgumentError expected.');
        } on ArgumentError catch (e) {
          expect(e.message,
              contains('Got an unlinked summary for --build-summary-input'));
        }
      });
    }
  
    test_fail_whenHasError() async {
      await _doDrive(path.join('data', 'file_with_error.dart'));
      expect(exitCode, isNot(0));
    }
  
    test_noStatistics() async {
      await _doDrive(path.join('data', 'test_file.dart'));
      // Should not print statistics summary.
      expect(outSink.toString(), isEmpty);
      expect(errorSink.toString(), isEmpty);
      expect(exitCode, 0);
    }
  
    test_onlyErrors_partFirst() async {
      await withTempDirAsync((tempDir) async {
        var aDart = path.join(tempDir, 'a.dart');
        var bDart = path.join(tempDir, 'b.dart');
  
        var aUri = 'package:aaa/a.dart';
        var bUri = 'package:aaa/b.dart';
  
        new File(aDart).writeAsStringSync(r'''
  library lib;
  part 'b.dart';
  class A {}
  ''');
        new File(bDart).writeAsStringSync('''
  part of lib;
  class B {}
  var a = new A();
  var b = new B();
  ''');
  
        // Analyze b.dart (part) and then a.dart (its library).
        // No errors should be reported - the part should know its library.
        await _doDrive(bDart, uri: bUri, additionalArgs: ['$aUri|$aDart']);
        expect(errorSink, isEmpty);
      });
    }
  
    Future<void> _doDrive(String path,
        {String uri,
        List<String> additionalArgs: const [],
  
negative.code:   @override
    noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
  }
  
  class _DependencyPackage {
    final String name;
    final String path;
    final String uri;
    final String sum;
    final String dep;
  
    _DependencyPackage({this.name, this.path, this.uri, this.sum, this.dep});
  }
  