Run ddc worker tests

Change-Id: I3555fe64bacd03a728d63a035457ca1e3398edb2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98699
Commit-Queue: Vijay Menon <vsm@google.com>
Reviewed-by: Nate Bosch <nbosch@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 596b6e6..e9f2a3a 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -96,7 +96,23 @@
   SharedCompilerOptions.addArguments(argParser);
 
   var declaredVariables = parseAndRemoveDeclaredVariables(args);
-  var argResults = argParser.parse(filterUnknownArguments(args, argParser));
+  ArgResults argResults;
+  try {
+    argResults = argParser.parse(filterUnknownArguments(args, argParser));
+  } on FormatException catch (error) {
+    print(error);
+    print(_usageMessage(argParser));
+    return CompilerResult(64);
+  }
+
+  var output = argResults['out'] as String;
+  if (output == null) {
+    print('Please specify the output file location. For example:\n'
+        '    -o PATH/TO/OUTPUT_FILE.js'
+        '');
+    print(_usageMessage(argParser));
+    return CompilerResult(64);
+  }
 
   if (argResults['help'] as bool || args.isEmpty) {
     print(_usageMessage(argParser));
@@ -230,7 +246,6 @@
 
   List<Uri> inputSummaries = compilerState.options.inputSummaries;
 
-  var output = argResults['out'] as String;
   // TODO(jmesserly): is there a cleaner way to do this?
   //
   // Ideally we'd manage our own batch compilation caching rather than rely on
diff --git a/pkg/dev_compiler/test/worker/worker_test.dart b/pkg/dev_compiler/test/worker/worker_test.dart
index dd4b5cc..07c9dc9 100644
--- a/pkg/dev_compiler/test/worker/worker_test.dart
+++ b/pkg/dev_compiler/test/worker/worker_test.dart
@@ -10,28 +10,41 @@
 // TODO(jakemac): Remove once this is a part of the testing library.
 import 'package:bazel_worker/src/async_message_grouper.dart';
 import 'package:bazel_worker/testing.dart';
-import 'package:path/path.dart' show join, joinAll;
+import 'package:path/path.dart' show dirname, join, joinAll;
 import 'package:test/test.dart';
 
-File file(String path) => File(joinAll(path.split('/'))).absolute;
+Directory tmp = Directory.systemTemp.createTempSync('ddc_worker_test');
+File file(String path) => File(join(tmp.path, joinAll(path.split('/'))));
 
-main() {
-  var dartdevc = join('bin', 'dartdevc.dart');
-  group('Hello World', () {
-    final argsFile = file('test/worker/hello_world.args');
-    final inputDartFile = file('test/worker/hello_world.dart');
-    final outputJsFile = file('test/worker/out/hello_world.js');
-    final dartSdkSummary = file('gen/sdk/ddc_sdk.sum');
-    final executableArgs = [dartdevc];
-    final compilerArgs = [
-      '--no-source-map',
-      '--no-summarize',
-      '--dart-sdk-summary',
-      dartSdkSummary.path,
-      '-o',
-      outputJsFile.path,
-      inputDartFile.path,
-    ];
+void main() {
+  runTests(false);
+  runTests(true);
+}
+
+void runTests(bool isKernel) {
+  String mode = isKernel ? 'DDK' : 'DDC';
+  List<String> baseArgs = isKernel ? ['-k'] : [];
+  String ext = isKernel ? 'dill' : 'sum';
+  final binDir = dirname(Platform.resolvedExecutable);
+  // Note, the bots use the dart binary in the top-level build directory.
+  // On windows, this is a .bat file.
+  final dartdevc = 'dartdevc${Platform.isWindows ? ".bat" : ""}';
+  final executable = binDir.endsWith('bin')
+      ? join(binDir, dartdevc)
+      : join(binDir, 'dart-sdk', 'bin', dartdevc);
+  final executableArgs = <String>[];
+  group('$mode: Hello World', () {
+    final argsFile = file('hello_world.args');
+    final inputDartFile = file('hello_world.dart');
+    final outputJsFile = file('out/hello_world.js');
+    final compilerArgs = baseArgs +
+        [
+          '--no-source-map',
+          '--no-summarize',
+          '-o',
+          outputJsFile.path,
+          inputDartFile.path,
+        ];
 
     setUp(() {
       inputDartFile.createSync();
@@ -48,7 +61,7 @@
 
     test('can compile in worker mode', () async {
       var args = executableArgs.toList()..add('--persistent_worker');
-      var process = await Process.start(Platform.executable, args);
+      var process = await Process.start(executable, args);
       var messageGrouper = AsyncMessageGrouper(process.stdout);
 
       var request = WorkRequest();
@@ -71,6 +84,17 @@
       expect(response.output, isEmpty);
       expect(outputJsFile.readAsStringSync(), contains('goodbye world'));
 
+      // Try to compile an error.
+      inputDartFile.writeAsStringSync('main() { int x = "hello"; }');
+      process.stdin.add(protoToDelimitedBuffer(request));
+
+      response = await _readResponse(messageGrouper);
+      expect(response.exitCode, 1, reason: response.output);
+      expect(
+          response.output,
+          contains(
+              'A value of type \'String\' can\'t be assigned to a variable of type \'int\'.'));
+
       process.kill();
 
       // TODO(jakemac): This shouldn't be necessary, but it is for the process
@@ -80,7 +104,7 @@
 
     test('can compile in basic mode', () {
       var args = executableArgs.toList()..addAll(compilerArgs);
-      var result = Process.runSync(Platform.executable, args);
+      var result = Process.runSync(executable, args);
 
       expect(result.exitCode, EXIT_CODE_OK);
       expect(result.stdout, isEmpty);
@@ -92,7 +116,7 @@
       var args = List<String>.from(executableArgs)
         ..add('--does-not-exist')
         ..addAll(compilerArgs);
-      var result = Process.runSync(Platform.executable, args);
+      var result = Process.runSync(executable, args);
 
       expect(result.exitCode, 64);
       expect(result.stdout,
@@ -106,7 +130,7 @@
         ..add('--does-not-exist')
         ..add('--ignore-unrecognized-flags')
         ..addAll(compilerArgs);
-      var result = Process.runSync(Platform.executable, args);
+      var result = Process.runSync(executable, args);
 
       expect(result.exitCode, EXIT_CODE_OK);
       expect(result.stdout, isEmpty);
@@ -118,7 +142,7 @@
       argsFile.createSync();
       argsFile.writeAsStringSync(compilerArgs.join('\n'));
       var args = executableArgs.toList()..add('@${argsFile.path}');
-      var process = await Process.start(Platform.executable, args);
+      var process = await Process.start(executable, args);
       stderr.addStream(process.stderr);
       var futureProcessOutput = process.stdout.map(utf8.decode).toList();
 
@@ -128,16 +152,16 @@
     });
   });
 
-  group('Hello World with Summaries', () {
-    final greetingDart = file('test/worker/greeting.dart');
-    final helloDart = file('test/worker/hello.dart');
+  group('$mode: Hello World with Summaries', () {
+    final greetingDart = file('greeting.dart');
+    final helloDart = file('hello.dart');
 
-    final greetingJS = file('test/worker/greeting.js');
-    final greetingSummary = file('test/worker/greeting.api.ds');
-    final helloJS = file('test/worker/hello_world.js');
+    final greetingJS = file('greeting.js');
+    final greetingSummary = file('greeting.$ext');
+    final helloJS = file('hello_world.js');
 
-    final greeting2JS = file('test/worker/greeting2.js');
-    final greeting2Summary = file('test/worker/greeting2.api.ds');
+    final greeting2JS = file('greeting2.js');
+    final greeting2Summary = file('greeting2.$ext');
 
     setUp(() {
       greetingDart.writeAsStringSync('String greeting = "hello";');
@@ -156,36 +180,35 @@
     });
 
     test('can compile in basic mode', () {
-      final dartSdkSummary = file('gen/sdk/ddc_sdk.sum');
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--summary-extension=api.ds',
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        greetingJS.path,
-        greetingDart.path,
-      ]);
-      expect(result.exitCode, EXIT_CODE_OK);
+      var result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-source-map',
+                '-o',
+                greetingJS.path,
+                greetingDart.path,
+              ]);
       expect(result.stdout, isEmpty);
       expect(result.stderr, isEmpty);
+      expect(result.exitCode, EXIT_CODE_OK);
       expect(greetingJS.existsSync(), isTrue);
       expect(greetingSummary.existsSync(), isTrue);
 
-      result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--no-source-map',
-        '--no-summarize',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '--summary-extension=api.ds',
-        '-s',
-        greetingSummary.path,
-        '-o',
-        helloJS.path,
-        helloDart.path,
-      ]);
+      result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-source-map',
+                '--no-summarize',
+                '-s',
+                greetingSummary.path,
+                '-o',
+                helloJS.path,
+                helloDart.path,
+              ]);
       expect(result.exitCode, EXIT_CODE_OK);
       expect(result.stdout, isEmpty);
       expect(result.stderr, isEmpty);
@@ -193,54 +216,53 @@
     });
 
     test('reports error on overlapping summaries', () {
-      final dartSdkSummary = file('gen/sdk/ddc_sdk.sum');
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--summary-extension=api.ds',
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        greetingJS.path,
-        greetingDart.path,
-      ]);
+      var result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-source-map',
+                '-o',
+                greetingJS.path,
+                greetingDart.path,
+              ]);
       expect(result.exitCode, EXIT_CODE_OK);
       expect(result.stdout, isEmpty);
       expect(result.stderr, isEmpty);
       expect(greetingJS.existsSync(), isTrue);
       expect(greetingSummary.existsSync(), isTrue);
 
-      result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--summary-extension=api.ds',
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        greeting2JS.path,
-        greetingDart.path,
-      ]);
+      result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-source-map',
+                '-o',
+                greeting2JS.path,
+                greetingDart.path,
+              ]);
       expect(result.exitCode, EXIT_CODE_OK);
       expect(result.stdout, isEmpty);
       expect(result.stderr, isEmpty);
       expect(greeting2JS.existsSync(), isTrue);
       expect(greeting2Summary.existsSync(), isTrue);
 
