Skip to content
This repository was archived by the owner on Aug 28, 2024. It is now read-only.

Ignore implicit functions #400

Merged
merged 6 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lib/src/collect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,10 @@ Future<void> _processFunction(VmService service, IsolateRef isolateRef,
Script script, FuncRef funcRef, HitMap hits) async {
final func = await service.getObject(isolateRef.id!, funcRef.id!) as Func;
final location = func.location;
if (location != null) {
if (!(func.implicit ?? false) && location != null) {
final funcName = await _getFuncName(service, isolateRef, func);
final tokenPos = location.tokenPos!;
final line = _getLineFromTokenPos(script, tokenPos);

if (line == null) {
stderr.writeln(
'tokenPos $tokenPos in function ${funcRef.name} has no line mapping '
Expand Down
6 changes: 2 additions & 4 deletions test/collect_coverage_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,10 @@ void main() {
68: 1
};
expect(isolateFile?.lineHits, expectedHits);
expect(isolateFile?.funcHits, {11: 1, 19: 1, 21: 0, 23: 1, 28: 1, 38: 1});
expect(isolateFile?.funcHits, {11: 1, 19: 1, 23: 1, 28: 1, 38: 1});
expect(isolateFile?.funcNames, {
11: 'fooSync',
19: 'BarClass.BarClass',
21: 'BarClass.x=',
23: 'BarClass.baz',
28: 'fooAsync',
38: 'isolateTask'
Expand Down Expand Up @@ -225,11 +224,10 @@ void main() {
68: 1
};
expect(isolateFile?.lineHits, expectedHits);
expect(isolateFile?.funcHits, {11: 1, 19: 1, 21: 0, 23: 1, 28: 1, 38: 1});
expect(isolateFile?.funcHits, {11: 1, 19: 1, 23: 1, 28: 1, 38: 1});
expect(isolateFile?.funcNames, {
11: 'fooSync',
19: 'BarClass.BarClass',
21: 'BarClass.x=',
23: 'BarClass.baz',
28: 'fooAsync',
38: 'isolateTask'
Expand Down
125 changes: 125 additions & 0 deletions test/function_coverage_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (c) 2022, 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' show json, LineSplitter, utf8;
import 'dart:io';

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 _collectAppPath = p.join('bin', 'collect_coverage.dart');
final _funcCovApp = p.join('test', 'test_files', 'function_coverage_app.dart');
final _sampleAppFileUri = p.toUri(p.absolute(_funcCovApp)).toString();

void main() {
test('Function coverage', () async {
final resultString = await _collectCoverage();
final jsonResult = json.decode(resultString) as Map<String, dynamic>;
final coverage = jsonResult['coverage'] as List;
final hitMap = await HitMap.parseJson(
coverage.cast<Map<String, dynamic>>(),
);

// function_coverage_app.dart.
expect(hitMap, contains(_sampleAppFileUri));
final isolateFile = hitMap[_sampleAppFileUri]!;
expect(isolateFile.funcHits, {
7: 1,
12: 0, // TODO(#398): This abstract method should be ignored.
16: 1,
21: 1,
25: 1,
29: 1,
36: 1,
42: 1,
47: 1,
});
expect(isolateFile.funcNames, {
7: 'normalFunction',
12: 'BaseClass.abstractMethod',
16: 'SomeClass.SomeClass',
21: 'SomeClass.normalMethod',
25: 'SomeClass.staticMethod',
29: 'SomeClass.abstractMethod',
36: 'SomeExtension.extensionMethod',
42: 'OtherClass.otherMethod',
47: 'main',
});

// test_library.dart.
final testLibraryPath =
p.absolute(p.join('test', 'test_files', 'test_library.dart'));
final testLibraryUri = p.toUri(testLibraryPath).toString();
expect(hitMap, contains(testLibraryUri));
final libraryfile = hitMap[testLibraryUri]!;
expect(libraryfile.funcHits, {9: 1});
expect(libraryfile.funcNames, {9: 'libraryFunction'});

// test_library_part.dart.
final testLibraryPartPath =
p.absolute(p.join('test', 'test_files', 'test_library_part.dart'));
final testLibraryPartUri = p.toUri(testLibraryPartPath).toString();
expect(hitMap, contains(testLibraryPartUri));
// TODO(#399): Fix handling of part files then re-enable this check.
// final libraryPartFile = hitMap[testLibraryPartUri]!;
// expect(libraryPartFile.funcHits, {7: 1});
// expect(libraryPartFile.funcNames, {7: 'otherLibraryFunction'});
});
}

Future<String> _collectCoverage() async {
expect(FileSystemEntity.isFileSync(_funcCovApp), isTrue);

final openPort = await getOpenPort();

// Run the sample app with the right flags.
final sampleProcess = await Process.start(Platform.resolvedExecutable, [
'--enable-vm-service=$openPort',
'--pause_isolates_on_exit',
_funcCovApp
]);

// Capture the VM service URI.
final serviceUriCompleter = Completer<Uri>();
sampleProcess.stdout
.transform(utf8.decoder)
.transform(LineSplitter())
.listen((line) {
if (!serviceUriCompleter.isCompleted) {
final serviceUri = extractVMServiceUri(line);
if (serviceUri != null) {
serviceUriCompleter.complete(serviceUri);
}
}
});
final serviceUri = await serviceUriCompleter.future;

// Run the collection tool.
final toolResult = await Process.run(Platform.resolvedExecutable, [
_collectAppPath,
'--function-coverage',
'--uri',
'$serviceUri',
'--resume-isolates',
'--wait-paused'
]).timeout(timeout, onTimeout: () {
throw 'We timed out waiting for the tool to finish.';
});

print(toolResult.stderr);
if (toolResult.exitCode != 0) {
print(toolResult.stdout);
fail('Tool failed with exit code ${toolResult.exitCode}.');
}

await sampleProcess.exitCode;
await sampleProcess.stderr.drain();

return toolResult.stdout as String;
}
56 changes: 56 additions & 0 deletions test/test_files/function_coverage_app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2022, 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 'test_library.dart';

int normalFunction() {
return 123;
}

abstract class BaseClass {
int abstractMethod();
}

class SomeClass extends BaseClass {
SomeClass() : x = 123;

// Creates an implicit getter and setter that should be ignored.
int x;

int normalMethod() {
return 123;
}

static int staticMethod() {
return 123;
}

@override
int abstractMethod() {
return 123;
}
}

extension SomeExtension on SomeClass {
int extensionMethod() {
return 123;
}
}

class OtherClass {
int otherMethod() {
return 123;
}
}

void main() {
print(normalFunction());
print(SomeClass().normalMethod());
print(SomeClass.staticMethod());
print(SomeClass().extensionMethod());
print(SomeClass().abstractMethod());
print(OtherClass().otherMethod());
print(libraryFunction());
print(otherLibraryFunction());
}
11 changes: 11 additions & 0 deletions test/test_files/test_library.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2022, 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.

library test_library;

part 'test_library_part.dart';

int libraryFunction() {
return 123;
}
9 changes: 9 additions & 0 deletions test/test_files/test_library_part.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2022, 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.

part of test_library;

int otherLibraryFunction() {
return 123;
}