// Copyright 2014 The Flutter 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:coverage/coverage.dart' as coverage;
import 'package:meta/meta.dart';
import 'package:vm_service/vm_service.dart' as vm_service;

import '../base/file_system.dart';
import '../base/io.dart';
import '../base/process.dart';
import '../globals.dart' as globals;
import '../vmservice.dart';

import 'test_device.dart';
import 'test_time_recorder.dart';
import 'watcher.dart';

/// A class that collects code coverage data during test runs.
class CoverageCollector extends TestWatcher {
  CoverageCollector({this.libraryNames, this.verbose = true, required this.packagesPath, this.resolver, this.testTimeRecorder});

  /// True when log messages should be emitted.
  final bool verbose;

  /// The path to the package_config.json of the package for which code
  /// coverage is computed.
  final String packagesPath;

  /// Map of file path to coverage hit map for that file.
  Map<String, coverage.HitMap>? _globalHitmap;

  /// The names of the libraries to gather coverage for. If null, all libraries
  /// will be accepted.
  Set<String>? libraryNames;

  final coverage.Resolver? resolver;
  final Map<String, List<List<int>>> _ignoredLinesInFilesCache = <String, List<List<int>>>{};

  final TestTimeRecorder? testTimeRecorder;

  static Future<coverage.Resolver> getResolver(String? packagesPath) async {
    try {
      return await coverage.Resolver.create(packagesPath: packagesPath);
    } on FileSystemException {
      // When given a bad packages path (as for instance done in some tests)
      // just ignore it and return one without a packages path.
      return coverage.Resolver.create();
    }
  }

  @override
  Future<void> handleFinishedTest(TestDevice testDevice) async {
    _logMessage('Starting coverage collection');
    await collectCoverage(testDevice);
  }

  void _logMessage(String line, { bool error = false }) {
    if (!verbose) {
      return;
    }
    if (error) {
      globals.printError(line);
    } else {
      globals.printTrace(line);
    }
  }

  void _addHitmap(Map<String, coverage.HitMap> hitmap) {
    final Stopwatch? stopwatch = testTimeRecorder?.start(TestTimePhases.CoverageAddHitmap);
    if (_globalHitmap == null) {
      _globalHitmap = hitmap;
    } else {
      _globalHitmap!.merge(hitmap);
    }
    testTimeRecorder?.stop(TestTimePhases.CoverageAddHitmap, stopwatch!);
  }

  /// The directory of the package for which coverage is being collected.
  String get packageDirectory {
    // The coverage package expects the directory of the package itself, and
    // uses that to locate the package_info.json file, which it treats as a
    // private implementation detail. In general, the package_info.json file is
    // located in `.dart_tool/package_info.json` relative to the package
    // directory, so we return the grandparent directory of that file.
    //
    // This may not be a safe assumption in non-standard environments, such as
    // when building under build systems such as Bazel. In those cases, this
    // getter should be overridden.
    return globals.fs.directory(globals.fs.file(packagesPath).dirname).dirname;
  }

  /// Collects coverage for an isolate using the given `port`.
  ///
  /// This should be called when the code whose coverage data is being collected
  /// has been run to completion so that all coverage data has been recorded.
  ///
  /// The returned [Future] completes when the coverage is collected.
  Future<void> collectCoverageIsolate(Uri observatoryUri) async {
    assert(observatoryUri != null);
    _logMessage('collecting coverage data from $observatoryUri...');
    final Map<String, dynamic> data = await collect(observatoryUri, libraryNames);
    if (data == null) {
      throw Exception('Failed to collect coverage.');
    }
    assert(data != null);

    _logMessage('($observatoryUri): collected coverage data; merging...');
    _addHitmap(await coverage.HitMap.parseJson(
      data['coverage'] as List<Map<String, dynamic>>,
      packagePath: packageDirectory,
      checkIgnoredLines: true,
    ));
    _logMessage('($observatoryUri): done merging coverage data into global coverage map.');
  }