-      result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--no-source-map',
-        '--no-summarize',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '--summary-extension=api.ds',
-        '-s',
-        greetingSummary.path,
-        '-s',
-        greeting2Summary.path,
-        '-o',
-        helloJS.path,
-        helloDart.path,
-      ]);
+      result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-source-map',
+                '--no-summarize',
+                '-s',
+                greetingSummary.path,
+                '-s',
+                greeting2Summary.path,
+                '-o',
+                helloJS.path,
+                helloDart.path,
+              ]);
       // TODO(vsm): Re-enable when we turn this check back on.
       expect(result.exitCode, 0);
       // expect(result.exitCode, 65);
@@ -250,10 +272,9 @@
     });
   });
 
-  group('Error handling', () {
-    final dartSdkSummary = file('gen/sdk/ddc_sdk.sum');
-    final badFileDart = file('test/worker/bad.dart');
-    final badFileJs = file('test/worker/bad.js');
+  group('$mode: Error handling', () {
+    final badFileDart = file('bad.dart');
+    final badFileJs = file('bad.js');
 
     tearDown(() {
       if (badFileDart.existsSync()) badFileDart.deleteSync();
@@ -261,40 +282,41 @@
     });
 
     test('incorrect usage', () {
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        'oops',
-      ]);
+      var result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                'oops',
+              ]);
       expect(result.exitCode, 64);
       expect(
-          result.stdout, contains('Please include the output file location.'));
+          result.stdout, contains('Please specify the output file location.'));
       expect(result.stdout, isNot(contains('#0')));
     });
 
     test('compile errors', () {
       badFileDart.writeAsStringSync('main() => "hello world"');
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        badFileJs.path,
-        badFileDart.path,
-      ]);
+      var result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-source-map',
+                '-o',
+                badFileJs.path,
+                badFileDart.path,
+              ]);
       expect(result.exitCode, 1);
