Version 2.15.0-292.0.dev
Merge commit '490e625ce78b49c6b57fe405261234623fc4e8f5' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 981de4b..4281850 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -710,6 +710,11 @@
"languageVersion": "2.12"
},
{
+ "name": "test_package",
+ "rootUri": "../pkg/vm_service/test/test_package",
+ "languageVersion": "2.12"
+ },
+ {
"name": "test_process",
"rootUri": "../third_party/pkg/test_process",
"packageUri": "lib/",
diff --git a/.packages b/.packages
index 568fa66..f5ea5bc 100644
--- a/.packages
+++ b/.packages
@@ -105,6 +105,7 @@
test_api:third_party/pkg/test/pkgs/test_api/lib
test_core:third_party/pkg/test/pkgs/test_core/lib
test_descriptor:third_party/pkg/test_descriptor/lib
+test_package:pkg/vm_service/test/test_package
test_process:third_party/pkg/test_process/lib
test_reflective_loader:third_party/pkg/test_reflective_loader/lib
test_runner:pkg/test_runner/lib
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef0ba40..81152a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,10 +2,9 @@
### Language
-The following new features are new in the Dart 2.15 [language version][]. To use
+The following features are new in the Dart 2.15 [language version][]. To use
them, you must set the lower bound on the SDK constraint for your package to
-2.15 or greater. (If using a beta preview release, use an SDK constraint of
-`>=2.15.0-0`):
+2.15 or greater (`sdk: '>=2.15.0 <3.0.0'`).
[language version]: https://dart.dev/guides/language/evolution
@@ -113,12 +112,6 @@
}
```
- Generic type literals are only available as part of the 2.15 [language
- version](https://dart.dev/guides/language/evolution). To use this feature, you
- must set the lower bound on the SDK constraint for your package to 2.15 or
- greater (if using a beta preview release, an SDK constraint of
- `>=2.15.0-0` must be used).
-
- **[Explicit generic method instantiations][explicit instantiation]**: Previous
Dart versions allowed generic methods to be implicitly specialized (or
"instantiated") to non-generic versions when assigned to a location with a
diff --git a/DEPS b/DEPS
index 5709b47..df4cc35 100644
--- a/DEPS
+++ b/DEPS
@@ -91,7 +91,7 @@
"collection_rev": "a4c941ab94044d118b2086a3f261c30377604127",
"convert_rev": "e063fdca4bebffecbb5e6aa5525995120982d9ce",
"crypto_rev": "b5024e4de2b1c474dd558bef593ddbf0bfade152",
- "csslib_rev": "6f35da3d93eb56eb25925779d235858d4090ce6f",
+ "csslib_rev": "02abc1ddf93092efef2be365300f15504d23cd23",
# Note: Updates to dart_style have to be coordinated with the infrastructure
# team so that the internal formatter `tools/sdks/dart-sdk/bin/dart format`
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 2b98916..bbe634a 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -32,8 +32,8 @@
import 'package:analysis_server/src/plugin/notification_manager.dart';
import 'package:analysis_server/src/protocol_server.dart' as server;
import 'package:analysis_server/src/search/search_domain.dart';
-import 'package:analysis_server/src/server/completion_request_aborting.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
+import 'package:analysis_server/src/server/debounce_requests.dart';
import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
import 'package:analysis_server/src/server/diagnostic_server.dart';
import 'package:analysis_server/src/server/error_notifier.dart';
@@ -56,6 +56,7 @@
import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
import 'package:http/http.dart' as http;
+import 'package:meta/meta.dart';
import 'package:telemetry/crash_reporting.dart';
import 'package:telemetry/telemetry.dart' as telemetry;
import 'package:watcher/watcher.dart';
@@ -116,8 +117,11 @@
final DetachableFileSystemManager? detachableFileSystemManager;
- final CompletionRequestAborting completionRequestAborting =
- CompletionRequestAborting();
+ /// The broadcast stream of requests that were discarded because there
+ /// was another request that made this one irrelevant.
+ @visibleForTesting
+ final StreamController<Request> discardedRequests =
+ StreamController.broadcast(sync: true);
/// Initialize a newly created server to receive requests from and send
/// responses to the given [channel].
@@ -171,7 +175,8 @@
io.pid,
).toNotification(),
);
- channel.requests.listen(handleRequest, onDone: done, onError: error);
+ debounceRequests(channel, discardedRequests)
+ .listen(handleRequest, onDone: done, onError: error);
handlers = <server.RequestHandler>[
ServerDomainHandler(this),
AnalysisDomainHandler(this),
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index ec4c4f3..1595e38 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -417,7 +417,6 @@
}
}
- server.completionRequestAborting.abort();
server.updateContent(request.id, params.files);
//
// Forward the request to the plugins.
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 925a100..76a3f3b 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -297,14 +297,6 @@
return;
}
- server.completionRequestAborting.abort();
- if (await server.completionRequestAborting.waitIfAborted(request)) {
- return server.sendResponse(
- CompletionGetSuggestions2Result(offset, 0, [], [], true)
- .toResponse(request.id),
- );
- }
-
var performance = OperationPerformanceImpl('<root>');
performance.runAsync(
'request',
diff --git a/pkg/analysis_server/lib/src/server/completion_request_aborting.dart b/pkg/analysis_server/lib/src/server/completion_request_aborting.dart
deleted file mode 100644
index 8f03f53..0000000
--- a/pkg/analysis_server/lib/src/server/completion_request_aborting.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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:analysis_server/protocol/protocol.dart';
-import 'package:meta/meta.dart';
-
-class CompletionRequestAborting {
- /// IDs of requests to abort on another completion request.
- final Set<String> _pendingRequests = {};
-
- /// IDs from [_pendingRequests] that we decided to abort.
- final Set<String> _abortedRequests = {};
-
- /// The function to be invoked when requests are aborted.
- @visibleForTesting
- void Function(Set<String> id)? onAbort;
-
- /// Abort requests that were pending.
- void abort() {
- onAbort?.call(_pendingRequests);
- _abortedRequests.addAll(_pendingRequests);
- }
-
- /// Return `true` if the [request] should be aborted because there is
- /// another request in the queue, so [abort] was invoked while pumping the
- /// event queue.
- Future<bool> waitIfAborted(Request request) async {
- // Mark the current request as pending.
- var id = request.id;
- _pendingRequests.add(id);
-
- // Wait for more requests to arrive and abort this one.
- await _pumpEventQueue(64);
-
- // We are done waiting.
- _pendingRequests.remove(id);
-
- // See it the request was aborted.
- return _abortedRequests.remove(id);
- }
-
- static Future<void> _pumpEventQueue(int times) {
- if (times == 0) return Future.value();
- return Future(() => _pumpEventQueue(times - 1));
- }
-}
diff --git a/pkg/analysis_server/lib/src/server/debounce_requests.dart b/pkg/analysis_server/lib/src/server/debounce_requests.dart
new file mode 100644
index 0000000..4ee01d6
--- /dev/null
+++ b/pkg/analysis_server/lib/src/server/debounce_requests.dart
@@ -0,0 +1,83 @@
+// 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 'dart:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_constants.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/channel/channel.dart';
+
+/// Return the stream of requests that is filtered to exclude requests for
+/// which the client does not need actual responses.
+///
+/// If there is one completion request, and then another completion request,
+/// then most probably the user continued typing, and there is no need to
+/// compute results for the first request. But we will have to respond, an
+/// empty response is enough.
+///
+/// Discarded requests are reported into [discardedRequests].
+Stream<Request> debounceRequests(
+ ServerCommunicationChannel channel,
+ StreamController<Request> discardedRequests,
+) {
+ return _DebounceRequests(channel, discardedRequests).requests;
+}
+
+class _DebounceRequests {
+ final ServerCommunicationChannel channel;
+ final StreamController<Request> discardedRequests;
+ late final Stream<Request> requests;
+
+ _DebounceRequests(this.channel, this.discardedRequests) {
+ var buffer = <Request>[];
+ Timer? timer;
+
+ requests = channel.requests.transform(
+ StreamTransformer.fromHandlers(
+ handleData: (request, sink) {
+ buffer.add(request);
+ // Accumulate requests for a short period of time.
+ // When we were busy processing a request, the client could put
+ // multiple requests into the event queue. So, when we look, we will
+ // quickly get all of them. So, even 1 ms should be enough.
+ timer ??= Timer(const Duration(milliseconds: 1), () {
+ timer = null;
+ var filtered = _filterCompletion(buffer);
+ buffer = [];
+ for (var request in filtered) {
+ sink.add(request);
+ }
+ });
+ },
+ ),
+ );
+ }
+
+ List<Request> _filterCompletion(List<Request> requests) {
+ var reversed = <Request>[];
+ var abortCompletionRequests = false;
+ for (var request in requests.reversed) {
+ if (request.method == ANALYSIS_REQUEST_UPDATE_CONTENT) {
+ abortCompletionRequests = true;
+ }
+ if (request.method == COMPLETION_REQUEST_GET_SUGGESTIONS2) {
+ if (abortCompletionRequests) {
+ discardedRequests.add(request);
+ var params = CompletionGetSuggestions2Params.fromRequest(request);
+ var offset = params.offset;
+ channel.sendResponse(
+ CompletionGetSuggestions2Result(offset, 0, [], [], true)
+ .toResponse(request.id),
+ );
+ continue;
+ } else {
+ abortCompletionRequests = true;
+ }
+ }
+ reversed.add(request);
+ }
+ return reversed.reversed.toList();
+ }
+}
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 226a8b8..d4f174f 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -230,9 +230,9 @@
Future<void> test_abort_onAnotherCompletionRequest() async {
var abortedIdSet = <String>{};
- server.completionRequestAborting.onAbort = (idSet) {
- abortedIdSet.addAll(idSet);
- };
+ server.discardedRequests.stream.listen((request) {
+ abortedIdSet.add(request.id);
+ });
newFile(testFilePath, content: '');
@@ -268,9 +268,9 @@
Future<void> test_abort_onUpdateContent() async {
var abortedIdSet = <String>{};
- server.completionRequestAborting.onAbort = (idSet) {
- abortedIdSet.addAll(idSet);
- };
+ server.discardedRequests.stream.listen((request) {
+ abortedIdSet.add(request.id);
+ });
newFile(testFilePath, content: '');
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 81e92a4..2984592 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -21,3 +21,5 @@
process: ^4.0.0
pub_semver: ^2.0.0-nullsafety.0
test: ^1.16.0-nullsafety.13
+ test_package:
+ path: 'test/test_package'
diff --git a/pkg/vm_service/test/add_breakpoint_rpc_kernel_test.dart b/pkg/vm_service/test/add_breakpoint_rpc_kernel_test.dart
new file mode 100644
index 0000000..bead75c
--- /dev/null
+++ b/pkg/vm_service/test/add_breakpoint_rpc_kernel_test.dart
@@ -0,0 +1,178 @@
+// Copyright (c) 2017, 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 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 24;
+const int LINE_B = 26;
+
+int value = 0;
+
+int incValue(int amount) {
+ value += amount;
+ return amount;
+}
+
+Future testMain() async {
+ incValue(incValue(1)); // line A.
+
+ incValue(incValue(1)); // line B.
+}
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+
+ // Test future breakpoints.
+ (VmService service, IsolateRef isolateRef) async {
+ final isolateId = isolateRef.id!;
+ final isolate = await service.getIsolate(isolateId);
+ final rootLib =
+ await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+ final rootLibId = rootLib.id!;
+ final scriptId = rootLib.scripts![0].id!;
+ final script = await service.getObject(isolateId, scriptId) as Script;
+
+ // Future breakpoint.
+ var futureBpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
+ expect(futureBpt1.breakpointNumber, 1);
+ expect(futureBpt1.resolved, isFalse);
+ expect(await futureBpt1.location!.line!, LINE_A);
+ expect(await futureBpt1.location!.column, null);
+
+ // Future breakpoint with specific column.
+ var futureBpt2 =
+ await service.addBreakpoint(isolateId, scriptId, LINE_A, column: 3);
+ expect(futureBpt2.breakpointNumber, 2);
+ expect(futureBpt2.resolved, isFalse);
+ expect(await futureBpt2.location!.line!, LINE_A);
+ expect(await futureBpt2.location!.column!, 3);
+
+ int resolvedCount = await resumeAndCountResolvedBreakpointsUntilPause(
+ service,
+ isolate,
+ );
+
+ // After resolution the breakpoints have assigned line & column.
+ expect(resolvedCount, 2);
+
+ // Refresh objects
+ futureBpt1 =
+ await service.getObject(isolateId, futureBpt1.id!) as Breakpoint;
+ futureBpt2 =
+ await service.getObject(isolateId, futureBpt2.id!) as Breakpoint;
+
+ expect(futureBpt1.resolved, isTrue);
+ expect(script.getLineNumberFromTokenPos(futureBpt1.location!.tokenPos!),
+ LINE_A);
+ expect(
+ script.getColumnNumberFromTokenPos(futureBpt1.location!.tokenPos!), 12);
+ expect(futureBpt2.resolved, isTrue);
+ expect(script.getLineNumberFromTokenPos(futureBpt2.location!.tokenPos!),
+ LINE_A);
+ expect(
+ script.getColumnNumberFromTokenPos(futureBpt2.location!.tokenPos!), 3);
+
+ // The first breakpoint hits before value is modified.
+ InstanceRef result =
+ await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
+ expect(result.valueAsString, '0');
+
+ await service.resume(isolateId);
+ await hasStoppedAtBreakpoint(service, isolate);
+
+ // The second breakpoint hits after value has been modified once.
+ result =
+ await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
+ expect(result.valueAsString, '1');
+
+ // Remove the breakpoints.
+ expect((await service.removeBreakpoint(isolateId, futureBpt1.id!)).type,
+ 'Success');
+ expect((await service.removeBreakpoint(isolateId, futureBpt2.id!)).type,
+ 'Success');
+ },
+
+ // Test resolution of column breakpoints.
+ (VmService service, IsolateRef isolateRef) async {
+ final isolateId = isolateRef.id!;
+ final isolate = await service.getIsolate(isolateId);
+ final rootLibId = isolate.rootLib!.id!;
+ final rootLib = await service.getObject(isolateId, rootLibId) as Library;
+
+ final scriptId = rootLib.scripts![0].id!;
+ final script = await service.getObject(isolateId, scriptId) as Script;
+
+ // Try all columns, including some columns that are too big.
+ for (int col = 1; col <= 50; col++) {
+ final bpt =
+ await service.addBreakpoint(isolateId, scriptId, LINE_A, column: col);
+ expect(bpt.resolved, isTrue);
+ int resolvedLine =
+ script.getLineNumberFromTokenPos(bpt.location!.tokenPos!)!;
+ int resolvedCol =
+ script.getColumnNumberFromTokenPos(bpt.location!.tokenPos!)!;
+ print('$LINE_A:${col} -> ${resolvedLine}:${resolvedCol}');
+ if (col <= 12) {
+ expect(resolvedLine, LINE_A);
+ expect(resolvedCol, 3);
+ } else if (col <= 36) {
+ expect(resolvedLine, LINE_A);
+ expect(resolvedCol, 12);
+ } else {
+ expect(resolvedLine, LINE_B);
+ expect(resolvedCol, 12);
+ }
+ expect(
+ (await service.removeBreakpoint(isolateId, bpt.id!)).type, 'Success');
+ }
+
+ // Make sure that a zero column is an error.
+ var caughtException = false;
+ try {
+ await service.addBreakpoint(isolateId, scriptId, 20, column: 0);
+ expect(false, isTrue, reason: 'Unreachable');
+ } on RPCError catch (e) {
+ caughtException = true;
+ expect(e.code, RPCError.kInvalidParams);
+ expect(e.details, "addBreakpoint: invalid 'column' parameter: 0");
+ }
+ expect(caughtException, isTrue);
+ },
+];
+
+Future<int> resumeAndCountResolvedBreakpointsUntilPause(
+ VmService service, Isolate isolate) async {
+ final completer = Completer<void>();
+ late StreamSubscription subscription;
+ int resolvedCount = 0;
+
+ subscription = service.onDebugEvent.listen((event) {
+ if (event.kind == EventKind.kBreakpointResolved) {
+ resolvedCount++;
+ } else if (event.kind == EventKind.kPauseBreakpoint) {
+ subscription.cancel();
+ service.streamCancel(EventStreams.kDebug);
+ completer.complete();
+ }
+ });
+ await service.streamListen(EventStreams.kDebug);
+
+ await service.resume(isolate.id!);
+ await completer.future;
+ return resolvedCount;
+}
+
+main(args) => runIsolateTests(
+ args,
+ tests,
+ 'add_breakpoint_rpc_kernel_test.dart',
+ testeeConcurrent: testMain,
+ pause_on_start: true,
+ );
diff --git a/pkg/vm_service/test/allocations_test.dart b/pkg/vm_service/test/allocations_test.dart
new file mode 100644
index 0000000..9e38e57
--- /dev/null
+++ b/pkg/vm_service/test/allocations_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2014, 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/test_helper.dart';
+
+class Foo {}
+
+// Prevent TFA from removing this static field to ensure the objects are kept
+// alive, so the allocation stats will report them via the service api.
+@pragma('vm:entry-point')
+List<Foo>? foos;
+
+void script() {
+ foos = [
+ Foo(),
+ Foo(),
+ Foo(),
+ ];
+}
+
+var tests = <IsolateTest>[
+ (VmService service, IsolateRef isolateRef) async {
+ var profile = await service.callMethod('_getAllocationProfile',
+ isolateId: isolateRef.id!) as AllocationProfile;
+ print(profile.runtimeType);
+ var classHeapStats = profile.members!.singleWhere((stats) {
+ return stats.classRef!.name == 'Foo';
+ });
+ expect(classHeapStats.instancesCurrent, 3);
+ expect(classHeapStats.instancesAccumulated, 3);
+ },
+];
+
+main(args) => runIsolateTests(
+ args,
+ tests,
+ 'allocations_test.dart',
+ testeeBefore: script,
+ );
diff --git a/pkg/vm_service/test/async_next_regression_18877_test.dart b/pkg/vm_service/test/async_next_regression_18877_test.dart
new file mode 100644
index 0000000..6912a67
--- /dev/null
+++ b/pkg/vm_service/test/async_next_regression_18877_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2018, 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.
+// VMOptions=--verbose_debug
+
+import 'dart:developer';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 24;
+const int LINE_B = 25;
+const int LINE_C = 26;
+
+foo() async {}
+
+doAsync(stop) async {
+ // Flutter issue 18877:
+ // If a closure is defined in the context of an async method, stepping over
+ // an await causes the implicit breakpoint to be set for that closure instead
+ // of the async_op, resulting in the debugger falling through.
+ final baz = () => print('doAsync($stop) done!');
+ if (stop) debugger();
+ await foo(); // Line A.
+ await foo(); // Line B.
+ await foo(); // Line C.
+ baz();
+ return null;
+}
+
+testMain() {
+ // With two runs of doAsync floating around, async step should only cause
+ // us to stop in the run we started in.
+ doAsync(false);
+ doAsync(true);
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ stepOver, // foo()
+ stoppedAtLine(LINE_A),
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ stepOver, // foo()
+ stoppedAtLine(LINE_B),
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ resumeIsolate,
+];
+
+main(args) => runIsolateTests(
+ args,
+ tests,
+ 'async_next_regression_18877_test.dart',
+ testeeConcurrent: testMain,
+ );
diff --git a/pkg/vm_service/test/awaiter_async_stack_contents_2_test.dart b/pkg/vm_service/test/awaiter_async_stack_contents_2_test.dart
new file mode 100644
index 0000000..88d17d0a
--- /dev/null
+++ b/pkg/vm_service/test/awaiter_async_stack_contents_2_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2018, 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.
+//
+// VMOptions=--async-debugger --verbose-debug --lazy-async-stacks
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 28;
+const LINE_B = 34;
+const LINE_C = 38;
+
+notCalled() async {
+ await null;
+ await null;
+ await null;
+ await null;
+}
+
+foobar() async {
+ await null;
+ debugger();
+ print('foobar'); // LINE_A.
+}
+
+helper() async {
+ await null;
+ print('helper');
+ await foobar(); // LINE_B.
+}
+
+testMain() async {
+ helper(); // LINE_C.
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ (VmService service, IsolateRef isolate) async {
+ final isolateId = isolate.id!;
+ // Verify awaiter stack trace is the current frame + the awaiter.
+ Stack stack = await service.getStack(isolateId);
+ expect(stack.awaiterFrames, isNotNull);
+ List<Frame> awaiterFrames = stack.awaiterFrames!;
+ expect(awaiterFrames.length, greaterThanOrEqualTo(2));
+ // Awaiter frame.
+ expect(awaiterFrames[0].function!.owner.name, 'foobar');
+ // Awaiter frame.
+ expect(awaiterFrames[1].function!.owner.name, 'helper');
+ },
+];
+
+main(args) => runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'awaiter_async_stack_contents_2_test.dart',
+ testeeConcurrent: testMain,
+ extraArgs: extraDebuggingArgs,
+ );
diff --git a/pkg/vm_service/test/awaiter_async_stack_contents_test.dart b/pkg/vm_service/test/awaiter_async_stack_contents_test.dart
new file mode 100644
index 0000000..0fea350
--- /dev/null
+++ b/pkg/vm_service/test/awaiter_async_stack_contents_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2017, 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.
+//
+// VMOptions=--async-debugger --verbose-debug --lazy-async-stacks
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_C = 22;
+const LINE_A = 28;
+const LINE_B = 34;
+const LINE_D = 29;
+
+foobar() async {
+ await null;
+ debugger();
+ print('foobar'); // LINE_C.
+}
+
+helper() async {
+ await null;
+ debugger();
+ print('helper'); // LINE_A.
+ await foobar(); // LINE_D
+}
+
+testMain() {
+ debugger();
+ helper(); // LINE_B.
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (VmService service, IsolateRef isolateRef) async {
+ Stack stack = await service.getStack(isolateRef.id!);
+ // No awaiter frames because we are in a completely synchronous stack.
+ expect(stack.awaiterFrames, isNull);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ (VmService service, IsolateRef isolateRef) async {
+ // Verify awaiter stack trace is the current frame + the awaiter.
+ Stack stack = await service.getStack(isolateRef.id!);
+ expect(stack.awaiterFrames, isNotNull);
+ List<Frame> awaiterFrames = stack.awaiterFrames!;
+
+ expect(awaiterFrames.length, greaterThanOrEqualTo(2));
+ // Awaiter frame.
+ expect(await awaiterFrames[0].function!.owner.name, 'foobar');
+ // Awaiter frame.
+ expect(await awaiterFrames[1].function!.owner.name, 'helper');
+ // "helper" is not await'ed.
+ },
+];
+
+main(args) => runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'awaiter_async_stack_contents_test.dart',
+ testeeConcurrent: testMain,
+ extraArgs: extraDebuggingArgs,
+ );
diff --git a/pkg/vm_service/test/breakpoint_async_break_test.dart b/pkg/vm_service/test/breakpoint_async_break_test.dart
new file mode 100644
index 0000000..d0c2443
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_async_break_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2019, 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 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 18;
+
+// Issue: https://github.com/dart-lang/sdk/issues/36622
+Future<void> testMain() async {
+ for (int i = 0; i < 2; i++) {
+ if (i > 0) {
+ break; // breakpoint here
+ }
+ await Future.delayed(Duration(seconds: 1));
+ }
+}
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ // Test future breakpoints.
+ (VmService service, IsolateRef isolateRef) async {
+ final isolateId = isolateRef.id!;
+ final isolate = await service.getIsolate(isolateId);
+ final rootLib =
+ await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+ final scriptId = rootLib.scripts![0].id!;
+ final script = await service.getObject(isolateId, scriptId) as Script;
+
+ // Future breakpoint.
+ var futureBpt = await service.addBreakpoint(isolateId, scriptId, LINE);
+ expect(futureBpt.breakpointNumber, 1);
+ expect(futureBpt.resolved, isFalse);
+ expect(await futureBpt.location!.line, LINE);
+ expect(await futureBpt.location!.column, null);
+
+ final completer = Completer<void>();
+ int resolvedCount = 0;
+ late StreamSubscription subscription;
+ subscription = service.onDebugEvent.listen((event) {
+ if (event.kind == EventKind.kBreakpointResolved) {
+ resolvedCount++;
+ } else if (event.kind == EventKind.kPauseBreakpoint) {
+ subscription.cancel();
+ service.streamCancel(EventStreams.kDebug);
+ completer.complete();
+ }
+ });
+
+ await service.streamListen(EventStreams.kDebug);
+ await service.resume(isolateId);
+ await hasStoppedAtBreakpoint(service, isolate);
+
+ // After resolution the breakpoints have assigned line & column.
+ expect(resolvedCount, 1);
+ futureBpt = await service.getObject(isolateId, futureBpt.id!) as Breakpoint;
+ expect(futureBpt.resolved, isTrue);
+ expect(
+ script.getLineNumberFromTokenPos(futureBpt.location!.tokenPos), LINE);
+ expect(script.getColumnNumberFromTokenPos(futureBpt.location!.tokenPos), 7);
+
+ // Remove the breakpoints.
+ expect((await service.removeBreakpoint(isolateId, futureBpt.id!)).type,
+ 'Success');
+ },
+];
+
+main(args) => runIsolateTests(
+ args,
+ tests,
+ 'breakpoint_async_break_test.dart',
+ testeeConcurrent: testMain,
+ pause_on_start: true,
+ );
diff --git a/pkg/vm_service/test/breakpoint_in_package_parts_class_file_uri_test.dart b/pkg/vm_service/test/breakpoint_in_package_parts_class_file_uri_test.dart
new file mode 100644
index 0000000..70cd0fd
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_package_parts_class_file_uri_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, 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:io' show Platform;
+
+import 'package:path/path.dart' as path;
+import 'package:test_package/has_part.dart' as has_part;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+// Chop off the file name.
+String baseDirectory = path.dirname(Platform.script.path) + '/';
+Uri baseUri = Platform.script.replace(path: baseDirectory);
+Uri breakpointFile = baseUri.resolve('test_package/the_part.dart');
+const String shortFile = "the_part.dart";
+
+const int LINE = 87;
+
+code() {
+ has_part.main();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$shortFile:${LINE + 0}:5", // on 'print'
+ "$shortFile:${LINE + 1}:3" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(breakpointFile.toString(), LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main([args = const <String>[]]) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_in_package_parts_class_file_uri_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_in_package_parts_class_test.dart b/pkg/vm_service/test/breakpoint_in_package_parts_class_test.dart
new file mode 100644
index 0000000..2dcf30f
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_package_parts_class_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, 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 breakpoint_in_parts_class;
+
+import 'package:test_package/has_part.dart' as has_part;
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 87;
+const String breakpointFile = "package:test_package/the_part.dart";
+const String shortFile = "the_part.dart";
+
+code() {
+ has_part.main();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$shortFile:${LINE + 0}:5", // on 'print'
+ "$shortFile:${LINE + 1}:3" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(breakpointFile, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_in_package_parts_class_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_in_parts_class_part.dart b/pkg/vm_service/test/breakpoint_in_parts_class_part.dart
new file mode 100644
index 0000000..4855332
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_parts_class_part.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2017, 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 breakpoint_in_parts_class;
+
+void foo() {
+ print("lalala");
+}
+
+class Foo1 {
+ final foo;
+
+ Foo1(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo2 {
+ final foo;
+
+ Foo2(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo3 {
+ final foo;
+
+ Foo3(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo4 {
+ final foo;
+
+ Foo4(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo5 {
+ final foo;
+
+ Foo5(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo6 {
+ final foo;
+
+ Foo6(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo7 {
+ final foo;
+
+ Foo7(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo8 {
+ final foo;
+
+ Foo8(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo9 {
+ final foo;
+
+ Foo9(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo10 {
+ final foo;
+
+ Foo10(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+var foo2 = foo() as dynamic;
diff --git a/pkg/vm_service/test/breakpoint_in_parts_class_test.dart b/pkg/vm_service/test/breakpoint_in_parts_class_test.dart
new file mode 100644
index 0000000..89f4e7f
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_parts_class_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2017, 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 breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+part 'breakpoint_in_parts_class_part.dart';
+
+const int LINE = 87;
+const String file = "breakpoint_in_parts_class_part.dart";
+
+code() {
+ final foo = Foo10("Foo!");
+ print(foo);
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$file:${LINE + 0}:5", // on 'print'
+ "$file:${LINE + 1}:3" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(file, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_in_parts_class_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_non_debuggable_library_test.dart b/pkg/vm_service/test/breakpoint_non_debuggable_library_test.dart
new file mode 100644
index 0000000..4ecd5c4
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_non_debuggable_library_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2019, 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:test_package/has_part.dart' as test_pkg;
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const String file = 'package:test_package/has_part.dart';
+// print() within fooz()
+const int LINE_A = 15;
+// print() within barz()
+const int LINE_B = 11;
+
+testMain() {
+ test_pkg.fooz();
+}
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ (VmService service, IsolateRef isolateRef) async {
+ // Mark 'package:observatory_test_package/has_part.dart' as not debuggable.
+ final isolateId = isolateRef.id!;
+ final isolate = await service.getIsolate(isolateId);
+
+ LibraryRef has_part_ref = isolate.libraries!.firstWhere(
+ (LibraryRef library) => library.uri == file,
+ );
+
+ Library has_part =
+ await service.getObject(isolateId, has_part_ref.id!) as Library;
+ expect(has_part.debuggable, true);
+ // SetBreakpoint before setting library to non-debuggable.
+ // Breakpoints are allowed to be set (before marking library as
+ // non-debuggable) but are not hit when running (after marking library
+ // as non-debuggable).
+ ScriptRef script = has_part.scripts!.firstWhere(
+ (ScriptRef script) => script.uri == file,
+ );
+ Breakpoint bpt = await service.addBreakpoint(isolateId, script.id!, LINE_A);
+ print("Breakpoint is $bpt");
+ expect(bpt, isNotNull);
+
+ // Set breakpoint and check later that this breakpoint won't be added if
+ // the library is non-debuggable.
+ bpt = await service.addBreakpoint(isolateId, script.id!, LINE_B);
+ print("Breakpoint is $bpt");
+ expect(bpt, isNotNull);
+
+ // Remove breakpoint.
+ final res = await service.removeBreakpoint(isolateId, bpt.id!);
+ expect(res.type, 'Success');
+
+ await service.setLibraryDebuggable(isolateId, has_part.id!, false);
+ has_part = await service.getObject(isolateId, has_part.id!) as Library;
+ expect(has_part.debuggable, false);
+ print('$has_part is debuggable: ${has_part.debuggable}');
+
+ // Breakpoints are not allowed to set on non-debuggable libraries.
+ try {
+ await service.addBreakpoint(isolateId, script.id!, LINE_B);
+ } on RPCError catch (e) {
+ // Cannot add breakpoint error code
+ expect(e.code, 102);
+ expect(e.details, contains("Cannot add breakpoint at line '11'"));
+ print("Set Breakpoint to non-debuggable library is not allowed");
+ }
+ },
+ resumeIsolate,
+ hasStoppedAtExit,
+];
+
+main(args) => runIsolateTests(
+ args,
+ tests,
+ 'breakpoint_non_debuggable_library_test.dart',
+ testeeConcurrent: testMain,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_1_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_1_test.dart
new file mode 100644
index 0000000..c46cabe
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_1_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2019, 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 breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 18;
+const String file = "breakpoint_on_if_null_1_test.dart";
+
+code() {
+ foo(42);
+}
+
+foo(dynamic args) {
+ if (args == null) {
+ print("was null");
+ }
+ if (args != null) {
+ print("was not null");
+ }
+ if (args == 42) {
+ print("was 42!");
+ }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$file:${LINE + 0}:12", // on '=='
+ "$file:${LINE + 3}:12", // on '!='
+ "$file:${LINE + 4}:5", // on 'print'
+ "$file:${LINE + 6}:12", // on '=='
+ "$file:${LINE + 7}:5", // on 'print'
+ "$file:${LINE + 9}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(file, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_on_if_null_1_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_2_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_2_test.dart
new file mode 100644
index 0000000..69bee59
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_2_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2019, 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 breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 21;
+const String file = "breakpoint_on_if_null_2_test.dart";
+
+dynamic compareWithMe = 43;
+
+code() {
+ compareWithMe = null;
+ foo(42);
+}
+
+foo(dynamic args) {
+ if (args == compareWithMe) {
+ print("was null");
+ }
+ if (args != compareWithMe) {
+ print("was not null");
+ }
+ if (args == 42) {
+ print("was 42!");
+ }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$file:${LINE + 0}:12", // on '=='
+ "$file:${LINE + 3}:12", // on '!='
+ "$file:${LINE + 4}:5", // on 'print'
+ "$file:${LINE + 6}:12", // on '=='
+ "$file:${LINE + 7}:5", // on 'print'
+ "$file:${LINE + 9}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(file, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_on_if_null_2_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_3_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_3_test.dart
new file mode 100644
index 0000000..9211410
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_3_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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 breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 17;
+const String file = "breakpoint_on_if_null_3_test.dart";
+
+code() {
+ foo(42);
+}
+
+foo(dynamic args) {
+ if (args == null) {
+ print("was null");
+ }
+ if (args != null) {
+ print("was not null");
+ }
+ if (args == 42) {
+ print("was 42!");
+ }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$file:${LINE + 0}:13", // on 'args'
+ "$file:${LINE + 1}:12", // on '=='
+ "$file:${LINE + 4}:12", // on '!='
+ "$file:${LINE + 5}:5", // on 'print'
+ "$file:${LINE + 7}:12", // on '=='
+ "$file:${LINE + 8}:5", // on 'print'
+ "$file:${LINE + 10}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(file, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_on_if_null_3_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_4_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_4_test.dart
new file mode 100644
index 0000000..08b7760
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_4_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2019, 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 breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 20;
+const String file = "breakpoint_on_if_null_4_test.dart";
+
+dynamic compareWithMe = 43;
+
+code() {
+ compareWithMe = null;
+ foo(42);
+}
+
+foo(dynamic args) {
+ if (args == compareWithMe) {
+ print("was null");
+ }
+ if (args != compareWithMe) {
+ print("was not null");
+ }
+ if (args == 42) {
+ print("was 42!");
+ }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$file:${LINE + 0}:13", // on 'args'
+ "$file:${LINE + 1}:12", // on '=='
+ "$file:${LINE + 4}:12", // on '!='
+ "$file:${LINE + 5}:5", // on 'print'
+ "$file:${LINE + 7}:12", // on '=='
+ "$file:${LINE + 8}:5", // on 'print'
+ "$file:${LINE + 10}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(file, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_on_if_null_4_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_partfile_test.dart b/pkg/vm_service/test/breakpoint_partfile_test.dart
new file mode 100644
index 0000000..a3c5fd1
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_partfile_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, 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 breakpoint_in_parts_class;
+
+import 'package:test_package/has_part.dart' as has_part;
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 8;
+const String breakpointFile = "package:test_package/the_part_2.dart";
+const String shortFile = "the_part_2.dart";
+
+code() {
+ has_part.bar();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$shortFile:${LINE + 0}:3", // on 'print'
+ "$shortFile:${LINE + 1}:1" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(breakpointFile, LINE),
+ runStepThroughProgramRecordingStops(stops),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoint_partfile_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/breakpoint_two_args_checked_test.dart b/pkg/vm_service/test/breakpoint_two_args_checked_test.dart
new file mode 100644
index 0000000..40d0dc6
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_two_args_checked_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2016, 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.
+// VMOptions=--verbose_debug
+
+// TODO(bkonyi): consider deleting now that DBC is no more.
+// This test was mostly interesting for DBC, which needed to patch two bytecodes
+// to create a breakpoint for fast Smi ops.
+
+import 'dart:developer';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 29;
+const int LINE_B = 30;
+const int LINE_C = 31;
+
+class NotGeneric {}
+
+testeeMain() {
+ final x = List<dynamic>.filled(1, null);
+ final y = 7;
+ debugger();
+ print("Statement");
+ x[0] = 3; // Line A.
+ x is NotGeneric; // Line B.
+ y & 4; // Line C.
+}
+
+final tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+
+// Add breakpoints.
+ (VmService service, IsolateRef isolateRef) async {
+ final isolateId = isolateRef.id!;
+ final isolate = await service.getIsolate(isolateId);
+ Library rootLib =
+ await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+
+ final script =
+ await service.getObject(isolateId, rootLib.scripts![0].id!) as Script;
+ final scriptId = script.id!;
+
+ final bpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
+ print(bpt1);
+ expect(bpt1.resolved, isTrue);
+ expect(script.getLineNumberFromTokenPos(bpt1.location!.tokenPos),
+ equals(LINE_A));
+
+ final bpt2 = await service.addBreakpoint(isolateId, scriptId, LINE_B);
+ print(bpt2);
+ expect(bpt2.resolved, isTrue);
+ expect(script.getLineNumberFromTokenPos(bpt2.location!.tokenPos),
+ equals(LINE_B));
+
+ final bpt3 = await service.addBreakpoint(isolateId, scriptId, LINE_C);
+ print(bpt3);
+ expect(bpt3.resolved, isTrue);
+ expect(script.getLineNumberFromTokenPos(bpt3.location!.tokenPos),
+ equals(LINE_C));
+ },
+
+ resumeIsolate,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ resumeIsolate,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ resumeIsolate,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ resumeIsolate,
+];
+
+main(args) => runIsolateTests(
+ args,
+ tests,
+ 'breakpoint_two_args_checked_test.dart',
+ testeeConcurrent: testeeMain,
+ );
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_lib1.dart b/pkg/vm_service/test/breakpoints_with_mixin_lib1.dart
new file mode 100644
index 0000000..3c43715
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_lib1.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib3.dart";
+
+class Test1 extends Object with Foo {}
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_lib2.dart b/pkg/vm_service/test/breakpoints_with_mixin_lib2.dart
new file mode 100644
index 0000000..c054176
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_lib2.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib3.dart";
+
+class Test2 extends Object with Foo {}
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_lib3.dart b/pkg/vm_service/test/breakpoints_with_mixin_lib3.dart
new file mode 100644
index 0000000..a7329de
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_lib3.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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.
+
+class Foo {
+ foo() {
+ print("I should be breakable!");
+ }
+}
+
+class Bar {
+ bar() {
+ print("I should be breakable too!");
+ }
+}
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_test.dart b/pkg/vm_service/test/breakpoints_with_mixin_test.dart
new file mode 100644
index 0000000..f382628
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib1.dart";
+import "breakpoints_with_mixin_lib2.dart";
+import "breakpoints_with_mixin_lib3.dart";
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const String testFilename = "breakpoints_with_mixin_test.dart";
+const int testCodeLineStart = 17;
+const String lib3Filename = "breakpoints_with_mixin_lib3.dart";
+const int lib3Bp1 = 7;
+const int lib3Bp2 = 13;
+
+void code() {
+ Test1 test1 = Test1();
+ test1.foo();
+ Test2 test2 = Test2();
+ test2.foo();
+ Foo foo = Foo();
+ foo.foo();
+ Bar bar = Bar();
+ bar.bar();
+ test1.foo();
+ test2.foo();
+ foo.foo();
+ bar.bar();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+ "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 2}:9)",
+ "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 4}:9)",
+ "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 6}:7)",
+ "$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 8}:7)",
+ "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 9}:9)",
+ "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 10}:9)",
+ "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 11}:7)",
+ "$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 12}:7)",
+];
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtUriAndLine(lib3Filename, lib3Bp1),
+ setBreakpointAtUriAndLine(lib3Filename, lib3Bp2),
+ resumeProgramRecordingStops(stops, true),
+ checkRecordedStops(stops, expected)
+];
+
+main(args) {
+ runIsolateTestsSynchronous(
+ args,
+ tests,
+ 'breakpoints_with_mixin_test.dart',
+ testeeConcurrent: code,
+ pause_on_start: true,
+ pause_on_exit: true,
+ );
+}
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
index 4f616ab..6e84d16 100644
--- a/pkg/vm_service/test/common/service_test_common.dart
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -6,6 +6,7 @@
import 'dart:async';
+import 'package:path/path.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
@@ -131,6 +132,16 @@
};
}
+IsolateTest setBreakpointAtUriAndLine(String uri, int line) {
+ return (VmService service, IsolateRef isolateRef) async {
+ print("Setting breakpoint for line $line in $uri");
+ Breakpoint bpt =
+ await service.addBreakpointWithScriptUri(isolateRef.id!, uri, line);
+ print("Breakpoint is $bpt");
+ expect(bpt, isNotNull);
+ };
+}
+
IsolateTest stoppedAtLine(int line) {
return (VmService service, IsolateRef isolateRef) async {
print("Checking we are at line $line");
@@ -221,3 +232,154 @@
await hasStoppedAtBreakpoint(service, isolateRef);
await _unsubscribeDebugStream(service);
}
+
+IsolateTest resumeProgramRecordingStops(
+ List<String> recordStops, bool includeCaller) {
+ return (VmService service, IsolateRef isolateRef) async {
+ final completer = Completer<void>();
+
+ late StreamSubscription subscription;
+ subscription = service.onDebugEvent.listen((event) async {
+ if (event.kind == EventKind.kPauseBreakpoint) {
+ final stack = await service.getStack(isolateRef.id!);
+ final frames = stack.frames!;
+ expect(frames.length, greaterThanOrEqualTo(2));
+
+ String brokeAt =
+ await _locationToString(service, isolateRef, frames[0]);
+ if (includeCaller) {
+ brokeAt =
+ '$brokeAt (${await _locationToString(service, isolateRef, frames[1])})';
+ }
+ recordStops.add(brokeAt);
+ await service.resume(isolateRef.id!);
+ } else if (event.kind == EventKind.kPauseExit) {
+ await subscription.cancel();
+ await service.streamCancel(EventStreams.kDebug);
+ completer.complete();
+ }
+ });
+
+ await service.streamListen(EventStreams.kDebug);
+ await service.resume(isolateRef.id!);
+ return completer.future;
+ };
+}
+
+Future<String> _locationToString(
+ VmService service,
+ IsolateRef isolateRef,
+ Frame frame,
+) async {
+ final location = frame.location!;
+ Script script =
+ await service.getObject(isolateRef.id!, location.script!.id!) as Script;
+ final scriptName = basename(script.uri!);
+ final tokenPos = location.tokenPos!;
+ final line = script.getLineNumberFromTokenPos(tokenPos);
+ final column = script.getColumnNumberFromTokenPos(tokenPos);
+ return '$scriptName:$line:$column';
+}
+
+IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) {
+ return (VmService service, IsolateRef isolateRef) async {
+ final completer = Completer<void>();
+
+ late StreamSubscription subscription;
+ subscription = service.onDebugEvent.listen((event) async {
+ if (event.kind == EventKind.kPauseBreakpoint) {
+ final isolate = await service.getIsolate(isolateRef.id!);
+ final frame = isolate.pauseEvent!.topFrame!;
+ recordStops.add(await _locationToString(service, isolateRef, frame));
+ if (event.atAsyncSuspension ?? false) {
+ await service.resume(isolateRef.id!,
+ step: StepOption.kOverAsyncSuspension);
+ } else {
+ await service.resume(isolateRef.id!, step: StepOption.kOver);
+ }
+ } else if (event.kind == EventKind.kPauseExit) {
+ await subscription.cancel();
+ await service.streamCancel(EventStreams.kDebug);
+ completer.complete();
+ }
+ });
+
+ await service.streamListen(EventStreams.kDebug);
+ await service.resume(isolateRef.id!);
+ return completer.future;
+ };
+}
+
+IsolateTest checkRecordedStops(
+ List<String> recordStops, List<String> expectedStops,
+ {bool removeDuplicates = false,
+ bool debugPrint = false,
+ String? debugPrintFile,
+ int? debugPrintLine}) {
+ return (VmService service, IsolateRef isolate) async {
+ if (debugPrint) {
+ for (int i = 0; i < recordStops.length; i++) {
+ String line = recordStops[i];
+ String output = line;
+ int firstColon = line.indexOf(":");
+ int lastColon = line.lastIndexOf(":");
+ if (debugPrintFile != null &&
+ debugPrintLine != null &&
+ firstColon > 0 &&
+ lastColon > 0) {
+ int lineNumber = int.parse(line.substring(firstColon + 1, lastColon));
+ int relativeLineNumber = lineNumber - debugPrintLine;
+ var columnNumber = line.substring(lastColon + 1);
+ var file = line.substring(0, firstColon);
+ if (file == debugPrintFile) {
+ output = '\$file:\${LINE+$relativeLineNumber}:$columnNumber';
+ }
+ }
+ String comma = i == recordStops.length - 1 ? "" : ",";
+ print('"$output"$comma');
+ }
+ }
+ if (removeDuplicates) {
+ recordStops = removeAdjacentDuplicates(recordStops);
+ expectedStops = removeAdjacentDuplicates(expectedStops);
+ }
+
+ // Single stepping may record extra stops.
+ // Allow the extra ones as long as the expected ones are recorded.
+ int i = 0;
+ int j = 0;
+ while (i < recordStops.length && j < expectedStops.length) {
+ if (recordStops[i] != expectedStops[j]) {
+ // Check if recordStops[i] is an extra stop.
+ int k = i + 1;
+ while (k < recordStops.length && recordStops[k] != expectedStops[j]) {
+ k++;
+ }
+ if (k < recordStops.length) {
+ // Allow and ignore extra recorded stops from i to k-1.
+ i = k;
+ } else {
+ // This will report an error.
+ expect(recordStops[i], expectedStops[j]);
+ }
+ }
+ i++;
+ j++;
+ }
+
+ expect(recordStops.length >= expectedStops.length, true,
+ reason: "Expects at least ${expectedStops.length} breaks, "
+ "got ${recordStops.length}.");
+ };
+}
+
+List<String> removeAdjacentDuplicates(List<String> fromList) {
+ List<String> result = <String>[];
+ String? latestLine;
+ for (String s in fromList) {
+ if (s == latestLine) continue;
+ latestLine = s;
+ result.add(s);
+ }
+ return result;
+}
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 45ce97b..585722f 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -277,6 +277,7 @@
vm = await vmServiceConnectUri(serviceWebsocketAddress);
print('Done loading VM');
isolate = await getFirstIsolate(vm);
+ print('Got first isolate');
});
});
@@ -326,19 +327,24 @@
Completer<dynamic>? completer = Completer();
late StreamSubscription subscription;
subscription = service.onIsolateEvent.listen((Event event) async {
+ print('Isolate event: $event');
if (completer == null) {
await subscription.cancel();
return;
}
if (event.kind == EventKind.kIsolateRunnable) {
+ print(event.isolate!.name);
vm = await service.getVM();
- assert(vmIsolates.isNotEmpty);
+ //assert(vmIsolates.isNotEmpty);
await subscription.cancel();
- completer!.complete(vmIsolates.first);
+ await service.streamCancel(EventStreams.kIsolate);
+ completer!.complete(event.isolate!);
completer = null;
}
});
+ await service.streamListen(EventStreams.kIsolate);
+
// The isolate may have started before we subscribed.
vm = await service.getVM();
if (vmIsolates.isNotEmpty) {
diff --git a/pkg/vm_service/test/test_package/has_part.dart b/pkg/vm_service/test/test_package/has_part.dart
new file mode 100644
index 0000000..fb68ee7
--- /dev/null
+++ b/pkg/vm_service/test/test_package/has_part.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, 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 has_part;
+
+part 'the_part.dart';
+part 'the_part_2.dart';
+
+barz() {
+ print('in bar!');
+}
+
+fooz() {
+ print('in foo!');
+ bar();
+}
+
+main() {
+ Foo10 foo = Foo10("Foo!");
+ print(foo);
+}
diff --git a/pkg/vm_service/test/test_package/pubspec.yaml b/pkg/vm_service/test/test_package/pubspec.yaml
new file mode 100644
index 0000000..b5bc9d7
--- /dev/null
+++ b/pkg/vm_service/test/test_package/pubspec.yaml
@@ -0,0 +1,4 @@
+name: test_package
+publish_to: none
+environment:
+ sdk: '>=2.12.0-0 <3.0.0'
diff --git a/pkg/vm_service/test/test_package/the_part.dart b/pkg/vm_service/test/test_package/the_part.dart
new file mode 100644
index 0000000..d8545f8
--- /dev/null
+++ b/pkg/vm_service/test/test_package/the_part.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, 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 has_part;
+
+void foo() {
+ print("lalala");
+}
+
+class Foo1 {
+ final foo;
+
+ Foo1(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo2 {
+ final foo;
+
+ Foo2(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo3 {
+ final foo;
+
+ Foo3(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo4 {
+ final foo;
+
+ Foo4(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo5 {
+ final foo;
+
+ Foo5(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo6 {
+ final foo;
+
+ Foo6(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo7 {
+ final foo;
+
+ Foo7(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo8 {
+ final foo;
+
+ Foo8(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo9 {
+ final foo;
+
+ Foo9(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+class Foo10 {
+ final foo;
+
+ Foo10(this.foo) {
+ print("hello from foo!");
+ }
+}
+
+var foo2 = foo() as dynamic;
diff --git a/pkg/vm_service/test/test_package/the_part_2.dart b/pkg/vm_service/test/test_package/the_part_2.dart
new file mode 100644
index 0000000..c38df9c
--- /dev/null
+++ b/pkg/vm_service/test/test_package/the_part_2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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 has_part;
+
+void bar() {
+ print('Should break here');
+}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index e474f19..37f1772 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -222,7 +222,7 @@
if (Dart_IsError(result)) goto failed;
} else {
result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
- if (Dart_IsError(result)) return result != nullptr;
+ if (Dart_IsError(result)) goto failed;
if (isolate_group_data->kernel_buffer().get() != nullptr) {
// Various core-library parts will send requests to the Loader to resolve
diff --git a/tests/standalone/io/directory_rename_test.dart b/tests/standalone/io/directory_rename_test.dart
index 9d31374..0d31c07 100644
--- a/tests/standalone/io/directory_rename_test.dart
+++ b/tests/standalone/io/directory_rename_test.dart
@@ -51,7 +51,8 @@
// On Windows, the directory will be *deleted*.
Expect.isFalse(dir.existsSync());
Expect.isTrue(
- e.osError!.message.contains('cannot find the file specified'));
+ e.osError!.message.contains('cannot find the file specified'),
+ 'Unexpected error: $e');
} else {
Expect.fail('Directory.rename to same path should not fail on '
'${Platform.operatingSystem} (${Platform.operatingSystemVersion}): '
@@ -74,9 +75,11 @@
Expect.fail('Directory.rename should fail to rename a non-directory');
} on FileSystemException catch (e) {
if (Platform.isLinux || Platform.isMacOS) {
- Expect.isTrue(e.osError!.message.contains('Not a directory'));
+ Expect.isTrue(e.osError!.message.contains('Not a directory'),
+ 'Unexpected error: $e');
} else if (Platform.isWindows) {
- Expect.isTrue(e.osError!.message.contains('file already exists'));
+ Expect.isTrue(e.osError!.message.contains('file already exists'),
+ 'Unexpected error: $e');
}
}
});
@@ -122,7 +125,8 @@
}
} on FileSystemException catch (e) {
if (Platform.isLinux || Platform.isMacOS) {
- Expect.isTrue(e.osError!.message.contains('Directory not empty'));
+ Expect.isTrue(e.osError!.message.contains('Directory not empty'),
+ 'Unexpected error: $e');
}
}
});
diff --git a/tests/standalone/io/platform_test.dart b/tests/standalone/io/platform_test.dart
index dacd0a8..3729439 100644
--- a/tests/standalone/io/platform_test.dart
+++ b/tests/standalone/io/platform_test.dart
@@ -8,6 +8,18 @@
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
+final executableSuffix = Platform.isWindows ? '.exe' : '';
+final jitExecutableName = 'dart$executableSuffix';
+final aotExecutableName = 'dart_precompiled_runtime$executableSuffix';
+
+bool hasJitOrAotExecutableName(String executable) =>
+ executable.endsWith(jitExecutableName) ||
+ executable.endsWith(aotExecutableName);
+
+bool isRunningFromSource() =>
+ Platform.executable.endsWith(jitExecutableName) &&
+ Platform.script.toFilePath().endsWith('.dart');
+
test() {
Expect.isTrue(Platform.numberOfProcessors > 0);
var os = Platform.operatingSystem;
@@ -23,13 +35,10 @@
Expect.isTrue(hostname is String && hostname != "");
var environment = Platform.environment;
Expect.isTrue(environment is Map<String, String>);
- if (!Platform.isWindows) {
- Expect.isTrue(Platform.executable.endsWith('dart'));
- Expect.isTrue(Platform.resolvedExecutable.endsWith('dart'));
- } else {
- Expect.isTrue(Platform.executable.endsWith('dart.exe'));
- Expect.isTrue(Platform.resolvedExecutable.endsWith('dart.exe'));
- }
+
+ Expect.isTrue(hasJitOrAotExecutableName(Platform.executable));
+ Expect.isTrue(hasJitOrAotExecutableName(Platform.resolvedExecutable));
+
if (!Platform.isWindows) {
Expect.isTrue(Platform.resolvedExecutable.startsWith('/'));
} else {
@@ -42,9 +51,11 @@
// Move directory to be sure script is correct.
var oldDir = Directory.current;
Directory.current = Directory.current.parent;
- Expect.isTrue(
- Platform.script.path.endsWith('tests/standalone/io/platform_test.dart'));
- Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+ if (isRunningFromSource()) {
+ Expect.isTrue(Platform.script.path
+ .endsWith('tests/standalone/io/platform_test.dart'));
+ Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+ }
}
void f(reply) {
@@ -58,7 +69,7 @@
testIsolate() {
asyncStart();
ReceivePort port = new ReceivePort();
- var remote = Isolate.spawn(f, port.sendPort);
+ Isolate.spawn(f, port.sendPort);
port.first.then((results) {
Expect.equals(Platform.executable, results["Platform.executable"]);
@@ -66,7 +77,10 @@
// SpawnFunction retains the script url of the parent which in this
// case was a relative path.
Expect.equals("file", uri.scheme);
- Expect.isTrue(uri.path.endsWith('tests/standalone/io/platform_test.dart'));
+ if (isRunningFromSource()) {
+ Expect.isTrue(
+ uri.path.endsWith('tests/standalone/io/platform_test.dart'));
+ }
Expect.listEquals(
Platform.executableArguments, results["Platform.executableArguments"]);
asyncEnd();
diff --git a/tests/standalone/standalone_kernel.status b/tests/standalone/standalone_kernel.status
index a628ff4..a958509 100644
--- a/tests/standalone/standalone_kernel.status
+++ b/tests/standalone/standalone_kernel.status
@@ -91,7 +91,6 @@
io/http_server_close_response_after_error_test: Skip # Flaky.
io/http_shutdown_test: Skip # Flaky.
io/https_client_certificate_test: Crash
-io/platform_test: Crash
io/raw_datagram_socket_test: Skip # Flaky.
io/raw_secure_server_closing_test: Skip # Flaky
io/raw_socket_test: Crash
diff --git a/tests/standalone/standalone_precompiled.status b/tests/standalone/standalone_precompiled.status
index f6c27d2..536731b 100644
--- a/tests/standalone/standalone_precompiled.status
+++ b/tests/standalone/standalone_precompiled.status
@@ -21,7 +21,6 @@
io/named_pipe_script_test: Skip
io/namespace_test: Skip # Issue 33168
io/platform_resolved_executable_test: Skip
-io/platform_test: RuntimeError # Expects to be running from 'dart' instead of 'dart_precompiled_runtime'
io/print_sync_test: Skip
io/process_check_arguments_test: Skip
io/process_detached_test: Skip
diff --git a/tests/standalone_2/io/directory_rename_test.dart b/tests/standalone_2/io/directory_rename_test.dart
index e943a8a..50af674 100644
--- a/tests/standalone_2/io/directory_rename_test.dart
+++ b/tests/standalone_2/io/directory_rename_test.dart
@@ -53,7 +53,8 @@
// On Windows, the directory will be *deleted*.
Expect.isFalse(dir.existsSync());
Expect.isTrue(
- e.osError.message.contains('cannot find the file specified'));
+ e.osError.message.contains('cannot find the file specified'),
+ 'Unexpected error: $e');
} else {
Expect.fail('Directory.rename to same path should not fail on '
'${Platform.operatingSystem} (${Platform.operatingSystemVersion}): '
@@ -76,9 +77,11 @@
Expect.fail('Directory.rename should fail to rename a non-directory');
} on FileSystemException catch (e) {
if (Platform.isLinux || Platform.isMacOS) {
- Expect.isTrue(e.osError.message.contains('Not a directory'));
+ Expect.isTrue(e.osError.message.contains('Not a directory'),
+ 'Unexpected error: $e');
} else if (Platform.isWindows) {
- Expect.isTrue(e.osError.message.contains('file already exists'));
+ Expect.isTrue(e.osError.message.contains('file already exists'),
+ 'Unexpected error: $e');
}
}
});
@@ -124,7 +127,8 @@
}
} on FileSystemException catch (e) {
if (Platform.isLinux || Platform.isMacOS) {
- Expect.isTrue(e.osError.message.contains('Directory not empty'));
+ Expect.isTrue(e.osError.message.contains('Directory not empty'),
+ 'Unexpected error: $e');
}
}
});
diff --git a/tests/standalone_2/io/platform_test.dart b/tests/standalone_2/io/platform_test.dart
index dfe18ba..e58632d 100644
--- a/tests/standalone_2/io/platform_test.dart
+++ b/tests/standalone_2/io/platform_test.dart
@@ -10,6 +10,18 @@
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
+final executableSuffix = Platform.isWindows ? '.exe' : '';
+final jitExecutableName = 'dart$executableSuffix';
+final aotExecutableName = 'dart_precompiled_runtime$executableSuffix';
+
+bool hasJitOrAotExecutableName(String executable) =>
+ executable.endsWith(jitExecutableName) ||
+ executable.endsWith(aotExecutableName);
+
+bool isRunningFromSource() =>
+ Platform.executable.endsWith(jitExecutableName) &&
+ Platform.script.toFilePath().endsWith('.dart');
+
test() {
Expect.isTrue(Platform.numberOfProcessors > 0);
var os = Platform.operatingSystem;
@@ -25,13 +37,10 @@
Expect.isTrue(hostname is String && hostname != "");
var environment = Platform.environment;
Expect.isTrue(environment is Map<String, String>);
- if (!Platform.isWindows) {
- Expect.isTrue(Platform.executable.endsWith('dart'));
- Expect.isTrue(Platform.resolvedExecutable.endsWith('dart'));
- } else {
- Expect.isTrue(Platform.executable.endsWith('dart.exe'));
- Expect.isTrue(Platform.resolvedExecutable.endsWith('dart.exe'));
- }
+
+ Expect.isTrue(hasJitOrAotExecutableName(Platform.executable));
+ Expect.isTrue(hasJitOrAotExecutableName(Platform.resolvedExecutable));
+
if (!Platform.isWindows) {
Expect.isTrue(Platform.resolvedExecutable.startsWith('/'));
} else {
@@ -44,9 +53,11 @@
// Move directory to be sure script is correct.
var oldDir = Directory.current;
Directory.current = Directory.current.parent;
- Expect.isTrue(Platform.script.path
- .endsWith('tests/standalone_2/io/platform_test.dart'));
- Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+ if (isRunningFromSource()) {
+ Expect.isTrue(Platform.script.path
+ .endsWith('tests/standalone_2/io/platform_test.dart'));
+ Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+ }
}
void f(reply) {
@@ -60,7 +71,7 @@
testIsolate() {
asyncStart();
ReceivePort port = new ReceivePort();
- var remote = Isolate.spawn(f, port.sendPort);
+ Isolate.spawn(f, port.sendPort);
port.first.then((results) {
Expect.equals(Platform.executable, results["Platform.executable"]);
@@ -68,8 +79,10 @@
// SpawnFunction retains the script url of the parent which in this
// case was a relative path.
Expect.equals("file", uri.scheme);
- Expect.isTrue(
- uri.path.endsWith('tests/standalone_2/io/platform_test.dart'));
+ if (isRunningFromSource()) {
+ Expect.isTrue(
+ uri.path.endsWith('tests/standalone_2/io/platform_test.dart'));
+ }
Expect.listEquals(
Platform.executableArguments, results["Platform.executableArguments"]);
asyncEnd();
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index 548f99c..77236ea 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -93,7 +93,6 @@
io/http_server_close_response_after_error_test: Skip # Flaky.
io/http_shutdown_test: Skip # Flaky.
io/https_client_certificate_test: Crash
-io/platform_test: Crash
io/raw_datagram_socket_test: Skip # Flaky.
io/raw_secure_server_closing_test: Skip # Flaky
io/raw_socket_test: Crash
diff --git a/tests/standalone_2/standalone_2_precompiled.status b/tests/standalone_2/standalone_2_precompiled.status
index cf466ae..07c20e7 100644
--- a/tests/standalone_2/standalone_2_precompiled.status
+++ b/tests/standalone_2/standalone_2_precompiled.status
@@ -18,7 +18,6 @@
io/named_pipe_script_test: Skip
io/namespace_test: Skip # Issue 33168
io/platform_resolved_executable_test: Skip
-io/platform_test: RuntimeError # Expects to be running from 'dart' instead of 'dart_precompiled_runtime'
io/print_sync_test: Skip
io/process_check_arguments_test: Skip
io/process_detached_test: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 0754943..87e29e7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 291
+PRERELEASE 292
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/generate_package_config.dart b/tools/generate_package_config.dart
index 066eb2c..d6c7b56 100644
--- a/tools/generate_package_config.dart
+++ b/tools/generate_package_config.dart
@@ -56,6 +56,7 @@
packageDirectory('runtime/observatory_2'),
packageDirectory(
'runtime/observatory_2/tests/service_2/observatory_test_package_2'),
+ packageDirectory('pkg/vm_service/test/test_package'),
packageDirectory('sdk/lib/_internal/sdk_library_metadata'),
packageDirectory('third_party/devtools/devtools_server'),
packageDirectory('third_party/devtools/devtools_shared'),