[ddc] Run tests on canary and stable bots with matching settings

Closes: https://github.com/dart-lang/sdk/issues/53077
Towards: https://github.com/dart-lang/sdk/issues/43986
Change-Id: I60df13b8ff29a0865a45b3a48a97af0ce94460b7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317448
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Anna Gringauze <annagrin@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 48a7595..b8b9f7e 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -4546,12 +4546,27 @@
       jsCondition = runtimeCall('test(#)', [jsCondition]);
     }
 
-    var encodedSource =
-        node.enclosingComponent!.uriToSource[node.location!.file]!.source;
-    var source = utf8.decode(encodedSource, allowMalformed: true);
-    var conditionSource =
-        source.substring(node.conditionStartOffset, node.conditionEndOffset);
-    var location = _toSourceLocation(node.conditionStartOffset)!;
+    SourceLocation? location;
+    late String conditionSource;
+    if (node.location != null) {
+      var encodedSource =
+          node.enclosingComponent!.uriToSource[node.location!.file]!.source;
+      var source = utf8.decode(encodedSource, allowMalformed: true);
+
+      conditionSource =
+          source.substring(node.conditionStartOffset, node.conditionEndOffset);
+      location = _toSourceLocation(node.conditionStartOffset)!;
+    } else {
+      // Location is null in expression compilation when modules
+      // are loaded from kernel using expression compiler worker.
+      // Show the error only in that case, with the condition AST
+      // instead of the source.
+      //
+      // TODO(annagrin): Can we add some information to the kernel,
+      // or add better printing for the condition?
+      // Issue: https://github.com/dart-lang/sdk/issues/43986
+      conditionSource = node.condition.toString();
+    }
     return js.statement(' if (!#) #;', [
       jsCondition,
       runtimeCall('assertFailed(#, #, #, #, #)', [
@@ -4559,10 +4574,13 @@
           js_ast.LiteralNull()
         else
           _visitExpression(node.message!),
-        _cacheUri(location.sourceUrl.toString()),
+        if (location == null)
+          _cacheUri('<unknown source>')
+        else
+          _cacheUri(location.sourceUrl.toString()),
         // Lines and columns are typically printed with 1 based indexing.
-        js.number(location.line + 1),
-        js.number(location.column + 1),
+        js.number(location == null ? -1 : location.line + 1),
+        js.number(location == null ? -1 : location.column + 1),
         js.escapedString(conditionSource),
       ])
     ]);
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 30b44a3..6230ae2 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -84,6 +84,7 @@
   final CompilerOptions _compilerOptions;
   final ModuleFormat _moduleFormat;
   final bool _canaryFeatures;
+  final bool _enableAsserts;
   final Component _sdkComponent;
 
   void Function()? onDone;
@@ -93,17 +94,13 @@
     this._compilerOptions,
     this._moduleFormat,
     this._canaryFeatures,
+    this._enableAsserts,
     this._sdkComponent,
     this.requestStream,
     this.sendResponse,
     this.onDone,
   );
 
-  // Disable asserts due to failures to load source and locations on kernel
-  // loaded from dill files in DDC.
-  // https://github.com/dart-lang/sdk/issues/43986
-  static const bool _enableAsserts = false;
-
   /// Create expression compiler worker from [args] and start it.
   ///
   /// If [sendPort] is provided, creates a `receivePort` and sends it to
@@ -197,6 +194,7 @@
       soundNullSafety: parsedArgs['sound-null-safety'] as bool,
       moduleFormat: moduleFormat,
       canaryFeatures: parsedArgs['canary'] as bool,
+      enableAsserts: parsedArgs['enable-asserts'] as bool,
       verbose: parsedArgs['verbose'] as bool,
       requestStream: requestStream,
       sendResponse: sendResponse,
@@ -223,6 +221,7 @@
     bool soundNullSafety = false,
     ModuleFormat moduleFormat = ModuleFormat.amd,
     bool canaryFeatures = false,
+    bool enableAsserts = true,
     bool verbose = false,
     Stream<Map<String, dynamic>>? requestStream, // Defaults to read from stdin
     void Function(Map<String, dynamic>)?
@@ -242,7 +241,7 @@
       ..omitPlatform = true
       ..environmentDefines = addGeneratedVariables({
         if (environmentDefines != null) ...environmentDefines,
-      }, enableAsserts: _enableAsserts)
+      }, enableAsserts: enableAsserts)
       ..explicitExperimentalFlags = explicitExperimentalFlags
       ..onDiagnostic = _onDiagnosticHandler(errors, warnings, infos)
       ..nnbdMode = soundNullSafety ? NnbdMode.Strong : NnbdMode.Weak
@@ -267,6 +266,7 @@
         compilerOptions,
         moduleFormat,
         canaryFeatures,
+        enableAsserts,
         sdkComponent,
         requestStream,
         sendResponse,
@@ -451,8 +451,8 @@
         summarizeApi: false,
         moduleName: moduleName,
         soundNullSafety: _compilerOptions.nnbdMode == NnbdMode.Strong,
-        enableAsserts: _enableAsserts,
         canaryFeatures: _canaryFeatures,
+        enableAsserts: _enableAsserts,
       ),
       _moduleCache.componentForLibrary,
       _moduleCache.moduleNameForComponent,
