mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[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:
parent
8f853bc32f
commit
de5986ef24
4 changed files with 132 additions and 2 deletions
75
pkg/dds/test/dap/integration/debug_exceptions_test.dart
Normal file
75
pkg/dds/test/dap/integration/debug_exceptions_test.dart
Normal 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);
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
''';
|
||||
|
|
|
@ -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].
|
||||
|
|
Loading…
Reference in a new issue