| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. 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 'dart:convert'; |
| |
| import 'package:coverage/coverage.dart'; |
| import 'package:coverage/src/util.dart'; |
| import 'package:path/path.dart' as p; |
| import 'package:test/test.dart'; |
| |
| import 'test_util.dart'; |
| |
| final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart'); |
| |
| final _sampleAppFileUri = p.toUri(p.absolute(testAppPath)).toString(); |
| final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString(); |
| |
| void main() { |
| test('collect_coverage_api', () async { |
| final json = await _collectCoverage(); |
| expect(json.keys, unorderedEquals(<String>['type', 'coverage'])); |
| expect(json, containsPair('type', 'CodeCoverage')); |
| |
| final coverage = json['coverage'] as List; |
| expect(coverage, isNotEmpty); |
| |
| final sources = coverage.cast<Map>().fold(<String, List<Map>>{}, |
| (Map<String, List<Map>> map, value) { |
| final sourceUri = value['source'] as String; |
| map.putIfAbsent(sourceUri, () => <Map>[]).add(value); |
| return map; |
| }); |
| |
| for (var sampleCoverageData in sources[_sampleAppFileUri]!) { |
| expect(sampleCoverageData['hits'], isNotEmpty); |
| } |
| |
| for (var sampleCoverageData in sources[_isolateLibFileUri]!) { |
| expect(sampleCoverageData['hits'], isNotEmpty); |
| } |
| }); |
| |
| test('collect_coverage_api with scoped output', () async { |
| final json = |
| await _collectCoverage(scopedOutput: <String>{}..add('coverage')); |
| expect(json.keys, unorderedEquals(<String>['type', 'coverage'])); |
| expect(json, containsPair('type', 'CodeCoverage')); |
| |
| final coverage = json['coverage'] as List; |
| expect(coverage, isNotEmpty); |
| |
| final sources = coverage.fold(<String, dynamic>{}, |
| (Map<String, dynamic> map, dynamic value) { |
| final sourceUri = value['source'] as String; |
| map.putIfAbsent(sourceUri, () => <Map>[]).add(value); |
| return map; |
| }); |
| |
| for (var key in sources.keys) { |
| final uri = Uri.parse(key); |
| expect(uri.path.startsWith('coverage'), isTrue); |
| } |
| }); |
| |
| test('collect_coverage_api with isolateIds', () async { |
| final json = await _collectCoverage(isolateIds: true); |
| expect(json.keys, unorderedEquals(<String>['type', 'coverage'])); |
| expect(json, containsPair('type', 'CodeCoverage')); |
| |
| final coverage = json['coverage'] as List<Map<String, dynamic>>; |
| expect(coverage, isNotEmpty); |
| |
| final testAppCoverage = _getScriptCoverage(coverage, 'test_app.dart')!; |
| var hits = testAppCoverage['hits'] as List<int>; |
| _expectHitCount(hits, 46, 0); |
| _expectHitCount(hits, 50, 0); |
| |
| final isolateCoverage = |
| _getScriptCoverage(coverage, 'test_app_isolate.dart')!; |
| hits = isolateCoverage['hits'] as List<int>; |
| _expectHitCount(hits, 11, 1); |
| _expectHitCount(hits, 28, 1); |
| }); |
| |
| test('collect_coverage_api with function coverage', () async { |
| final json = await _collectCoverage(functionCoverage: true); |
| expect(json.keys, unorderedEquals(<String>['type', 'coverage'])); |
| expect(json, containsPair('type', 'CodeCoverage')); |
| |
| final coverage = json['coverage'] as List; |
| expect(coverage, isNotEmpty); |
| |
| final sources = coverage.cast<Map>().fold(<String, List<Map>>{}, |
| (Map<String, List<Map>> map, value) { |
| final sourceUri = value['source'] as String; |
| map.putIfAbsent(sourceUri, () => <Map>[]).add(value); |
| return map; |
| }); |
| |
| for (var sampleCoverageData in sources[_sampleAppFileUri]!) { |
| expect(sampleCoverageData['funcNames'], isNotEmpty); |
| expect(sampleCoverageData['funcHits'], isNotEmpty); |
| } |
| |
| for (var sampleCoverageData in sources[_isolateLibFileUri]!) { |
| expect(sampleCoverageData['funcNames'], isNotEmpty); |
| expect(sampleCoverageData['funcHits'], isNotEmpty); |
| } |
| }); |
| } |
| |
| Future<Map<String, dynamic>> _collectCoverage( |
| {Set<String> scopedOutput = const {}, |
| bool isolateIds = false, |
| bool functionCoverage = false}) async { |
| final openPort = await getOpenPort(); |
| |
| // run the sample app, with the right flags |
| final sampleProcess = await runTestApp(openPort); |
| |
| // Capture the VM service URI. |
| final serviceUriCompleter = Completer<Uri>(); |
| final isolateIdCompleter = Completer<String>(); |
| sampleProcess.stdout |
| .transform(utf8.decoder) |
| .transform(LineSplitter()) |
| .listen((line) { |
| if (!serviceUriCompleter.isCompleted) { |
| final serviceUri = extractObservatoryUri(line); |
| if (serviceUri != null) { |
| serviceUriCompleter.complete(serviceUri); |
| } |
| } |
| if (line.contains('isolateId = ')) { |
| isolateIdCompleter.complete(line.split(' = ')[1]); |
| } |
| }); |
| |
| final serviceUri = await serviceUriCompleter.future; |
| final isolateId = await isolateIdCompleter.future; |
| final isolateIdSet = isolateIds ? {isolateId} : null; |
| |
| return collect(serviceUri, true, true, false, scopedOutput, |
| timeout: timeout, |
| isolateIds: isolateIdSet, |
| functionCoverage: functionCoverage); |
| } |
| |
| // Returns the first coverage hitmap for the script with with the specified |
| // script filename, ignoring leading path. |
| Map<String, dynamic>? _getScriptCoverage( |
| List<Map<String, dynamic>> coverage, String filename) { |
| for (var isolateCoverage in coverage) { |
| final script = Uri.parse(isolateCoverage['script']['uri'] as String); |
| if (script.pathSegments.last == filename) { |
| return isolateCoverage; |
| } |
| } |
| return null; |
| } |
| |
| /// Tests that the specified hitmap has the specified hit count for the |
| /// specified line. |
| void _expectHitCount(List<int> hits, int line, int hitCount) { |
| final hitIndex = hits.indexOf(line); |
| if (hitIndex < 0) { |
| fail('No hit count for line $line'); |
| } |
| final actual = hits[hitIndex + 1]; |
| expect(actual, equals(hitCount), |
| reason: 'Expected line $line to have $hitCount hits, but found $actual.'); |
| } |