-      expect(result.stdout, contains("[error] Expected to find ';'"));
+      expect(result.stdout, contains(RegExp(r"Expected (to find )?\';\'")));
     });
   });
 
-  group('Parts', () {
-    final dartSdkSummary = file('gen/sdk/ddc_sdk.sum');
-    final partFile = file('test/worker/greeting.dart');
-    final libraryFile = file('test/worker/hello.dart');
+  group('$mode: Parts', () {
+    final partFile = file('greeting.dart');
+    final libraryFile = file('hello.dart');
 
-    final outJS = file('test/worker/output.js');
+    final outJS = file('output.js');
 
     setUp(() {
       partFile.writeAsStringSync('part of hello;\n'
@@ -311,17 +333,18 @@
     });
 
     test('works if part and library supplied', () {
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--no-summarize',
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        outJS.path,
-        partFile.path,
-        libraryFile.path,
-      ]);
+      var result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-summarize',
+                '--no-source-map',
+                '-o',
+                outJS.path,
+                partFile.path,
+                libraryFile.path,
+              ]);
       expect(result.stdout, isEmpty);
       expect(result.stderr, isEmpty);
       expect(result.exitCode, 0);
@@ -329,38 +352,43 @@
     });
 
     test('works if part is not supplied', () {
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--no-summarize',
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        outJS.path,
-        libraryFile.path,
-      ]);
+      var result = Process.runSync(
+          executable,
+          executableArgs +
+              baseArgs +
+              [
+                '--no-summarize',
+                '--no-source-map',
+                '-o',
+                outJS.path,
+                libraryFile.path,
+              ]);
       expect(result.stdout, isEmpty);
       expect(result.stderr, isEmpty);
       expect(result.exitCode, 0);
       expect(outJS.existsSync(), isTrue);
     });
 