  /// Collects coverage for the given [Process] using the given `port`.
  ///
  /// This should be called when the code whose coverage data is being collected
  /// has been run to completion so that all coverage data has been recorded.
  ///
  /// The returned [Future] completes when the coverage is collected.
  Future<void> collectCoverage(TestDevice testDevice, {@visibleForTesting Future<FlutterVmService> Function(Uri?)? connector}) async {
    assert(testDevice != null);

    final Stopwatch? totalTestTimeRecorderStopwatch = testTimeRecorder?.start(TestTimePhases.CoverageTotal);

    Map<String, dynamic>? data;

    final Stopwatch? collectTestTimeRecorderStopwatch = testTimeRecorder?.start(TestTimePhases.CoverageCollect);

    final Future<void> processComplete = testDevice.finished.catchError(
      (Object error) => throw Exception(
          'Failed to collect coverage, test device terminated prematurely with '
          'error: ${(error as TestDeviceException).message}.'),
      test: (Object error) => error is TestDeviceException,
    );

    final Future<void> collectionComplete = testDevice.observatoryUri
      .then((Uri? observatoryUri) {
        _logMessage('collecting coverage data from $testDevice at $observatoryUri...');
        return collect(observatoryUri, libraryNames, connector: connector ?? _defaultConnect)
          .then<void>((Map<String, dynamic> result) {
            if (result == null) {
              throw Exception('Failed to collect coverage.');
            }
            _logMessage('Collected coverage data.');
            data = result;
          });
      });

    await Future.any<void>(<Future<void>>[ processComplete, collectionComplete ]);
    assert(data != null);
    testTimeRecorder?.stop(TestTimePhases.CoverageCollect, collectTestTimeRecorderStopwatch!);

    _logMessage('Merging coverage data...');
    final Stopwatch? parseTestTimeRecorderStopwatch = testTimeRecorder?.start(TestTimePhases.CoverageParseJson);
    final Map<String, coverage.HitMap> hitmap = coverage.HitMap.parseJsonSync(
        data!['coverage'] as List<Map<String, dynamic>>,
        checkIgnoredLines: true,
        resolver: resolver ?? await CoverageCollector.getResolver(packageDirectory),
        ignoredLinesInFilesCache: _ignoredLinesInFilesCache);
    testTimeRecorder?.stop(TestTimePhases.CoverageParseJson, parseTestTimeRecorderStopwatch!);

    _addHitmap(hitmap);
    _logMessage('Done merging coverage data into global coverage map.');
    testTimeRecorder?.stop(TestTimePhases.CoverageTotal, totalTestTimeRecorderStopwatch!);
  }

  /// Returns formatted coverage data once all coverage data has been collected.
  ///
  /// This will not start any collection tasks. It us up to the caller of to
  /// call [collectCoverage] for each process first.
  Future<String?> finalizeCoverage({
    String Function(Map<String, coverage.HitMap> hitmap)? formatter,
    coverage.Resolver? resolver,
    Directory? coverageDirectory,
  }) async {
    if (_globalHitmap == null) {
      return null;
    }
    if (formatter == null) {
      final coverage.Resolver usedResolver = resolver ?? this.resolver ?? await CoverageCollector.getResolver(packagesPath);
      final String packagePath = globals.fs.currentDirectory.path;
      final List<String> reportOn = coverageDirectory == null
          ? <String>[globals.fs.path.join(packagePath, 'lib')]
          : <String>[coverageDirectory.path];
      formatter = (Map<String, coverage.HitMap> hitmap) => hitmap
          .formatLcov(usedResolver, reportOn: reportOn, basePath: packagePath);
    }
    final String result = formatter(_globalHitmap!);
    _globalHitmap = null;
    return result;
  }

  Future<bool> collectCoverageData(String? coveragePath, { bool mergeCoverageData = false, Directory? coverageDirectory }) async {
    final String? coverageData = await finalizeCoverage(
      coverageDirectory: coverageDirectory,
    );
    _logMessage('coverage information collection complete');
    if (coverageData == null) {
      return false;
    }

    final File coverageFile = globals.fs.file(coveragePath)
      ..createSync(recursive: true)
      ..writeAsStringSync(coverageData, flush: true);
    _logMessage('wrote coverage data to $coveragePath (size=${coverageData.length})');

    const String baseCoverageData = 'coverage/lcov.base.info';
    if (mergeCoverageData) {
      if (!globals.fs.isFileSync(baseCoverageData)) {
        _logMessage('Missing "$baseCoverageData". Unable to merge coverage data.', error: true);
        return false;
      }

      if (globals.os.which('lcov') == null) {
        String installMessage = 'Please install lcov.';
        if (globals.platform.isLinux) {
          installMessage = 'Consider running "sudo apt-get install lcov".';
        } else if (globals.platform.isMacOS) {
          installMessage = 'Consider running "brew install lcov".';
        }
        _logMessage('Missing "lcov" tool. Unable to merge coverage data.\n$installMessage', error: true);
        return false;
      }

      final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_test_coverage.');
      try {
        final File sourceFile = coverageFile.copySync(globals.fs.path.join(tempDir.path, 'lcov.source.info'));
        final RunResult result = globals.processUtils.runSync(<String>[
          'lcov',
          '--add-tracefile', baseCoverageData,
          '--add-tracefile', sourceFile.path,
          '--output-file', coverageFile.path,
        ]);
        if (result.exitCode != 0) {
          return false;
        }
      } finally {
        tempDir.deleteSync(recursive: true);
      }
    }
    return true;
  }

  @override
  Future<void> handleTestCrashed(TestDevice testDevice) async { }

  @override
  Future<void> handleTestTimedOut(TestDevice testDevice) async { }
}

Future<FlutterVmService> _defaultConnect(Uri? serviceUri) {
  return connectToVmService(
      serviceUri!, compression: CompressionOptions.compressionOff, logger: globals.logger,);
}

Future<Map<String, dynamic>> collect(Uri? serviceUri, Set<String>? libraryNames, {
  bool waitPaused = false,
  String? debugName,
  Future<FlutterVmService> Function(Uri?) connector = _defaultConnect,
  @visibleForTesting bool forceSequential = false,
}) async {
  final FlutterVmService vmService = await connector(serviceUri);
  final Map<String, dynamic> result = await _getAllCoverage(vmService.service, libraryNames, forceSequential);
  await vmService.dispose();
  return result;
}

