Skip to content

Commit 5b4cc4f

Browse files
authored
Use evaluate instead of periodic timer to test dot shorthands (#2687)
Fixes #2638 Fields are cached after their first execution. When debugging, this means we may not hit the body of the field when using the AMD module format. The DDC library bundle format always has a getter for fields, even with the cached value, however. To make the test consistent, we should avoid any previous executions of the field by using an evaluate call instead of a periodic timer in main. This requires moving the dot shorthands test to its own fixture.
1 parent d2e5593 commit 5b4cc4f

File tree

6 files changed

+99
-47
lines changed

6 files changed

+99
-47
lines changed

dwds/test/fixtures/project.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ class TestProject {
121121
htmlEntryFileName: 'index.html',
122122
);
123123

124+
static final testDotShorthands = TestProject._(
125+
packageName: '_test_dot_shorthands',
126+
packageDirectory: '_test_dot_shorthands',
127+
webAssetsPath: 'web',
128+
dartEntryFileName: 'main.dart',
129+
htmlEntryFileName: 'index.html',
130+
);
131+
124132
static final testHotRestart1 = TestProject._(
125133
packageName: '_test_hot_restart1',
126134
packageDirectory: '_test_hot_restart1',

dwds/test/instances/common/dot_shorthands_common.dart

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:dwds/src/services/expression_compiler.dart' show ModuleFormat;
65
import 'package:path/path.dart' show basename;
76
import 'package:test/test.dart';
87
import 'package:test_common/logging.dart';
@@ -20,7 +19,7 @@ void runTests({
2019
required bool canaryFeatures,
2120
required bool debug,
2221
}) {
23-
final context = TestContext(TestProject.testExperiment, provider);
22+
final context = TestContext(TestProject.testDotShorthands, provider);
2423
final testInspector = TestInspector(context);
2524

2625
late VmService service;
@@ -73,8 +72,8 @@ void runTests({
7372
await context.tearDown();
7473
});
7574

76-
test('expression evaluation and single-stepping', () async {
77-
await onBreakpoint('testDotShorthands', (event) async {
75+
test('expression evaluation', () async {
76+
final bp = onBreakpoint('testDotShorthands', (event) async {
7877
final frame = event.topFrame!.index!;
7978

8079
var instanceRef = await getInstanceRef(frame, '(c = .two).value');
@@ -86,22 +85,36 @@ void runTests({
8685
instanceRef = await getInstanceRef(frame, '(c = .four()).value');
8786
expect(instanceRef.valueAsString, '4');
8887

88+
await service.resume(isolateId);
89+
});
90+
final isolate = await service.getIsolate(isolateId);
91+
await service.evaluate(
92+
isolateId,
93+
isolate.rootLib!.id!,
94+
'testDotShorthands()',
95+
);
96+
await bp;
97+
});
98+
99+
test('single-stepping', () async {
100+
final bp = onBreakpoint('testDotShorthands', (event) async {
89101
final scriptBasename = basename(mainScript.uri!);
90102

91-
const lineA = 116;
92-
const lineB = 118;
93-
const lineC = 119;
94-
const lineD = 120;
95-
const lineE = 127;
96-
const lineF = 129;
97-
const lineG = 131;
98-
const lineH = 132;
103+
const lineA = 9;
104+
const lineB = 11;
105+
const lineC = 12;
106+
const lineD = 13;
107+
const lineE = 20;
108+
const lineF = 22;
109+
const lineG = 24;
110+
const lineH = 25;
99111

100112
final expected = [
101113
'$scriptBasename:$lineE:3', // on 'c'
102-
// TODO(2638): Investigate why this conditional exclusion is needed.
103-
if (provider.ddcModuleFormat == ModuleFormat.ddc)
104-
'$scriptBasename:$lineB:20', // on '2'
114+
'$scriptBasename:$lineB:15', // on 'C'
115+
'$scriptBasename:$lineA:10', // on 'v' of 'value'
116+
'$scriptBasename:$lineA:16', // on ';'
117+
'$scriptBasename:$lineB:20', // on '2'
105118
'$scriptBasename:$lineF:3', // on 'c'
106119
'$scriptBasename:$lineC:25', // on 'C'
107120
'$scriptBasename:$lineA:10', // on 'v' of 'value'
@@ -119,11 +132,20 @@ void runTests({
119132
await testInspector.runStepIntoThroughProgramRecordingStops(
120133
isolateId,
121134
stops,
122-
provider.ddcModuleFormat == ModuleFormat.ddc ? 13 : 12,
135+
expected.length,
123136
);
124137

125138
expect(stops, expected);
139+
140+
await service.resume(isolateId);
126141
});
142+
final isolate = await service.getIsolate(isolateId);
143+
await service.evaluate(
144+
isolateId,
145+
isolate.rootLib!.id!,
146+
'testDotShorthands()',
147+
);
148+
await bp;
127149
});
128150
});
129151
}

fixtures/_experiment/web/main.dart

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
import 'dart:async';
88
import 'dart:core';
9-
// TODO: https://github.com/dart-lang/webdev/issues/2508
10-
// ignore: deprecated_member_use
11-
import 'dart:html';
9+
import 'dart:js_interop';
10+
11+
@JS('document.body.append')
12+
external void append(String text);
1213

1314
void main() {
1415
// for evaluation
@@ -26,11 +27,9 @@ void main() {
2627
testPattern2();
2728
print('Classes');
2829
testClass();
29-
print('Dot shorthands');
30-
testDotShorthands();
3130
});
3231

33-
document.body!.appendText('Program is running!');
32+
append('Program is running!');
3433
}
3534

3635
void printSimpleLocalRecord() {
@@ -93,10 +92,7 @@ class GreeterClass {
9392
final String greeteeName;
9493
final bool useFrench;
9594

96-
GreeterClass({
97-
this.greeteeName = 'Snoopy',
98-
this.useFrench = false,
99-
});
95+
GreeterClass({this.greeteeName = 'Snoopy', this.useFrench = false});
10096

10197
void sayHello() {
10298
useFrench ? greetInFrench() : greetInEnglish();
@@ -110,24 +106,3 @@ class GreeterClass {
110106
print('Bonjour $greeteeName');
111107
}
112108
}
113-
114-
class C {
115-
int value;
116-
C(this.value); // lineA
117-
118-
static C two = C(2); // lineB
119-
static C get three => C(3); // lineC
120-
static C four() => C(4); // lineD
121-
}
122-
123-
void testDotShorthands() {
124-
C c = C(1);
125-
print('breakpoint'); // Breakpoint: testDotShorthands
126-
// ignore: experiment_not_enabled
127-
c = .two; // lineE
128-
// ignore: experiment_not_enabled
129-
c = .three; // lineF
130-
// ignore: experiment_not_enabled
131-
c = .four(); // lineG
132-
print(c.value); // lineH
133-
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: _test_dot_shorthands
2+
version: 1.0.0
3+
description: >-
4+
A fake package used for testing dot shorthands.
5+
publish_to: none
6+
7+
environment:
8+
sdk: ^3.9.0
9+
10+
dev_dependencies:
11+
build_runner: ^2.5.0
12+
build_web_compilers: ^4.0.4
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<html>
2+
3+
<head>
4+
<script defer src="main.dart.js"></script>
5+
</head>
6+
7+
</html>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 3.9
6+
7+
class C {
8+
int value;
9+
C(this.value); // lineA
10+
11+
static C two = C(2); // lineB
12+
static C get three => C(3); // lineC
13+
static C four() => C(4); // lineD
14+
}
15+
16+
void testDotShorthands() {
17+
C c = C(1);
18+
print('breakpoint'); // Breakpoint: testDotShorthands
19+
// ignore: experiment_not_enabled
20+
c = .two; // lineE
21+
// ignore: experiment_not_enabled
22+
c = .three; // lineF
23+
// ignore: experiment_not_enabled
24+
c = .four(); // lineG
25+
print(c.value); // lineH
26+
}
27+
28+
void main() {}

0 commit comments

Comments
 (0)