| // 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. | |
| @Tags(['integration']) | |
| library; | |
| import 'dart:async'; | |
| import 'dart:io'; | |
| import 'package:coverage/coverage.dart'; | |
| import 'package:coverage/src/util.dart'; | |
| import 'package:glob/glob.dart'; | |
| import 'package:path/path.dart' as p; | |
| import 'package:test/test.dart'; | |
| import 'package:test_process/test_process.dart'; | |
| final _sampleAppPath = p.join('test', 'test_files', 'test_app.dart'); | |
| final _sampleGeneratedPath = p.join('test', 'test_files', 'test_app.g.dart'); | |
| final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart'); | |
| final _sampleAppFileUri = p.toUri(p.absolute(_sampleAppPath)).toString(); | |
| final _sampleGeneratedFileUri = p | |
| .toUri(p.absolute(_sampleGeneratedPath)) | |
| .toString(); | |
| final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString(); | |
| void main() { | |
| test('validate hitMap', () async { | |
| final hitmap = await _getHitMap(); | |
| expect(hitmap, contains(_sampleAppFileUri)); | |
| expect(hitmap, contains(_sampleGeneratedFileUri)); | |
| expect(hitmap, contains(_isolateLibFileUri)); | |
| expect(hitmap, contains('package:coverage/src/util.dart')); | |
| final sampleAppHitMap = hitmap[_sampleAppFileUri]; | |
| final sampleAppHitLines = sampleAppHitMap?.lineHits; | |
| final sampleAppHitFuncs = sampleAppHitMap?.funcHits; | |
| final sampleAppFuncNames = sampleAppHitMap?.funcNames; | |
| final sampleAppBranchHits = sampleAppHitMap?.branchHits; | |
| expect( | |
| sampleAppHitLines, | |
| containsPair(56, greaterThanOrEqualTo(1)), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitLines, | |
| containsPair(60, 0), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitLines, | |
| isNot(contains(42)), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitFuncs, | |
| containsPair(55, 1), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitFuncs, | |
| containsPair(59, 0), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppFuncNames, | |
| containsPair(55, 'usedMethod'), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppBranchHits, | |
| containsPair(51, 1), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| }); | |
| test('validate hitMap, old VM without branch coverage', () async { | |
| final hitmap = await _getHitMap(); | |
| expect(hitmap, contains(_sampleAppFileUri)); | |
| expect(hitmap, contains(_sampleGeneratedFileUri)); | |
| expect(hitmap, contains(_isolateLibFileUri)); | |
| expect(hitmap, contains('package:coverage/src/util.dart')); | |
| final sampleAppHitMap = hitmap[_sampleAppFileUri]; | |
| final sampleAppHitLines = sampleAppHitMap?.lineHits; | |
| final sampleAppHitFuncs = sampleAppHitMap?.funcHits; | |
| final sampleAppFuncNames = sampleAppHitMap?.funcNames; | |
| expect( | |
| sampleAppHitLines, | |
| containsPair(56, greaterThanOrEqualTo(1)), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitLines, | |
| containsPair(60, 0), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitLines, | |
| isNot(contains(42)), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitFuncs, | |
| containsPair(55, 1), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppHitFuncs, | |
| containsPair(59, 0), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| expect( | |
| sampleAppFuncNames, | |
| containsPair(55, 'usedMethod'), | |
| reason: 'be careful if you modify the test file', | |
| ); | |
| }); | |
| group('LcovFormatter', () { | |
| test('format()', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| // ignore: deprecated_member_use_from_same_package | |
| final formatter = LcovFormatter(resolver); | |
| final res = await formatter.format( | |
| hitmap.map((key, value) => MapEntry(key, value.lineHits)), | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| }); | |
| test('formatLcov()', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = hitmap.formatLcov(resolver); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| }); | |
| test('formatLcov() includes files in reportOn list', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = hitmap.formatLcov(resolver, reportOn: ['lib/', 'test/']); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| }); | |
| test('formatLcov() excludes files not in reportOn list', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = hitmap.formatLcov(resolver, reportOn: ['lib/']); | |
| expect(res, isNot(contains(p.absolute(_sampleAppPath)))); | |
| expect(res, isNot(contains(p.absolute(_sampleGeneratedPath)))); | |
| expect(res, isNot(contains(p.absolute(_isolateLibPath)))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| }); | |
| test('formatLcov() excludes files matching glob patterns', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = hitmap.formatLcov( | |
| resolver, | |
| ignoreGlobs: {Glob('**/*.g.dart'), Glob('**/util.dart')}, | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, isNot(contains(p.absolute(_sampleGeneratedPath)))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect( | |
| res, | |
| isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))), | |
| ); | |
| }); | |
| test( | |
| 'formatLcov() excludes files matching glob patterns regardless of their' | |
| 'presence on reportOn list', | |
| () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = hitmap.formatLcov( | |
| resolver, | |
| reportOn: ['test/'], | |
| ignoreGlobs: {Glob('**/*.g.dart')}, | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, isNot(contains(p.absolute(_sampleGeneratedPath)))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| }, | |
| ); | |
| test('formatLcov() uses paths relative to basePath', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = hitmap.formatLcov(resolver, basePath: p.absolute('lib')); | |
| expect( | |
| res, | |
| isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))), | |
| ); | |
| expect(res, contains(p.join('src', 'util.dart'))); | |
| }); | |
| }); | |
| group('PrettyPrintFormatter', () { | |
| test('format()', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| // ignore: deprecated_member_use_from_same_package | |
| final formatter = PrettyPrintFormatter(resolver, Loader()); | |
| final res = await formatter.format( | |
| hitmap.map((key, value) => MapEntry(key, value.lineHits)), | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| // be very careful if you change the test file | |
| expect(res, contains(' 0| return a - b;')); | |
| expect( | |
| res, | |
| contains('| return withTimeout(() async {'), | |
| reason: 'be careful if you change lib/src/util.dart', | |
| ); | |
| final hitLineRegexp = RegExp(r'\s+(\d+)\| return a \+ b;'); | |
| final match = hitLineRegexp.allMatches(res).single; | |
| final hitCount = int.parse(match[1]!); | |
| expect(hitCount, greaterThanOrEqualTo(1)); | |
| }); | |
| test('prettyPrint()', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint(resolver, Loader()); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| // be very careful if you change the test file | |
| expect(res, contains(' 0| return a - b;')); | |
| expect( | |
| res, | |
| contains('| return withTimeout(() async {'), | |
| reason: 'be careful if you change lib/src/util.dart', | |
| ); | |
| final hitLineRegexp = RegExp(r'\s+(\d+)\| return a \+ b;'); | |
| final match = hitLineRegexp.allMatches(res).single; | |
| final hitCount = int.parse(match[1]!); | |
| expect(hitCount, greaterThanOrEqualTo(1)); | |
| }); | |
| test('prettyPrint() includes files in reportOn list', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint( | |
| resolver, | |
| Loader(), | |
| reportOn: ['lib/', 'test/'], | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| }); | |
| test('prettyPrint() excludes files not in reportOn list', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint( | |
| resolver, | |
| Loader(), | |
| reportOn: ['lib/'], | |
| ); | |
| expect(res, isNot(contains(p.absolute(_sampleAppPath)))); | |
| expect(res, isNot(contains(p.absolute(_sampleGeneratedPath)))); | |
| expect(res, isNot(contains(p.absolute(_isolateLibPath)))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| }); | |
| test('prettyPrint() excludes files matching glob patterns', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint( | |
| resolver, | |
| Loader(), | |
| ignoreGlobs: {Glob('**/*.g.dart'), Glob('**/util.dart')}, | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, isNot(contains(p.absolute(_sampleGeneratedPath)))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect( | |
| res, | |
| isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))), | |
| ); | |
| }); | |
| test('prettyPrint() excludes files matching glob patterns regardless of' | |
| 'their presence on reportOn list', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint( | |
| resolver, | |
| Loader(), | |
| reportOn: ['test/'], | |
| ignoreGlobs: {Glob('**/*.g.dart')}, | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, isNot(contains(p.absolute(_sampleGeneratedPath)))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| }); | |
| test('prettyPrint() functions', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint( | |
| resolver, | |
| Loader(), | |
| reportFuncs: true, | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| // be very careful if you change the test file | |
| expect(res, contains(' 1|Future<void> main() async {')); | |
| expect(res, contains(' 1|int usedMethod(int a, int b) {')); | |
| expect(res, contains(' 0|int unusedMethod(int a, int b) {')); | |
| expect(res, contains(' | return a + b;')); | |
| }); | |
| test('prettyPrint() branches', () async { | |
| final hitmap = await _getHitMap(); | |
| final resolver = await Resolver.create(packagePath: '.'); | |
| final res = await hitmap.prettyPrint( | |
| resolver, | |
| Loader(), | |
| reportBranches: true, | |
| ); | |
| expect(res, contains(p.absolute(_sampleAppPath))); | |
| expect(res, contains(p.absolute(_sampleGeneratedPath))); | |
| expect(res, contains(p.absolute(_isolateLibPath))); | |
| expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart')))); | |
| // be very careful if you change the test file | |
| expect(res, contains(' 1| if (x == answer) {')); | |
| expect(res, contains(' 0| while (i < lines.length) {')); | |
| expect(res, contains(' | bar.baz();')); | |
| }); | |
| }); | |
| } | |
| Future<Map<String, HitMap>>? _hitMapFuture; | |
| Future<Map<String, HitMap>> _getHitMap() => _hitMapFuture ??= _createHitMap(); | |
| Future<Map<String, HitMap>> _createHitMap() async { | |
| expect(FileSystemEntity.isFileSync(_sampleAppPath), isTrue); | |
| // start sample app. | |
| final sampleAppArgs = [ | |
| '--pause-isolates-on-exit', | |
| '--enable-vm-service=0', | |
| '--branch-coverage', | |
| _sampleAppPath, | |
| ]; | |
| final sampleProcess = await TestProcess.start( | |
| Platform.resolvedExecutable, | |
| sampleAppArgs, | |
| ); | |
| final serviceUri = await serviceUriFromProcess(sampleProcess.stdoutStream()); | |
| // collect hit map. | |
| final coverageJson = | |
| (await collect( | |
| serviceUri, | |
| true, | |
| true, | |
| false, | |
| <String>{}, | |
| functionCoverage: true, | |
| branchCoverage: true, | |
| ))['coverage'] | |
| as List<Map<String, dynamic>>; | |
| final hitMap = HitMap.parseJson(coverageJson); | |
| await sampleProcess.shouldExit(0); | |
| return hitMap; | |
| } |