@@ -74,6 +74,7 @@ class SetupCompilerOptions {
74
74
final ModuleFormat moduleFormat;
75
75
final fe.CompilerOptions options;
76
76
final bool soundNullSafety;
77
+ final bool canaryFeatures;
77
78
78
79
static fe.CompilerOptions _getOptions (
79
80
{required bool enableAsserts, required bool soundNullSafety}) {
@@ -95,12 +96,13 @@ class SetupCompilerOptions {
95
96
return options;
96
97
}
97
98
98
- SetupCompilerOptions (
99
- {bool enableAsserts = true ,
100
- this .soundNullSafety = true ,
101
- this .legacyCode = false ,
102
- this .moduleFormat = ModuleFormat .amd})
103
- : options = _getOptions (
99
+ SetupCompilerOptions ({
100
+ bool enableAsserts = true ,
101
+ this .soundNullSafety = true ,
102
+ this .legacyCode = false ,
103
+ this .moduleFormat = ModuleFormat .amd,
104
+ this .canaryFeatures = false ,
105
+ }) : options = _getOptions (
104
106
soundNullSafety: soundNullSafety, enableAsserts: enableAsserts) {
105
107
options.onDiagnostic = (fe.DiagnosticMessage m) {
106
108
diagnosticMessages.addAll (m.plainTextFormatted);
@@ -154,7 +156,7 @@ class TestCompiler {
154
156
experiments: experiments,
155
157
soundNullSafety: setup.soundNullSafety,
156
158
emitDebugMetadata: true ,
157
- canaryFeatures: false ,
159
+ canaryFeatures: setup.canaryFeatures ,
158
160
);
159
161
var coreTypes = compilerResult.coreTypes;
160
162
@@ -599,6 +601,68 @@ class TestDriver {
599
601
});
600
602
}
601
603
604
+ /// Evaluates a dart [expression] on a breakpoint.
605
+ ///
606
+ /// [breakpointId] is the ID of the breakpoint from the source.
607
+ Future <String > evaluateDartExpression ({
608
+ required String breakpointId,
609
+ required String expression,
610
+ }) async {
611
+ var dartLine = _findBreakpointLine (breakpointId);
612
+ return await _onBreakpoint (breakpointId, onPause: (event) async {
613
+ var result = await _evaluateDartExpression (
614
+ event,
615
+ expression,
616
+ dartLine,
617
+ );
618
+ return await stringifyRemoteObject (result);
619
+ });
620
+ }
621
+
622
+ /// Evaluates a js [expression] on a breakpoint.
623
+ ///
624
+ /// [breakpointId] is the ID of the breakpoint from the source.
625
+ Future <String > evaluateJsExpression ({
626
+ required String breakpointId,
627
+ required String expression,
628
+ }) async {
629
+ return await _onBreakpoint (breakpointId, onPause: (event) async {
630
+ var result = await _evaluateJsExpression (
631
+ event,
632
+ expression,
633
+ );
634
+ return await stringifyRemoteObject (result);
635
+ });
636
+ }
637
+
638
+ /// Evaluates a JavaScript [expression] on a breakpoint and validates result.
639
+ ///
640
+ /// [breakpointId] is the ID of the breakpoint from the source.
641
+ /// [expression] is a dart runtime method call, i.e.
642
+ /// `dart.getLibraryMetadata(uri)` ;
643
+ /// [expectedResult] is the JSON for the returned remote object.
644
+ ///
645
+ /// Nested objects are not included in the result (they appear as `{}` ),
646
+ /// only primitive values, lists or maps, etc.
647
+ ///
648
+ /// TODO(annagrin): Add recursive check for nested objects.
649
+ Future <void > checkRuntime ({
650
+ required String breakpointId,
651
+ required String expression,
652
+ required dynamic expectedResult,
653
+ }) async {
654
+ return await _onBreakpoint (breakpointId, onPause: (event) async {
655
+ var actual = await _evaluateJsExpression (event, expression);
656
+ expect (actual.json, expectedResult);
657
+ });
658
+ }
659
+
660
+ /// Evaluates a dart [expression] on a breakpoint and validates result.
661
+ ///
662
+ /// [breakpointId] is the ID of the breakpoint from the source.
663
+ /// [expression] is a dart expression.
664
+ /// [expectedResult] is the JSON for the returned remote object.
665
+ /// [expectedError] is the error string if the error is expected.
602
666
Future <void > check (
603
667
{required String breakpointId,
604
668
required String expression,
@@ -609,45 +673,89 @@ class TestDriver {
609
673
610
674
var dartLine = _findBreakpointLine (breakpointId);
611
675
return await _onBreakpoint (breakpointId, onPause: (event) async {
612
- // Retrieve the call frame and its scope variables.
613
- var frame = event.getCallFrames ().first;
614
- var scope = await _collectScopeVariables (frame);
615
-
616
- // Perform an incremental compile.
617
- var result = await compiler.compileExpression (
618
- input: input,
619
- line: dartLine,
620
- column: 1 ,
621
- scope: scope,
622
- expression: expression);
623
-
624
- if (expectedError != null ) {
676
+ var evalResult = await _evaluateDartExpression (
677
+ event,
678
+ expression,
679
+ dartLine,
680
+ );
681
+
682
+ var error = evalResult.json['error' ];
683
+ if (error != null ) {
625
684
expect (
626
- result,
627
- const TypeMatcher <TestCompilationResult >().having (
628
- (_) => result.result, 'result' , _matches (expectedError)));
629
- setup.diagnosticMessages.clear ();
630
- setup.errors.clear ();
631
- return ;
685
+ expectedError,
686
+ isNotNull,
687
+ reason: 'Unexpected expression evaluation failure:\n $error ' ,
688
+ );
689
+ expect (error, _matches (expectedError! ));
690
+ } else {
691
+ var actual = await stringifyRemoteObject (evalResult);
692
+ expect (actual, _matches (expectedResult! ));
632
693
}
694
+ });
695
+ }
633
696
634
- if (! result.isSuccess) {
635
- throw Exception (
636
- 'Unexpected expression evaluation failure:\n ${result .result }' );
637
- }
697
+ Future <wip.RemoteObject > _evaluateJsExpression (
698
+ wip.DebuggerPausedEvent event,
699
+ String expression, {
700
+ bool returnByValue = true ,
701
+ }) async {
702
+ var frame = event.getCallFrames ().first;
703
+
704
+ var loadModule = setup.moduleFormat == ModuleFormat .amd
705
+ ? 'require'
706
+ : 'dart_library.import' ;
707
+
708
+ var jsExpression = '''
709
+ (function () {
710
+ try {
711
+ var sdk = $loadModule ('dart_sdk');
712
+ var dart = sdk.dart;
713
+ var interceptors = sdk._interceptors;
714
+ return $expression ;
715
+ } catch (error) {
716
+ return "Runtime API call failed: " + error.name +
717
+ ": " + error.message + ": " + error.stack;
718
+ }
719
+ })()
720
+ ''' ;
721
+
722
+ return await debugger.evaluateOnCallFrame (
723
+ frame.callFrameId,
724
+ jsExpression,
725
+ returnByValue: returnByValue,
726
+ );
727
+ }
638
728
639
- // Evaluate the compiled expression.
640
- var evalResult = await debugger.evaluateOnCallFrame (
641
- frame.callFrameId, result.result! ,
642
- returnByValue: false );
729
+ Future <wip.RemoteObject > _evaluateDartExpression (
730
+ wip.DebuggerPausedEvent event,
731
+ String expression,
732
+ int dartLine, {
733
+ bool returnByValue = false ,
734
+ }) async {
735
+ // Retrieve the call frame and its scope variables.
736
+ var frame = event.getCallFrames ().first;
737
+ var scope = await _collectScopeVariables (frame);
643
738
644
- var value = await stringifyRemoteObject (evalResult);
739
+ // Perform an incremental compile.
740
+ var result = await compiler.compileExpression (
741
+ input: input,
742
+ line: dartLine,
743
+ column: 1 ,
744
+ scope: scope,
745
+ expression: expression);
746
+
747
+ if (! result.isSuccess) {
748
+ setup.diagnosticMessages.clear ();
749
+ setup.errors.clear ();
750
+ return wip.RemoteObject ({'error' : result.result});
751
+ }
645
752
646
- expect (
647
- result,
648
- const TypeMatcher <TestCompilationResult >()
649
- .having ((_) => value, 'result' , _matches (expectedResult! )));
650
- });
753
+ // Evaluate the compiled expression.
754
+ return await debugger.evaluateOnCallFrame (
755
+ frame.callFrameId,
756
+ result.result! ,
757
+ returnByValue: returnByValue,
758
+ );
651
759
}
652
760
653
761
/// Generate simple string representation of a RemoteObject that closely
0 commit comments