blob: fd6aa9fde88bbaae411bb753ac05974f1f2fb2e4 [file]
// Copyright (c) 2023, 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 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'get_source_report_lib.dart' as testee_lib;
bool allRangesCompiled(SourceReport coverage) {
for (final range in coverage.ranges!) {
if (!range.compiled!) {
return false;
}
}
return true;
}
void main([args = const <String>[]]) =>
IsolateTestHarness('get_source_report_lib.dart', args)
.hasStoppedAtBreakpoint()
.stoppedAtLine('LINE_A')
.addCustomTestWithParser((VmService service, IsolateRef isolateRef,
TestScriptParser parser) async {
final isolateId = isolateRef.id!;
final stack = await service.getStack(isolateId);
final func = stack.frames!.first.function!;
final scriptId = func.location!.script!.id!;
final expectedRange = SourceReportRange(
scriptIndex: 0,
startPos: parser.offsetForTag('OFFSET_START'),
endPos: parser.offsetForTag('OFFSET_END'),
compiled: true,
coverage: SourceReportCoverage(
hits: [
parser.offsetForTag('OFFSET_START'),
parser.offsetForTag('OFFSET_COMPARE'),
parser.offsetForTag('OFFSET_PRINT_POSITIVE'),
parser.offsetForTag('OFFSET_DEBUGGER'),
],
misses: [parser.offsetForTag('OFFSET_PRINT_NEGATIVE')],
),
);
// Full script
var coverage = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
scriptId: scriptId,
);
var ranges = coverage.ranges!;
expect(ranges.length, greaterThanOrEqualTo(7));
// TODO(bkonyi): implement operator== properly.
expect(ranges[0].toJson(), expectedRange.toJson());
var scripts = coverage.scripts!;
expect(coverage.scripts!.length, 1);
expect(scripts[0].uri!, endsWith('get_source_report_lib.dart'));
expect(allRangesCompiled(coverage), false);
// Force compilation.
coverage = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
scriptId: scriptId,
forceCompile: true,
);
ranges = coverage.ranges!;
expect(ranges.length, greaterThanOrEqualTo(7));
expect(allRangesCompiled(coverage), isTrue);
// One function
coverage = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
scriptId: scriptId,
tokenPos: func.location!.tokenPos!,
endTokenPos: func.location!.endTokenPos!,
);
ranges = coverage.ranges!;
scripts = coverage.scripts!;
expect(ranges.length, 1);
// TODO(bkonyi): implement operator== properly.
expect(ranges[0].toJson(), expectedRange.toJson());
expect(scripts.length, 1);
expect(scripts[0].uri!, endsWith('get_source_report_lib.dart'));
// With `libraryFilters` and `librariesAlreadyCompiled`
coverage = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
scriptId: scriptId,
tokenPos: func.location!.tokenPos!,
endTokenPos: func.location!.endTokenPos!,
libraryFilters: [scripts[0].uri!],
librariesAlreadyCompiled: [scripts[0].uri!],
);
scripts = coverage.scripts!;
expect(scripts[0].uri!, endsWith('get_source_report_lib.dart'));
// Full isolate
coverage = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
);
ranges = coverage.ranges!;
scripts = coverage.scripts!;
expect(ranges.length, greaterThan(1));
expect(scripts.length, greaterThan(1));
// Full isolate
coverage = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
forceCompile: true,
);
ranges = coverage.ranges!;
scripts = coverage.scripts!;
expect(ranges.length, greaterThan(1));
expect(scripts.length, greaterThan(1));
// Multiple reports (make sure enum list parameter parsing works).
coverage = await service.getSourceReport(
isolateId,
[
SourceReportKind.kCoverage,
SourceReportKind.kPossibleBreakpoints,
'_CallSites',
],
scriptId: scriptId,
tokenPos: func.location!.tokenPos!,
endTokenPos: func.location!.endTokenPos!,
);
ranges = coverage.ranges!;
expect(ranges.length, 1);
final range = ranges[0];
expect(coverage.json!['ranges'][0].containsKey('callSites'), true);
expect(range.coverage, isNotNull);
expect(range.possibleBreakpoints, isNotNull);
// missing scriptId with tokenPos.
bool caughtException = false;
try {
await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
tokenPos: func.location!.tokenPos!,
);
fail('Unreachable');
} on RPCError catch (e) {
caughtException = true;
expect(e.code, RPCErrorKind.kInvalidParams.code);
expect(
e.details,
"getSourceReport: the 'tokenPos' parameter requires the "
"'scriptId' parameter");
}
expect(caughtException, true);
// missing scriptId with endTokenPos.
caughtException = false;
try {
await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
endTokenPos: func.location!.endTokenPos!,
);
fail('Unreachable');
} on RPCError catch (e) {
caughtException = true;
expect(e.code, RPCErrorKind.kInvalidParams.code);
expect(
e.details,
"getSourceReport: the 'endTokenPos' parameter requires the "
"'scriptId' parameter");
}
expect(caughtException, true);
}).run(testeeMain: testee_lib.main);