[pigeon] Port over several test suites from run_tests.sh to run_tests.dart (#532)

* Port over several test suites from run_tests.sh to run_tests.dart

This ports over
 - dart_unittests
 - flutter_unittests
 - mock_handler_tests

* [pigeon] Update version and changelog
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 7c89793..7f52ca1 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.0.14
+
+* [tests] Port several generator tests to run in Dart over bash
+
 ## 1.0.13
 
 * [style] Fixes new style rules for Dart analyzer.
diff --git a/packages/pigeon/bin/run_tests.dart b/packages/pigeon/bin/run_tests.dart
index b02afc0..8d0a3ba 100644
--- a/packages/pigeon/bin/run_tests.dart
+++ b/packages/pigeon/bin/run_tests.dart
@@ -5,8 +5,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 /// Script for executing the Pigeon tests
 ///
-/// This currently only supports Windows tests.
-///
 /// usage: pub run pigeon:run_tests
 ////////////////////////////////////////////////////////////////////////////////
 import 'dart:io' show Process, exit, stdout, stderr;
@@ -58,6 +56,16 @@
   return process;
 }
 
+Future<int> _runProcess(String command, List<String> arguments,
+    {String? workingDirectory}) async {
+  final Process process = await _streamOutput(Process.start(
+    command,
+    arguments,
+    workingDirectory: workingDirectory,
+  ));
+  return process.exitCode;
+}
+
 Future<int> _runAndroidUnitTests() async {
   throw UnimplementedError('See run_tests.sh.');
 }
@@ -67,11 +75,68 @@
 }
 
 Future<int> _runDartUnitTests() async {
-  throw UnimplementedError('See run_tests.sh.');
+  int exitCode = await _runProcess('dart', <String>['analyze', 'bin']);
+  if (exitCode != 0) {
+    return exitCode;
+  }
+  exitCode = await _runProcess('dart', <String>['analyze', 'lib']);
+  if (exitCode != 0) {
+    return exitCode;
+  }
+  exitCode = await _runProcess('dart', <String>['test']);
+  return exitCode;
 }
 
 Future<int> _runFlutterUnitTests() async {
-  throw UnimplementedError('See run_tests.sh.');
+  const String flutterUnitTestsPath =
+      'platform_tests/flutter_null_safe_unit_tests';
+  int generateCode = await _runPigeon(
+    input: 'pigeons/flutter_unittests.dart',
+    dartOut: '$flutterUnitTestsPath/lib/null_safe_pigeon.dart',
+  );
+  if (generateCode != 0) {
+    return generateCode;
+  }
+  generateCode = await _runPigeon(
+    input: 'pigeons/all_datatypes.dart',
+    dartOut: '$flutterUnitTestsPath/lib/all_datatypes.dart',
+  );
+  if (generateCode != 0) {
+    return generateCode;
+  }
+  generateCode = await _runPigeon(
+    input: 'pigeons/primitive.dart',
+    dartOut: '$flutterUnitTestsPath/lib/primitive.dart',
+  );
+  if (generateCode != 0) {
+    return generateCode;
+  }
+  generateCode = await _runPigeon(
+    input: 'pigeons/multiple_arity.dart',
+    dartOut: '$flutterUnitTestsPath/lib/multiple_arity.gen.dart',
+  );
+  if (generateCode != 0) {
+    return generateCode;
+  }
+
+  const List<String> testFiles = <String>[
+    'null_safe_test.dart',
+    'all_datatypes_test.dart',
+    'primitive_test.dart',
+    'multiple_arity_test.dart'
+  ];
+  for (final String testFile in testFiles) {
+    final int testCode = await _runProcess(
+      'flutter',
+      <String>['test', 'test/$testFile'],
+      workingDirectory: flutterUnitTestsPath,
+    );
+    if (testCode != 0) {
+      return testCode;
+    }
+  }
+
+  return 0;
 }
 
 Future<int> _runIosE2eTests() async {
@@ -83,14 +148,33 @@
 }
 
 Future<int> _runMockHandlerTests() async {
-  throw UnimplementedError('See run_tests.sh.');
+  const String unitTestsPath = './mock_handler_tester';
+  final int generateCode = await _runPigeon(
+    input: './pigeons/message.dart',
+    dartOut: './mock_handler_tester/test/message.dart',
+    dartTestOut: './mock_handler_tester/test/test.dart',
+  );
+  if (generateCode != 0) {
+    return generateCode;
+  }
+
+  final int testCode = await _runProcess(
+    'flutter',
+    <String>['test'],
+    workingDirectory: unitTestsPath,
+  );
+  if (testCode != 0) {
+    return testCode;
+  }
+  return 0;
 }
 