Future<Map<String, dynamic>> _getAllCoverage(
  vm_service.VmService service,
  Set<String>? libraryNames,
  bool forceSequential,
) async {
  final vm_service.Version version = await service.getVersion();
  final bool libraryFilters = (version.major == 3 && version.minor! >= 57) || version.major! > 3;
  final vm_service.VM vm = await service.getVM();
  final List<Map<String, dynamic>> coverage = <Map<String, dynamic>>[];
  bool libraryPredicate(String? libraryName) {
    if (libraryNames == null) {
      return true;
    }
    final Uri uri = Uri.parse(libraryName!);
    if (uri.scheme != 'package') {
      return false;
    }
    final String scope = uri.path.split('/').first;
    return libraryNames.contains(scope);
  }
  for (final vm_service.IsolateRef isolateRef in vm.isolates!) {
    if (isolateRef.isSystemIsolate!) {
      continue;
    }
    if (libraryFilters) {
      final vm_service.SourceReport sourceReport = await service.getSourceReport(
          isolateRef.id!,
          <String>['Coverage'],
          forceCompile: true,
          reportLines: true,
          libraryFilters: libraryNames == null ? null : List<String>.from(
              libraryNames.map((String name) => 'package:$name/')),
        );
      _buildCoverageMap(
          <String, vm_service.Script>{},
          <vm_service.SourceReport>[sourceReport],
          coverage,
        );
    } else {
      vm_service.ScriptList scriptList;
      try {
        scriptList = await service.getScripts(isolateRef.id!);
      } on vm_service.SentinelException {
        continue;
      }

      final List<Future<void>> futures = <Future<void>>[];
      final Map<String, vm_service.Script> scripts = <String, vm_service.Script>{};
      final List<vm_service.SourceReport> sourceReports = <vm_service.SourceReport>[];

      // For each ScriptRef loaded into the VM, load the corresponding Script
      // and SourceReport object.
      for (final vm_service.ScriptRef script in scriptList.scripts!) {
        final String? libraryUri = script.uri;
        if (!libraryPredicate(libraryUri)) {
          continue;
        }
        final String? scriptId = script.id;
        final Future<void> getSourceReport = service.getSourceReport(
          isolateRef.id!,
          <String>['Coverage'],
          scriptId: scriptId,
          forceCompile: true,
          reportLines: true,
        )
        .then((vm_service.SourceReport report) {
          sourceReports.add(report);
        });
        if (forceSequential) {
          await null;
        }
        futures.add(getSourceReport);
      }
      await Future.wait(futures);
      _buildCoverageMap(scripts, sourceReports, coverage);
    }
  }
  return <String, dynamic>{'type': 'CodeCoverage', 'coverage': coverage};
}

// Build a hitmap of Uri -> Line -> Hit Count for each script object.
void _buildCoverageMap(
  Map<String, vm_service.Script> scripts,
  List<vm_service.SourceReport> sourceReports,
  List<Map<String, dynamic>> coverage,
) {
  final Map<String?, Map<int, int>> hitMaps = <String?, Map<int, int>>{};
  for (final vm_service.SourceReport sourceReport  in sourceReports) {
    for (final vm_service.SourceReportRange range in sourceReport.ranges!) {
      final vm_service.SourceReportCoverage? coverage = range.coverage;
      // Coverage reports may sometimes be null for a Script.
      if (coverage == null) {
        continue;
      }
      final vm_service.ScriptRef scriptRef = sourceReport.scripts![range.scriptIndex!];
      final String? uri = scriptRef.uri;

      hitMaps[uri] ??= <int, int>{};
      final Map<int, int>? hitMap = hitMaps[uri];
      final List<int>? hits = coverage.hits;
      final List<int>? misses = coverage.misses;
      if (hits != null) {
        for (final int line in hits) {
          final int current = hitMap![line] ?? 0;
          hitMap[line] = current + 1;
        }
      }
      if (misses != null) {
        for (final int line in misses) {
          hitMap![line] ??= 0;
        }
      }
    }
  }
  hitMaps.forEach((String? uri, Map<int, int> hitMap) {
    coverage.add(_toScriptCoverageJson(uri!, hitMap));
  });
}

// Returns a JSON hit map backward-compatible with pre-1.16.0 SDKs.
Map<String, dynamic> _toScriptCoverageJson(String scriptUri, Map<int, int> hitMap) {
  final Map<String, dynamic> json = <String, dynamic>{};
  final List<int> hits = <int>[];
  hitMap.forEach((int line, int hitCount) {
    hits.add(line);
    hits.add(hitCount);
  });
  json['source'] = scriptUri;
  json['script'] = <String, dynamic>{
    'type': '@Script',
    'fixedId': true,
    'id': 'libraries/1/scripts/${Uri.encodeComponent(scriptUri)}',
    'uri': scriptUri,
    '_kind': 'library',
  };
  json['hits'] = hits;
  return json;
}
