[dds] Add tests for DAP exception behaviour

Change-Id: I524a7bdebd0c4f572db67550cd42f4ba5118cfc3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/209640
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
Danny Tuppeny 2021-08-09 22:44:09 +00:00 committed by commit-bot@chromium.org
parent 8f853bc32f
commit de5986ef24
4 changed files with 132 additions and 2 deletions

View file

@ -0,0 +1,75 @@
// Copyright (c) 2021, 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 'test_client.dart';
import 'test_scripts.dart';
import 'test_support.dart';
main() {
group('debug mode', () {
late DapTestSession dap;
setUp(() async {
dap = await DapTestSession.setUp();
});
tearDown(() => dap.tearDown());
test('does not pause on exceptions if mode not set', () async {
final client = dap.client;
final testFile = dap.createTestFile(simpleThrowingProgram);
// Run the app and expect it to complete (it should not pause).
final outputEvents = await client.collectOutput(file: testFile);
// Expect error info printed to stderr.
final output = outputEvents
.where((e) => e.category == 'stderr')
.map((e) => e.output)
.join();
expectLinesStartWith(output, [
'Unhandled exception:',
'error',
]);
});
test('pauses on uncaught exceptions when mode=Unhandled', () async {
final client = dap.client;
final testFile = dap.createTestFile(simpleThrowingProgram);
// Run and expect to pause on an exception.
await client.pauseOnException(
testFile,
exceptionPauseMode: 'Unhandled',
);
});
test('does not pauses on caught exceptions when mode=Unhandled', () async {
final client = dap.client;
final testFile = dap.createTestFile(simpleCaughtErrorProgram);
// Run the app and expect it to complete (it should not pause).
final outputEvents = await client.collectOutput(file: testFile);
// Expect error info printed to stderr.
final output = outputEvents
.where((e) => e.category == 'stdout')
.map((e) => e.output)
.join();
expectLines(output, ['Caught!']);
});
test('pauses on caught exceptions when mode=All', () async {
final client = dap.client;
final testFile = dap.createTestFile(simpleCaughtErrorProgram);
// Run and expect to pause on an exception.
await client.pauseOnException(
testFile,
exceptionPauseMode: 'All',
);
});
// These tests can be slow due to starting up the external server process.
}, timeout: Timeout.none);
}

View file

@ -409,6 +409,31 @@ extension DapTestClientExtension on DapTestClient {
return stop;
}
/// Sets the exception pause mode to [pauseMode] and expects to pause after
/// running the script.
///
/// Launch options can be customised by passing a custom [launch] function that
/// will be used instead of calling `launch(file.path)`.
Future<StoppedEventBody> pauseOnException(
File file, {
String? exceptionPauseMode, // All, Unhandled, None
Future<Response> Function()? launch,
}) async {
final stop = expectStop('exception', file: file);
await Future.wait([
initialize(),
sendRequest(
SetExceptionBreakpointsArguments(
filters: [if (exceptionPauseMode != null) exceptionPauseMode],
),
),
launch?.call() ?? this.launch(file.path),
], eagerError: true);
return stop;
}
/// Returns whether DDS is available for the VM Service the debug adapter
/// is connected to.
Future<bool> get ddsAvailable async {

View file

@ -15,3 +15,21 @@ const simpleBreakpointProgram = r'''
print('Hello!'); // BREAKPOINT
}
''';
/// A simple Dart script that throws an error and catches it in user code.
const simpleCaughtErrorProgram = r'''
void main(List<String> args) async {
try {
throw 'error';
} catch (e) {
print('Caught!');
}
}
''';
/// A simple Dart script that throws in user code.
const simpleThrowingProgram = r'''
void main(List<String> args) async {
throw 'error';
}
''';

View file

@ -31,9 +31,21 @@ final vmServiceAuthCodePathPattern = RegExp(r'^/[\w_\-=]{5,15}/ws$');
final vmServiceUriPattern = RegExp(r'Connecting to VM Service at ([^\s]+)\s');
/// Expects [actual] to equal the lines [expected], ignoring differences in line
/// endings.
/// endings and trailing whitespace.
void expectLines(String actual, List<String> expected) {
expect(actual.replaceAll('\r\n', '\n'), equals(expected.join('\n')));
expect(
actual.replaceAll('\r\n', '\n').trim(),
equals(expected.join('\n').trim()),
);
}
/// Expects [actual] starts with [expected], ignoring differences in line
/// endings and trailing whitespace.
void expectLinesStartWith(String actual, List<String> expected) {
expect(
actual.replaceAll('\r\n', '\n').trim(),
startsWith(expected.join('\n').trim()),
);
}
/// Returns the 1-base line in [file] that contains [searchText].