-    test('part without library is silently ignored', () {
-      var result = Process.runSync(Platform.executable, [
-        dartdevc,
-        '--no-summarize',
-        '--no-source-map',
-        '--dart-sdk-summary',
-        dartSdkSummary.path,
-        '-o',
-        outJS.path,
-        partFile.path,
-      ]);
-      expect(result.stdout, isEmpty);
-      expect(result.stderr, isEmpty);
-      expect(result.exitCode, 0);
-      expect(outJS.existsSync(), isTrue);
-    });
+    if (!isKernel) {
+      // TODO(vsm): Consider dropping this test.  Kernel behavior is better.
+      test('part without library is silently ignored', () {
+        var result = Process.runSync(
+            executable,
+            executableArgs +
+                baseArgs +
+                [
+                  '--no-summarize',
+                  '--no-source-map',
+                  '-o',
+                  outJS.path,
+                  partFile.path,
+                ]);
+        expect(result.stdout, isEmpty);
+        expect(result.stderr, isEmpty);
+        expect(result.exitCode, 0);
+        expect(outJS.existsSync(), isTrue);
+      });
+    }
   });
 }
 
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index c50e05b..3cd4ed0 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -885,6 +885,14 @@
             "pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart",
             "-rnone"
           ]
+        },
+        {
+          "name": "ddc worker tests",
+          "script": "out/ReleaseX64/dart",
+          "arguments": [
+            "pkg/dev_compiler/test/worker/worker_test.dart",
+            "-rnone"
+          ]
         }
       ]
     },
@@ -950,6 +958,14 @@
             "pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart",
             "-rnone"
           ]
+        },
+        {
+          "name": "ddc worker tests",
+          "script": "xcodebuild/ReleaseX64/dart",
+          "arguments": [
+            "pkg/dev_compiler/test/worker/worker_test.dart",
+            "-rnone"
+          ]
         }
       ]
     },