@@ -790,6 +790,13 @@
   ..addFlag('track-widget-creation', defaultsTo: false)
   ..addFlag('sound-null-safety', negatable: true, defaultsTo: true)
   ..addFlag('canary', negatable: true, defaultsTo: false)
+  // Disable asserts in compiled code by default, which is different
+  // from the default value of the setting in DDC.
+  //
+  // TODO(annagrin) Change the default to `true` after the user code
+  // is tested with enabled asserts.
+  // Issue: https://github.com/dart-lang/sdk/issues/43986
+  ..addFlag('enable-asserts', negatable: true, defaultsTo: false)
   ..addFlag('verbose', defaultsTo: false);
 
 Uri? _argToUri(String? uriArg) =>
diff --git a/pkg/dev_compiler/test/expression_compiler/assertions_enabled_test.dart b/pkg/dev_compiler/test/expression_compiler/assertions_enabled_test.dart
index 931b7e9..bb52a6c 100644
--- a/pkg/dev_compiler/test/expression_compiler/assertions_enabled_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/assertions_enabled_test.dart
@@ -5,11 +5,12 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
-  group('dart.web.assertions_enabled', () {
+  group('Assertions |', () {
     const source = r'''
       void main() {
         var b = const bool.fromEnvironment('dart.web.assertions_enabled');
@@ -17,6 +18,10 @@
         // Breakpoint: bp
         print('hello world');
       }
+      int myAssert() {
+        assert(false);
+        return 0;
+      }
     ''';
 
     tearDown(() async {
@@ -27,19 +32,52 @@
       await driver.finish();
     });
 
-    test('is automatically set', () async {
-      var setup = SetupCompilerOptions(enableAsserts: true);
+    test('dart.web.assertions_enabled is set when asserts are enabled',
+        () async {
+      var setup = SetupCompilerOptions(args: args);
       await driver.initSource(setup, source);
-      // TODO(43986): Update when assertions are enabled.
+
       await driver.check(
-          breakpointId: 'bp', expression: 'b', expectedResult: 'false');
+          breakpointId: 'bp',
+          expression: 'b',
+          expectedResult: '${setup.enableAsserts}');
     });
 
-    test('is automatically unset', () async {
-      var setup = SetupCompilerOptions(enableAsserts: false);
+    test('assert errors in the source code when asserts are enabled', () async {
+      var setup = SetupCompilerOptions(args: args);
       await driver.initSource(setup, source);
+
       await driver.check(
-          breakpointId: 'bp', expression: 'b', expectedResult: 'false');
+        breakpointId: 'bp',
+        expression: 'myAssert()',
+        expectedResult: setup.enableAsserts
+            ? allOf(
+                contains('Error: Assertion failed:'),
+                contains('test.dart:8:16'),
+                contains('false'),
+                contains('is not true'),
+              )
+            : '0',
+      );
+    });
+
+    test('assert errors in evaluated expression when asserts are enabled',
+        () async {
+      var setup = SetupCompilerOptions(args: args);
+      await driver.initSource(setup, source);
+
+      await driver.check(
+        breakpointId: 'bp',
+        expression: '() { assert(false); return 0; } ()',
+        expectedResult: setup.enableAsserts
+            ? allOf(
+                contains('Error: Assertion failed:'),
+                contains('<unknown source>:-1:-1'),
+                contains('BoolLiteral(false)'),
+                contains('is not true'),
+              )
+            : '0',
+      );
     });
   });
 }
diff --git a/pkg/dev_compiler/test/expression_compiler/canary_features_enabled_test.dart b/pkg/dev_compiler/test/expression_compiler/canary_features_enabled_test.dart
new file mode 100644
index 0000000..284a079
--- /dev/null
+++ b/pkg/dev_compiler/test/expression_compiler/canary_features_enabled_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2023, 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';
+
+import 'package:test/test.dart';
+
+import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
+
+void main(List<String> args) async {
+  var driver = await TestDriver.init();
+
+  group('canary', () {
+    const source = r'''
+      void main() {
+        print('hello world');
+      }
+    ''';
+
+    tearDown(() async {
+      await driver.cleanupTest();
+    });
+
+    tearDownAll(() async {
+      await driver.finish();
+    });
+
+    test('is automatically set to the configuration value', () async {
+      var setup = SetupCompilerOptions(args: args);
+      await driver.initSource(setup, source);
+
+      expect(
+          File(driver.dartSdkPath).readAsStringSync(),
+          setup.canaryFeatures
+              ? contains('canary')
+              : isNot(contains('canary')));
+    });
+  });
+}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_1_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_1_test.dart
index 9d3c974..789bdda 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_1_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_1_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Sound null safety) (Agnostic code shard 1)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: true,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: true,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runAgnosticSharedTestsShard1(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_2_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_2_test.dart
index 7eaa138..828c278 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_2_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_sound_shard_2_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Sound null safety) (Agnostic code shard 2)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: true,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: true,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runAgnosticSharedTestsShard2(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_1_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_1_test.dart
index aa55e3c..1b09405 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_1_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_1_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Unsound null safety) (Agnostic code shard 1)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: false,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runAgnosticSharedTestsShard1(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_2_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_2_test.dart
index 4eff2ea..922ff85 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_2_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_agnostic_unsound_shard_2_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Unsound null safety) (Agnostic code shard 2)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: false,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runAgnosticSharedTestsShard2(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_1_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_1_test.dart
index 8c4523d..ac70c0f 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_1_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_1_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Legacy code shard 1)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: true,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: false,
+        legacyCode: true,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runAgnosticSharedTestsShard1(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_2_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_2_test.dart
index 478d824..914232d 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_2_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_legacy_shard_2_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Legacy code shard 2)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: true,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: false,
+        legacyCode: true,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runAgnosticSharedTestsShard2(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_sound_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_sound_test.dart
index 7daf32c..abbbf9f 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_sound_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_sound_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   // Set to `true` for debug output.
   final debug = false;
   var driver = await TestDriver.init();
@@ -21,9 +22,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: true,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: true,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       setup.options.verbose = debug;
       runNullSafeSharedTests(setup, driver);
     });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_unsound_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_unsound_test.dart
index 25a4fb0..213a800 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_unsound_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_amd_unsound_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Unsound null safety)', () {
@@ -19,9 +20,11 @@
 
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.amd);
+        soundNullSafety: false,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.amd,
+        args: args,
+      );
       runNullSafeSharedTests(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_2_17_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_2_17_test.dart
index e63cff3..93835f1 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_2_17_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_2_17_test.dart
@@ -7,8 +7,9 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('Dart 2.17 language features', () {
@@ -19,17 +20,21 @@
     group('(Unsound null safety)', () {
       group('(AMD module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: false,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.amd);
+          soundNullSafety: false,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.amd,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
 
       group('(DDC module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: false,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.ddc);
+          soundNullSafety: false,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.ddc,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
     });
@@ -37,17 +42,21 @@
     group('(Sound null safety)', () {
       group('(AMD module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: true,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.amd);
+          soundNullSafety: true,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.amd,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
 
       group('(DDC module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: true,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.ddc);
+          soundNullSafety: true,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.ddc,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
     });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_0_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_0_test.dart
index 25f01482..e6128b0 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_0_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_0_test.dart
@@ -7,8 +7,9 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('Dart 3.0 language features', () {
@@ -19,17 +20,21 @@
     group('(Unsound null safety)', () {
       group('(AMD module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: false,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.amd);
+          soundNullSafety: false,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.amd,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
 
       group('(DDC module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: false,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.ddc);
+          soundNullSafety: false,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.ddc,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
     });
@@ -37,17 +42,21 @@
     group('(Sound null safety)', () {
       group('(AMD module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: true,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.amd);
+          soundNullSafety: true,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.amd,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
 
       group('(DDC module system)', () {
         var setup = SetupCompilerOptions(
-            soundNullSafety: true,
-            legacyCode: false,
-            moduleFormat: ModuleFormat.ddc);
+          soundNullSafety: true,
+          legacyCode: false,
+          moduleFormat: ModuleFormat.ddc,
+          args: args,
+        );
         runSharedTests(setup, driver);
       });
     });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_1_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_1_test.dart
index c0f2fa9..89acab8 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_1_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_1_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Sound null safety) (Agnostic code shard 1)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: true,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: true,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runAgnosticSharedTestsShard1(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_2_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_2_test.dart
index cd35dea..9ebeff7 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_2_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_sound_shard_2_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Sound null safety) (Agnostic code shard 2)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: true,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: true,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runAgnosticSharedTestsShard2(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_1_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_1_test.dart
index 230a470..1be6dc5 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_1_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_1_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Unsound null safety) (Agnostic code shard 1)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: false,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runAgnosticSharedTestsShard1(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_2_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_2_test.dart
index ab5d610..d852f0f 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_2_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_agnostic_unsound_shard_2_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Unsound null safety) (Agnostic code shard 2)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: false,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runAgnosticSharedTestsShard2(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_1_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_1_test.dart
index de7e2a5..0d3fcd9 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_1_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_1_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Legacy code shard 1)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: true,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: false,
+        legacyCode: true,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runAgnosticSharedTestsShard1(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_2_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_2_test.dart
index b511675..b11baed 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_2_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_legacy_shard_2_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Legacy code shard 2)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: true,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: false,
+        legacyCode: true,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runAgnosticSharedTestsShard2(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_sound_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_sound_test.dart
index bcd6a64..8f4542d 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_sound_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_sound_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Sound null safety)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: true,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: true,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runNullSafeSharedTests(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_unsound_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_unsound_test.dart
index 4b61806..408c06b 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_unsound_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_ddc_unsound_test.dart
@@ -8,8 +8,9 @@
 
 import 'expression_compiler_e2e_shared.dart';
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   var driver = await TestDriver.init();
 
   group('(Unsound null safety)', () {
@@ -19,9 +20,11 @@
 
     group('(DDC module system)', () {
       var setup = SetupCompilerOptions(
-          soundNullSafety: false,
-          legacyCode: false,
-          moduleFormat: ModuleFormat.ddc);
+        soundNullSafety: false,
+        legacyCode: false,
+        moduleFormat: ModuleFormat.ddc,
+        args: args,
+      );
       runNullSafeSharedTests(setup, driver);
     });
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
index b5aac3f..83bdbff 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
@@ -5,6 +5,7 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
 const simpleClassSource = '''
 extension NumberParsing on String {
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
index 7eab6aba..47281d8 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -17,18 +17,17 @@
 import 'package:dev_compiler/src/kernel/expression_compiler.dart'
     show ExpressionCompiler;
 import 'package:dev_compiler/src/kernel/module_metadata.dart';
-import 'package:dev_compiler/src/kernel/target.dart' show DevCompilerTarget;
 import 'package:front_end/src/api_unstable/ddc.dart' as fe;
-import 'package:front_end/src/compute_platform_binaries_location.dart' as fe;
 import 'package:front_end/src/fasta/incremental_serializer.dart' as fe;
 import 'package:kernel/ast.dart' show Component, Library;
-import 'package:kernel/target/targets.dart';
 import 'package:path/path.dart' as p;
 import 'package:source_maps/source_maps.dart' as source_maps;
 import 'package:test/test.dart';
 import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
     as wip;
 
+import 'setup_compiler_options.dart';
+
 class DevelopmentIncrementalCompiler extends fe.IncrementalCompiler {
   Uri entryPoint;
 
@@ -54,65 +53,6 @@
             incrementalSerializer);
 }
 
-class SetupCompilerOptions {
-  static final sdkRoot = fe.computePlatformBinariesLocation();
-  static final buildRoot =
-      fe.computePlatformBinariesLocation(forceBuildDir: true);
-  // Unsound .dill files are not longer in the released SDK so this file must be
-  // read from the build output directory.
-  static final sdkUnsoundSummaryPath =
-      buildRoot.resolve('ddc_outline_unsound.dill').toFilePath();
-  // Use the outline copied to the released SDK.
-  static final sdkSoundSummaryPath =
-      sdkRoot.resolve('ddc_outline.dill').toFilePath();
-  static final librariesSpecificationUri =
-      p.join(p.dirname(p.dirname(getSdkPath())), 'libraries.json');
-
-  final bool legacyCode;
-  final List<String> errors = [];
-  final List<String> diagnosticMessages = [];
-  final ModuleFormat moduleFormat;
-  final fe.CompilerOptions options;
-  final bool soundNullSafety;
-  final bool canaryFeatures;
-
-  static fe.CompilerOptions _getOptions(
-      {required bool enableAsserts, required bool soundNullSafety}) {
-    var options = fe.CompilerOptions()
-      ..verbose = false // set to true for debugging
-      ..sdkRoot = sdkRoot
-      ..target =
-          DevCompilerTarget(TargetFlags(soundNullSafety: soundNullSafety))
-      ..librariesSpecificationUri = p.toUri('sdk/lib/libraries.json')
-      ..omitPlatform = true
-      ..sdkSummary =
-          p.toUri(soundNullSafety ? sdkSoundSummaryPath : sdkUnsoundSummaryPath)
-      ..environmentDefines = addGeneratedVariables({},
-          // Disable asserts due to failures to load source and
-          // locations on kernel loaded from dill files in DDC.
-          // https://github.com/dart-lang/sdk/issues/43986
-          enableAsserts: false)
-      ..nnbdMode = soundNullSafety ? fe.NnbdMode.Strong : fe.NnbdMode.Weak;
-    return options;
-  }
-
-  SetupCompilerOptions({
-    bool enableAsserts = true,
-    this.soundNullSafety = true,
-    this.legacyCode = false,
-    this.moduleFormat = ModuleFormat.amd,
-    this.canaryFeatures = false,
-  }) : options = _getOptions(
-            soundNullSafety: soundNullSafety, enableAsserts: enableAsserts) {
-    options.onDiagnostic = (fe.DiagnosticMessage m) {
-      diagnosticMessages.addAll(m.plainTextFormatted);
-      if (m.severity == fe.Severity.error) {
-        errors.addAll(m.plainTextFormatted);
-      }
-    };
-  }
-}
-
 class TestCompilationResult {
   final String? result;
   final bool isSuccess;
@@ -157,6 +97,7 @@
       soundNullSafety: setup.soundNullSafety,
       emitDebugMetadata: true,
       canaryFeatures: setup.canaryFeatures,
+      enableAsserts: setup.enableAsserts,
     );
     var coreTypes = compilerResult.coreTypes;
 
@@ -253,6 +194,7 @@
   late SetupCompilerOptions setup;
   late String source;
   late Directory testDir;
+  late String dartSdkPath;
 
   TestDriver._(this.chrome, this.chromeDir, this.connection, this.debugger);
 
@@ -361,13 +303,13 @@
 
     switch (setup.moduleFormat) {
       case ModuleFormat.ddc:
-        var dartSdkPath = escaped(SetupCompilerOptions.buildRoot
+        dartSdkPath = escaped(SetupCompilerOptions.buildRoot
             .resolve(p.join(
                 'gen',
                 'utils',
                 'ddc',
-                // TODO(nshahan): Add canary option here.
-                'stable${setup.soundNullSafety ? '' : '_unsound'}',
+                '${setup.canaryFeatures ? 'canary' : 'stable'}'
+                    '${setup.soundNullSafety ? '' : '_unsound'}',
                 'sdk',
                 'legacy',
                 'dart_sdk.js'))
@@ -403,19 +345,21 @@
 ''');
         break;
       case ModuleFormat.amd:
-        var dartSdkPath = escaped(SetupCompilerOptions.buildRoot
+        var dartSdkPathNoExtension = escaped(SetupCompilerOptions.buildRoot
             .resolve(p.join(
                 'gen',
                 'utils',
                 'ddc',
-                // TODO(nshahan): Add canary option here.
-                'stable${setup.soundNullSafety ? '' : '_unsound'}',
+                '${setup.canaryFeatures ? 'canary' : 'stable'}'
+                    '${setup.soundNullSafety ? '' : '_unsound'}',
                 'sdk',
                 'amd',
                 'dart_sdk'))
             .toFilePath());
-        if (!File('$dartSdkPath.js').existsSync()) {
-          throw Exception('Unable to find Dart SDK at $dartSdkPath.js');
+        dartSdkPath = '$dartSdkPathNoExtension.js';
+
+        if (!File(dartSdkPath).existsSync()) {
+          throw Exception('Unable to find Dart SDK at $dartSdkPath');
         }
         var requirePath = escaped(SetupCompilerOptions.buildRoot
             .resolve(
@@ -427,7 +371,7 @@
 <script>
   require.config({
     paths: {
-        'dart_sdk': '$dartSdkPath',
+        'dart_sdk': '$dartSdkPathNoExtension',
         '$moduleName': '$outputPath'
     },
     waitSeconds: 15
@@ -675,8 +619,8 @@
   Future<void> check(
       {required String breakpointId,
       required String expression,
-      String? expectedError,
-      String? expectedResult}) async {
+      dynamic expectedError,
+      dynamic expectedResult}) async {
     assert(expectedError == null || expectedResult == null,
         'Cannot expect both an error and result.');
 
@@ -697,6 +641,12 @@
         );
         expect(error, _matches(expectedError!));
       } else {
+        expect(
+          expectedResult,
+          isNotNull,
+          reason:
+              'Unexpected expression evaluation success:\n${evalResult.json}',
+        );
         var actual = await stringifyRemoteObject(evalResult);
         expect(actual, _matches(expectedResult!));
       }
@@ -827,8 +777,11 @@
   }
 
   /// Used for matching error text emitted during expression evaluation.
-  Matcher _matches(String text) {
-    var unindented = RegExp.escape(text).replaceAll(RegExp('[ ]+'), '[ ]*');
+  Matcher _matches(dynamic matcher) {
+    if (matcher is Matcher) return matcher;
+    if (matcher is! String) throw StateError('Unexpected matcher: $matcher');
+
+    var unindented = RegExp.escape(matcher).replaceAll(RegExp('[ ]+'), '[ ]*');
     return matches(RegExp(unindented, multiLine: true));
   }
 
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_canary_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_canary_test.dart
deleted file mode 100644
index fd3d284..0000000
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_canary_test.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2023, 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:dev_compiler/dev_compiler.dart';
-import 'package:test/test.dart';
-
-import 'expression_compiler_worker_shared.dart';
-
-void main() async {
-  // Set to true to enable debug output
-  var debug = false;
-
-  group('canary -', () {
-    group('amd module format -', () {
-      for (var soundNullSafety in [true, false]) {
-        group('${soundNullSafety ? "sound" : "unsound"} null safety -', () {
-          runTests(
-            moduleFormat: ModuleFormat.amd,
-            soundNullSafety: soundNullSafety,
-            canaryFeatures: true,
-            verbose: debug,
-          );
-        });
-      }
-    });
-  });
-}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_test.dart
index 50ff893..55d57a0 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_amd_test.dart
@@ -6,20 +6,21 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_worker_shared.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   // Set to true to enable debug output
   var debug = false;
 
   group('amd module format -', () {
     for (var soundNullSafety in [true, false]) {
       group('${soundNullSafety ? "sound" : "unsound"} null safety -', () {
-        runTests(
+        var setup = SetupCompilerOptions(
           moduleFormat: ModuleFormat.amd,
           soundNullSafety: soundNullSafety,
-          canaryFeatures: false,
-          verbose: debug,
+          args: args,
         );
+        runTests(setup, verbose: debug);
       });
     }
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_canary_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_canary_test.dart
deleted file mode 100644
index ea712b6..0000000
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_canary_test.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2023, 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:dev_compiler/dev_compiler.dart';
-import 'package:test/test.dart';
-
-import 'expression_compiler_worker_shared.dart';
-
-void main() async {
-  // Set to true to enable debug output
-  var debug = false;
-
-  group('canary -', () {
-    group('ddc module format -', () {
-      for (var soundNullSafety in [true, false]) {
-        group('${soundNullSafety ? "sound" : "unsound"} null safety -', () {
-          runTests(
-            moduleFormat: ModuleFormat.ddc,
-            soundNullSafety: soundNullSafety,
-            canaryFeatures: true,
-            verbose: debug,
-          );
-        });
-      }
-    });
-  });
-}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_test.dart
index b122958..51d1865 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_ddc_test.dart
@@ -6,20 +6,21 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_worker_shared.dart';
+import 'setup_compiler_options.dart';
 
-void main() async {
+void main(List<String> args) async {
   // Set to true to enable debug output
   var debug = false;
 
   group('ddc module format -', () {
     for (var soundNullSafety in [true, false]) {
       group('${soundNullSafety ? "sound" : "unsound"} null safety -', () {
-        runTests(
+        var setup = SetupCompilerOptions(
           moduleFormat: ModuleFormat.ddc,
           soundNullSafety: soundNullSafety,
-          canaryFeatures: false,
-          verbose: debug,
+          args: args,
         );
+        runTests(setup, verbose: debug);
       });
     }
   });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart
index 4c38165..1bfce27 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart
@@ -22,22 +22,19 @@
 import 'package:shelf/shelf_io.dart';
 import 'package:test/test.dart';
 
-void runTests({
-  required ModuleFormat moduleFormat,
-  required bool soundNullSafety,
-  required bool canaryFeatures,
-  bool verbose = false,
-}) {
+import 'setup_compiler_options.dart';
+
+void runTests(SetupCompilerOptions setup, {bool verbose = false}) {
   group('expression compiler worker on startup', () {
     late Directory tempDir;
     late ReceivePort receivePort;
 
-    setUp(() async {
+    setUp(() {
       tempDir = Directory.systemTemp.createTempSync('foo bar');
       receivePort = ReceivePort();
     });
 
-    tearDown(() async {
+    tearDown(() {
       receivePort.close();
       tempDir.deleteSync(recursive: true);
     });
@@ -63,9 +60,12 @@
             '--dart-sdk-summary',
             badPath,
             '--module-format',
-            moduleFormat.name,
-            soundNullSafety ? '--sound-null-safety' : '--no-sound-null-safety',
-            if (canaryFeatures) '--canary',
+            setup.moduleFormat.name,
+            setup.soundNullSafety
+                ? '--sound-null-safety'
+                : '--no-sound-null-safety',
+            if (setup.enableAsserts) '--enable-asserts',
+            if (setup.canaryFeatures) '--canary',
             if (verbose) '--verbose',
           ],
           sendPort: receivePort.sendPort,
@@ -78,27 +78,30 @@
 
   group('reading assets using standard file system - ', () {
     runExpressionCompilationTests(StandardFileSystemTestDriver(
-      soundNullSafety,
-      moduleFormat,
-      canaryFeatures,
+      setup.soundNullSafety,
+      setup.moduleFormat,
+      setup.canaryFeatures,
+      setup.enableAsserts,
       verbose,
     ));
   });
 
   group('reading assets using multiroot file system - ', () {
     runExpressionCompilationTests(MultiRootFileSystemTestDriver(
-      soundNullSafety,
-      moduleFormat,
-      canaryFeatures,
+      setup.soundNullSafety,
+      setup.moduleFormat,
+      setup.canaryFeatures,
+      setup.enableAsserts,
       verbose,
     ));
   });
 
   group('reading assets using asset file system -', () {
     runExpressionCompilationTests(AssetFileSystemTestDriver(
-      soundNullSafety,
-      moduleFormat,
-      canaryFeatures,
+      setup.soundNullSafety,
+      setup.moduleFormat,
+      setup.canaryFeatures,
+      setup.enableAsserts,
       verbose,
     ));
   });
@@ -122,7 +125,7 @@
       await driver.tearDown();
     });
 
-    test('can compile expressions in sdk', () async {
+    test('can compile expressions in sdk', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -155,7 +158,7 @@
           ]));
     }, skip: 'Evaluating expressions in SDK is not supported yet');
 
-    test('can compile expressions in a library', () async {
+    test('can compile expressions in a library', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -189,7 +192,7 @@
     });
 
     test('compile expressions include "dart.library..." environment defines.',
-        () async {
+        () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -222,7 +225,7 @@
           ]));
     });
 
-    test('can compile expressions in main', () async {
+    test('can compile expressions in main', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -255,7 +258,7 @@
           ]));
     });
 
-    test('can compile expressions in main (extension method)', () async {
+    test('can compile expressions in main (extension method)', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -288,7 +291,7 @@
           ]));
     });
 
-    test('can compile transitive expressions in main', () async {
+    test('can compile transitive expressions in main', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -322,8 +325,7 @@
           ]));
     });
 
-    test('can compile expressions in non-strongly-connected components',
-        () async {
+    test('can compile expressions in non-strongly-connected components', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -356,7 +358,7 @@
           ]));
     });
 
-    test('can compile expressions in strongly connected components', () async {
+    test('can compile expressions in strongly connected components', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -389,7 +391,7 @@
           ]));
     });
 
-    test('can compile series of expressions in various libraries', () async {
+    test('can compile series of expressions in various libraries', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -514,7 +516,7 @@
           ]));
     });
 
-    test('can compile after dependency update', () async {
+    test('can compile after dependency update', () {
       driver.requestController.add({
         'command': 'UpdateDeps',
         'inputs': driver.inputs,
@@ -965,9 +967,9 @@
   final bool soundNullSafety;
   final ModuleFormat moduleFormat;
   final bool canaryFeatures;
+  final bool enableAsserts;
   final bool verbose;
 
-  late FileSystem fileSystem;
   late FileSystem assetFileSystem;
 
   late Directory tempDir;
@@ -979,8 +981,13 @@
   ExpressionCompilerWorker? worker;
   Future<void>? workerDone;
 
-  TestDriver(this.soundNullSafety, this.moduleFormat, this.canaryFeatures,
-      this.verbose);
+  TestDriver(
+    this.soundNullSafety,
+    this.moduleFormat,
+    this.canaryFeatures,
+    this.enableAsserts,
+    this.verbose,
+  );
 
   /// Initialize file systems, inputs, and start servers if needed.
   Future<void> start();
@@ -1022,6 +1029,7 @@
       soundNullSafety: soundNullSafety,
       moduleFormat: moduleFormat,
       canaryFeatures: canaryFeatures,
+      enableAsserts: enableAsserts,
       verbose: verbose,
     );
     workerDone = worker?.run();
@@ -1040,14 +1048,14 @@
     bool soundNullSafety,
     ModuleFormat moduleFormat,
     bool canaryFeatures,
+    bool enableAsserts,
     bool verbose,
-  ) : super(soundNullSafety, moduleFormat, canaryFeatures, verbose);
+  ) : super(soundNullSafety, moduleFormat, canaryFeatures, enableAsserts,
+            verbose);
 
   @override
   Future<void> start() async {
     inputs = config.inputPaths;
-    fileSystem = MultiRootFileSystem(
-        'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
     assetFileSystem = StandardFileSystem.instance;
   }
 }
@@ -1057,13 +1065,15 @@
     bool soundNullSafety,
     ModuleFormat moduleFormat,
     bool canaryFeatures,
+    bool enableAsserts,
     bool verbose,
-  ) : super(soundNullSafety, moduleFormat, canaryFeatures, verbose);
+  ) : super(soundNullSafety, moduleFormat, canaryFeatures, enableAsserts,
+            verbose);
 
   @override
   Future<void> start() async {
     inputs = config.inputUris;
-    fileSystem = MultiRootFileSystem(
+    var fileSystem = MultiRootFileSystem(
         'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
     assetFileSystem = fileSystem;
   }
@@ -1077,13 +1087,15 @@
     bool soundNullSafety,
     ModuleFormat moduleFormat,
     bool canaryFeatures,
+    bool enableAsserts,
     bool verbose,
-  ) : super(soundNullSafety, moduleFormat, canaryFeatures, verbose);
+  ) : super(soundNullSafety, moduleFormat, canaryFeatures, enableAsserts,
+            verbose);
 
   @override
   Future<void> start() async {
     inputs = config.inputRelativeUris;
-    fileSystem = MultiRootFileSystem(
+    var fileSystem = MultiRootFileSystem(
         'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
     port = await findUnusedPort();
     server = TestAssetServer(fileSystem);
@@ -1148,10 +1160,13 @@
   final TestProjectConfiguration config;
   final bool verbose;
   static final dart = Platform.resolvedExecutable;
+  static final sdkPath =
+      computePlatformBinariesLocation(forceBuildDir: true).toFilePath();
+
   static final dartdevc =
-      p.join(p.dirname(dart), 'snapshots', 'dartdevc.dart.snapshot');
-  static final kernelWorker =
-      p.join(p.dirname(dart), 'snapshots', 'kernel_worker.dart.snapshot');
+      p.join(sdkPath, 'dart-sdk', 'bin', 'snapshots', 'dartdevc.dart.snapshot');
+  static final kernelWorker = p.join(
+      sdkPath, 'dart-sdk', 'bin', 'snapshots', 'kernel_worker.dart.snapshot');
 
   DDCKernelGenerator(this.config, this.verbose);
 
diff --git a/pkg/dev_compiler/test/expression_compiler/runtime_debugger_api_test.dart b/pkg/dev_compiler/test/expression_compiler/runtime_debugger_api_test.dart
index 4d7fd34..9430e02 100644
--- a/pkg/dev_compiler/test/expression_compiler/runtime_debugger_api_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/runtime_debugger_api_test.dart
@@ -7,38 +7,33 @@
 import 'package:test/test.dart';
 
 import 'expression_compiler_e2e_suite.dart';
+import 'setup_compiler_options.dart';
 
 void main(List<String> args) async {
-  if (args.length > 1 || (args.length == 1 && args.first != '--canary')) {
-    throw Exception('Invalid arguments: $args, expected "--canary"');
-  }
-  var canaryFeatures = args.isNotEmpty;
   var driver = await TestDriver.init();
 
   tearDownAll(() async {
     await driver.finish();
   });
-
-  var canary = canaryFeatures ? '(Canary)' : '';
-  group('$canary (Sound null safety)', () {
+  group('(Sound null safety)', () {
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
         soundNullSafety: true,
         legacyCode: false,
         moduleFormat: ModuleFormat.amd,
-        canaryFeatures: canaryFeatures,
+        args: args,
       );
       runSharedTests(setup, driver);
     });
   });
 
-  group('$canary (Weak null safety)', () {
+  group('(Weak null safety)', () {
     group('(AMD module system)', () {
       var setup = SetupCompilerOptions(
         soundNullSafety: false,
         legacyCode: false,
         moduleFormat: ModuleFormat.amd,
-        canaryFeatures: canaryFeatures,
+        args: args,
       );
       runSharedTests(setup, driver);
     });
diff --git a/pkg/dev_compiler/test/expression_compiler/setup_compiler_options.dart b/pkg/dev_compiler/test/expression_compiler/setup_compiler_options.dart
new file mode 100644
index 0000000..4958cc9
--- /dev/null
+++ b/pkg/dev_compiler/test/expression_compiler/setup_compiler_options.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2023, 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:dev_compiler/src/compiler/module_builder.dart';
+import 'package:dev_compiler/src/kernel/command.dart';
+import 'package:dev_compiler/src/kernel/target.dart' show DevCompilerTarget;
+import 'package:front_end/src/api_unstable/ddc.dart' as fe;
+import 'package:front_end/src/compute_platform_binaries_location.dart' as fe;
+import 'package:kernel/target/targets.dart';
+import 'package:path/path.dart' as p;
+
+class SetupCompilerOptions {
+  static final sdkRoot = fe.computePlatformBinariesLocation();
+  static final buildRoot =
+      fe.computePlatformBinariesLocation(forceBuildDir: true);
+  static final sdkUnsoundSummaryPath =
+      buildRoot.resolve('ddc_outline_unsound.dill').toFilePath();
+  static final sdkSoundSummaryPath =
+      buildRoot.resolve('ddc_outline.dill').toFilePath();
+  static final librariesSpecificationUri =
+      buildRoot.resolve('lib/libraries.json').toFilePath();
+
+  final bool legacyCode;
+  final List<String> errors = [];
+  final List<String> diagnosticMessages = [];
+  final ModuleFormat moduleFormat;
+  final fe.CompilerOptions options;
+  final bool soundNullSafety;
+  final bool canaryFeatures;
+  final bool enableAsserts;
+
+  static fe.CompilerOptions _getOptions(
+      {required bool enableAsserts, required bool soundNullSafety}) {
+    var options = fe.CompilerOptions()
+      ..verbose = false // set to true for debugging
+      ..sdkRoot = sdkRoot
+      ..target =
+          DevCompilerTarget(TargetFlags(soundNullSafety: soundNullSafety))
+      ..librariesSpecificationUri = p.toUri('sdk/lib/libraries.json')
+      ..omitPlatform = true
+      ..sdkSummary =
+          p.toUri(soundNullSafety ? sdkSoundSummaryPath : sdkUnsoundSummaryPath)
+      ..environmentDefines =
+          addGeneratedVariables({}, enableAsserts: enableAsserts)
+      ..nnbdMode = soundNullSafety ? fe.NnbdMode.Strong : fe.NnbdMode.Weak;
+    return options;
+  }
+
+  SetupCompilerOptions._({
+    this.enableAsserts = true,
+    this.soundNullSafety = true,
+    this.legacyCode = false,
+    this.moduleFormat = ModuleFormat.amd,
+    this.canaryFeatures = false,
+  }) : options = _getOptions(
+            soundNullSafety: soundNullSafety, enableAsserts: enableAsserts) {
+    options.onDiagnostic = (fe.DiagnosticMessage m) {
+      diagnosticMessages.addAll(m.plainTextFormatted);
+      if (m.severity == fe.Severity.error ||
+          m.severity == fe.Severity.internalProblem) {
+        errors.addAll(m.plainTextFormatted);
+      }
+    };
+  }
+
+  /// Creates current compiler setup options.
+  ///
+  /// Reads options determined by the test configuration from the configuration
+  /// environment variable set by the test runner.
+  ///
+  /// To run tests locally using test.py, pass a vm option defining required
+  /// configuration, for example:
+  ///
+  /// `./tools/test.py -n web-dev-canary-unittest-asserts-mac`
+  ///
+  /// To run a single test locally, pass the --canary or --enable-asserts flags
+  /// to the command line to enable corresponding features, for example:
+  ///
+  /// `dart test/expression_compiler/assertions_enabled_test.dart --canary --enable-asserts`
+  factory SetupCompilerOptions({
+    bool soundNullSafety = true,
+    bool legacyCode = false,
+    ModuleFormat moduleFormat = ModuleFormat.amd,
+    List<String> args = const <String>[],
+  }) {
+    // Find if the test is run with arguments overriding the configuration
+    late bool enableAsserts;
+    late bool canaryFeatures;
+
+    // Read configuration settings from matrix.json
+    var configuration = String.fromEnvironment('test_runner.configuration');
+    if (configuration.isEmpty) {
+      // If not running from test runner, read options from the args
+      enableAsserts = args.contains('--enable-asserts');
+      canaryFeatures = args.contains('--canary');
+    } else {
+      // If running from the test runner, read options from the environment
+      // (set to configuration settings from matrix.json).
+      enableAsserts = configuration.contains('-asserts-');
+      canaryFeatures = configuration.contains('-canary-');
+    }
+    return SetupCompilerOptions._(
+      enableAsserts: enableAsserts,
+      soundNullSafety: soundNullSafety,
+      legacyCode: legacyCode,
+      moduleFormat: moduleFormat,
+      canaryFeatures: canaryFeatures,
+    );
+  }
+}