-Future<int> _runPigeon({
-  required String input,
-  String? cppHeaderOut,
-  String? cppSourceOut,
-}) async {
+Future<int> _runPigeon(
+    {required String input,
+    String? cppHeaderOut,
+    String? cppSourceOut,
+    String? dartOut,
+    String? dartTestOut}) async {
   const bool hasDart = false;
   final List<String> args = <String>[
     'pub',
@@ -111,6 +195,12 @@
       cppSourceOut,
     ]);
   }
+  if (dartOut != null) {
+    args.addAll(<String>['--dart_out', dartOut]);
+  }
+  if (dartTestOut != null) {
+    args.addAll(<String>['--dart_test_out', dartTestOut]);
+  }
   if (!hasDart) {
     args.add('--one_language');
   }
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index de2bb02..f806326 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -8,7 +8,7 @@
 import 'ast.dart';
 
 /// The current version of pigeon. This must match the version in pubspec.yaml.
-const String pigeonVersion = '1.0.13';
+const String pigeonVersion = '1.0.14';
 
 /// Read all the content from [stdin] to a String.
 String readStdin() {
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index 8e5b454..25740a3 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,10 +2,10 @@
 description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
 repository: https://github.com/flutter/packages/tree/master/packages/pigeon
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon
-version: 1.0.13 # This must match the version in lib/generator_tools.dart
+version: 1.0.14 # This must match the version in lib/generator_tools.dart
 
 environment:
-  sdk: '>=2.12.0 <3.0.0'
+  sdk: ">=2.12.0 <3.0.0"
 
 dependencies:
   analyzer: ^2.4.0
diff --git a/packages/pigeon/run_tests.sh b/packages/pigeon/run_tests.sh
index 81e5983..bf31af4 100755
--- a/packages/pigeon/run_tests.sh
+++ b/packages/pigeon/run_tests.sh
@@ -184,9 +184,7 @@
 }
 
 run_dart_unittests() {
-  dart analyze bin
-  dart analyze lib
-  dart test
+  dart pub run pigeon:run_tests -t dart_unittests
 }
 
 test_command_line() {
@@ -204,41 +202,11 @@
 }
 
 run_flutter_unittests() {
-  local flutter_tests="platform_tests/flutter_null_safe_unit_tests"
-  pushd $PWD
-  $run_pigeon \
-    --input pigeons/flutter_unittests.dart \
-    --dart_out "$flutter_tests/lib/null_safe_pigeon.dart"
-  $run_pigeon \
-    --input pigeons/all_datatypes.dart \
-    --dart_out "$flutter_tests/lib/all_datatypes.dart"
-  $run_pigeon \
-    --input pigeons/primitive.dart \
-    --dart_out "$flutter_tests/lib/primitive.dart"
-    $run_pigeon \
-    --input pigeons/multiple_arity.dart \
-    --dart_out "$flutter_tests/lib/multiple_arity.gen.dart"
-  cd "$flutter_tests"
-  flutter pub get
-  flutter test test/null_safe_test.dart
-  flutter test test/all_datatypes_test.dart
-  flutter test test/primitive_test.dart
-  flutter test test/primitive_test.dart
-  flutter test test/multiple_arity_test.dart
-  popd
+  dart pub run pigeon:run_tests -t flutter_unittests
 }
 
 run_mock_handler_tests() {
-  pushd $PWD
-  $run_pigeon \
-    --input pigeons/message.dart \
-    --dart_out mock_handler_tester/test/message.dart \
-    --dart_test_out mock_handler_tester/test/test.dart
-  dart format mock_handler_tester/test/message.dart
-  dart format mock_handler_tester/test/test.dart
-  cd mock_handler_tester
-  flutter test
-  popd
+  dart pub run pigeon:run_tests -t mock_handler_tests
 }
 
 run_dart_compilation_tests() {