From 8fcd997345796d80c7ec23e7cf69d377c6afc495 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 20 Jan 2023 14:38:24 -0800 Subject: [PATCH] [pigeon] Convert run_tests.sh to Dart (#3075) * Remove test_pigeon_android, which is unused * Update Dart unit test output names for consistency * Simplify unit test generation * Fold dart analysis tests into the dart unit test system, which already does analysis * Move Java unit tests to Dart * Remove more dead code, consolidate slightly * Move legacy iOS unit tests to Dart * Move command-line tests from bash to Dart * Move default test set to Dart; eliminate sh * Update docs reference to script * Fix legacy iOS test * Disable iOS integration tests --- .cirrus.yml | 6 +- packages/pigeon/CONTRIBUTING.md | 3 +- .../lib/.gitignore | 9 + .../lib/all_datatypes.dart | 252 ----------- ...pigeon.dart => flutter_unittests.gen.dart} | 0 .../{primitive.dart => primitive.gen.dart} | 0 .../test/null_safe_test.dart | 2 +- .../test/primitive_test.dart | 2 +- .../test/primitive_test.mocks.dart | 2 +- packages/pigeon/run_tests.sh | 405 ------------------ packages/pigeon/tool/run_tests.dart | 240 +++++++++-- 11 files changed, 210 insertions(+), 711 deletions(-) create mode 100644 packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/.gitignore delete mode 100644 packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/all_datatypes.dart rename packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/{null_safe_pigeon.dart => flutter_unittests.gen.dart} (100%) rename packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/{primitive.dart => primitive.gen.dart} (100%) delete mode 100755 packages/pigeon/run_tests.sh diff --git a/.cirrus.yml b/.cirrus.yml index 7210d19ec5..821f9dfcb0 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -191,14 +191,12 @@ task: CHANNEL: "stable" << : *INSTALL_CHROME_LINUX local_tests_script: - # pigeon tests currently don't support Linux: - # https://github.com/flutter/flutter/issues/100386 # flutter_image # https://github.com/flutter/flutter/issues/100387 - if [[ "$CHANNEL" == "master" ]]; then - - ./script/tool_runner.sh custom-test --exclude=pigeon + - ./script/tool_runner.sh custom-test - else - - ./script/tool_runner.sh custom-test --exclude=pigeon,flutter_image + - ./script/tool_runner.sh custom-test --exclude=flutter_image - fi ### Web tasks ### - name: web-build_all_packages diff --git a/packages/pigeon/CONTRIBUTING.md b/packages/pigeon/CONTRIBUTING.md index 0bad855a9b..ed8541aa2c 100644 --- a/packages/pigeon/CONTRIBUTING.md +++ b/packages/pigeon/CONTRIBUTING.md @@ -34,7 +34,8 @@ generators with that AST. ## Testing Overview -Pigeon has 3 types of tests, you'll find them all in [run_tests.sh](./run_tests.sh). +Pigeon has 3 types of tests, you'll find them all in +[run_tests.dart](./tool/run_tests.dart). * Unit tests - These are the fastest tests that are just typical unit tests, they may be generating code and checking it against a regular expression to diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/.gitignore b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/.gitignore new file mode 100644 index 0000000000..94ed05fd4e --- /dev/null +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/.gitignore @@ -0,0 +1,9 @@ +# TODO(stuartmorgan) Remove this file when these are no longer generated; +# see the TODO in _runFlutterUnitTests in run_tests.dart +async_handlers.gen.dart +host2flutter.gen.dart +list.gen.dart +void_arg_flutter.gen.dart +void_arg_host.gen.dart +voidflutter.gen.dart +voidhost.gen.dart diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/all_datatypes.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/all_datatypes.dart deleted file mode 100644 index 9b07455774..0000000000 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/all_datatypes.dart +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Autogenerated from Pigeon (v4.2.9), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import -import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; - -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; -import 'package:flutter/services.dart'; - -class Everything { - Everything({ - this.aBool, - this.anInt, - this.aDouble, - this.aString, - this.aByteArray, - this.a4ByteArray, - this.a8ByteArray, - this.aFloatArray, - this.aList, - this.aMap, - this.nestedList, - this.mapWithAnnotations, - this.mapWithObject, - }); - - bool? aBool; - - int? anInt; - - double? aDouble; - - String? aString; - - Uint8List? aByteArray; - - Int32List? a4ByteArray; - - Int64List? a8ByteArray; - - Float64List? aFloatArray; - - List? aList; - - Map? aMap; - - List?>? nestedList; - - Map? mapWithAnnotations; - - Map? mapWithObject; - - Object encode() { - final List pigeonList = []; - pigeonList.add(aBool); - pigeonList.add(anInt); - pigeonList.add(aDouble); - pigeonList.add(aString); - pigeonList.add(aByteArray); - pigeonList.add(a4ByteArray); - pigeonList.add(a8ByteArray); - pigeonList.add(aFloatArray); - pigeonList.add(aList); - pigeonList.add(aMap); - pigeonList.add(nestedList); - pigeonList.add(mapWithAnnotations); - pigeonList.add(mapWithObject); - return pigeonList; - } - - static Everything decode(Object result) { - result as List; - return Everything( - aBool: result[0] as bool?, - anInt: result[1] as int?, - aDouble: result[2] as double?, - aString: result[3] as String?, - aByteArray: result[4] as Uint8List?, - a4ByteArray: result[5] as Int32List?, - a8ByteArray: result[6] as Int64List?, - aFloatArray: result[7] as Float64List?, - aList: result[8] as List?, - aMap: result[9] as Map?, - nestedList: (result[10] as List?)?.cast?>(), - mapWithAnnotations: - (result[11] as Map?)?.cast(), - mapWithObject: - (result[12] as Map?)?.cast(), - ); - } -} - -class _HostEverythingCodec extends StandardMessageCodec { - const _HostEverythingCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is Everything) { - buffer.putUint8(128); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 128: - return Everything.decode(readValue(buffer)! as List); - - default: - return super.readValueOfType(type, buffer); - } - } -} - -class HostEverything { - /// Constructor for [HostEverything]. The [binaryMessenger] named argument is - /// available for dependency injection. If it is left null, the default - /// BinaryMessenger will be used which routes to the host platform. - HostEverything({BinaryMessenger? binaryMessenger}) - : _binaryMessenger = binaryMessenger; - final BinaryMessenger? _binaryMessenger; - - static const MessageCodec codec = _HostEverythingCodec(); - - Future giveMeEverything() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.HostEverything.giveMeEverything', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send(null) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: (replyList[0] as String?)!, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as Everything?)!; - } - } - - Future echo(Everything arg_everything) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.HostEverything.echo', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_everything]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: (replyList[0] as String?)!, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as Everything?)!; - } - } -} - -class _FlutterEverythingCodec extends StandardMessageCodec { - const _FlutterEverythingCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is Everything) { - buffer.putUint8(128); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 128: - return Everything.decode(readValue(buffer)! as List); - - default: - return super.readValueOfType(type, buffer); - } - } -} - -abstract class FlutterEverything { - static const MessageCodec codec = _FlutterEverythingCodec(); - - Everything giveMeEverything(); - - Everything echo(Everything everything); - - static void setup(FlutterEverything? api, - {BinaryMessenger? binaryMessenger}) { - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.FlutterEverything.giveMeEverything', codec, - binaryMessenger: binaryMessenger); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - // ignore message - final Everything output = api.giveMeEverything(); - return output; - }); - } - } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.FlutterEverything.echo', codec, - binaryMessenger: binaryMessenger); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.FlutterEverything.echo was null.'); - final List args = (message as List?)!; - final Everything? arg_everything = (args[0] as Everything?); - assert(arg_everything != null, - 'Argument for dev.flutter.pigeon.FlutterEverything.echo was null, expected non-null Everything.'); - final Everything output = api.echo(arg_everything!); - return output; - }); - } - } - } -} diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart similarity index 100% rename from packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart rename to packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.gen.dart similarity index 100% rename from packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.dart rename to packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.gen.dart diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart index 317bea9394..32fdb52895 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_unit_tests/null_safe_pigeon.dart'; +import 'package:flutter_unit_tests/flutter_unittests.gen.dart'; import 'package:flutter_unit_tests/nullable_returns.gen.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.dart index d83383f64d..175bf53468 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.dart @@ -4,7 +4,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_unit_tests/primitive.dart'; +import 'package:flutter_unit_tests/primitive.gen.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.mocks.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.mocks.dart index 77923e5093..cd3dfc0c9d 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.mocks.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/primitive_test.mocks.dart @@ -7,7 +7,7 @@ import 'dart:typed_data' as _i2; import 'dart:ui' as _i5; import 'package:flutter/src/services/binary_messenger.dart' as _i3; -import 'package:flutter_unit_tests/primitive.dart' as _i6; +import 'package:flutter_unit_tests/primitive.gen.dart' as _i6; import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: comment_references diff --git a/packages/pigeon/run_tests.sh b/packages/pigeon/run_tests.sh deleted file mode 100755 index 20bb2dbf54..0000000000 --- a/packages/pigeon/run_tests.sh +++ /dev/null @@ -1,405 +0,0 @@ -#!/bin/bash -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -############################################################################### -# run_tests.sh -# -# This runs all the different types of tests for pigeon. It should be run from -# the directory that contains the script. -############################################################################### - -# exit when any command fails -set -e - -############################################################################### -# Variables -############################################################################### -flutter=$(which flutter) -flutter_bin=$(dirname $flutter) -framework_path="$flutter_bin/cache/artifacts/engine/ios/" - -java_linter=checkstyle-8.41-all.jar -java_formatter=google-java-format-1.3-all-deps.jar -google_checks=google_checks.xml -google_checks_version=7190c47ca5515ad8cb827bc4065ae7664d2766c1 -java_error_prone=error_prone_core-2.5.1-with-dependencies.jar -dataflow_shaded=dataflow-shaded-3.7.1.jar -jformat_string=jFormatString-3.0.0.jar -java_version=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1) -javac_jar=javac-9+181-r4173-1.jar -if [ $java_version == "8" ]; then - javac_bootclasspath="-J-Xbootclasspath/p:ci/$javac_jar" -else - javac_bootclasspath= -fi -run_pigeon="dart bin/pigeon.dart.dill --copyright_header ./copyright_header.txt" - -############################################################################### -# Helper Functions -############################################################################### - -# Create a temporary directory in a way that works on both Linux and macOS. -# -# The mktemp commands have slighly semantics on the BSD systems vs GNU systems. -mktmpdir() { - mktemp -d flutter_pigeon.XXXXXX 2>/dev/null || mktemp -d -t flutter_pigeon. -} - -# test_pigeon_android() -# -# Compiles the pigeon file to a temp directory and attempts to compile the java -# code. -# TODO(stuartmorgan): Remove this in favor of unit testing all files, which -# already includes compilation. -test_pigeon_android() { - echo "test_pigeon_android($1)" - temp_dir=$(mktmpdir) - - $run_pigeon \ - --input $1 \ - --dart_out $temp_dir/pigeon.dart \ - --java_out $temp_dir/Pigeon.java \ - --java_package foo - - java -jar ci/$java_formatter --replace "$temp_dir/Pigeon.java" - java -jar ci/$java_linter -c "ci/$google_checks" "$temp_dir/Pigeon.java" - if ! javac \ - $javac_bootclasspath \ - -XDcompilePolicy=simple \ - -processorpath "ci/$java_error_prone:ci/$dataflow_shaded:ci/$jformat_string" \ - '-Xplugin:ErrorProne -Xep:CatchingUnchecked:ERROR' \ - -classpath "$flutter_bin/cache/artifacts/engine/android-x64/flutter.jar" \ - $temp_dir/Pigeon.java; then - echo "javac $temp_dir/Pigeon.java failed" - exit 1 - fi - - rm -rf $temp_dir -} - -# test_null_safe_dart() -# -# Compiles the pigeon file to a temp directory and attempts to run the dart -# analyzer on it. -# TODO(stuartmorgan): Remove this in favor of analyzing test_plugin. -test_pigeon_dart() { - echo "test_pigeon_dart($1, $2)" - local flutter_project_dir=$2 - - $run_pigeon \ - --input $1 \ - --dart_out $flutter_project_dir/lib/pigeon.dart - - dart analyze $flutter_project_dir/lib/pigeon.dart --fatal-infos --fatal-warnings - - rm $flutter_project_dir/lib/pigeon.dart -} - -print_usage() { - echo "usage: ./run_tests.sh [-l] [-t test_name] - -flags: - -t test_name: Run only specified test. - -l : List available tests. -" -} - -############################################################################### -# Stages -############################################################################### -get_java_linter_formatter() { - if [ ! -f "ci/$java_linter" ]; then - curl -L https://github.com/checkstyle/checkstyle/releases/download/checkstyle-8.41/$java_linter >"ci/$java_linter" - fi - if [ ! -f "ci/$java_formatter" ]; then - curl -L https://github.com/google/google-java-format/releases/download/google-java-format-1.3/$java_formatter >"ci/$java_formatter" - fi - if [ ! -f "ci/$google_checks" ]; then - curl -L https://raw.githubusercontent.com/checkstyle/checkstyle/$google_checks_version/src/main/resources/$google_checks >"ci/$google_checks" - fi - if [ ! -f "ci/$java_error_prone" ]; then - curl https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/2.5.1/$java_error_prone >"ci/$java_error_prone" - fi - if [ ! -f "ci/$dataflow_shaded" ]; then - curl https://repo1.maven.org/maven2/org/checkerframework/dataflow-shaded/3.7.1/$dataflow_shaded >"ci/$dataflow_shaded" - fi - if [ ! -f "ci/$jformat_string" ]; then - curl https://repo1.maven.org/maven2/com/google/code/findbugs/jFormatString/3.0.0/$jformat_string >"ci/$jformat_string" - fi - if [ ! -f "ci/$javac_jar" ]; then - curl https://repo1.maven.org/maven2/com/google/errorprone/javac/9+181-r4173-1/$javac_jar >"ci/$javac_jar" - fi -} - -run_dart_unittests() { - dart run tool/run_tests.dart -t dart_unittests --skip-generation -} - -test_command_line() { - # Test with no arguments. - $run_pigeon 1>/dev/null - # Test one_language flag. With this flag specified, java_out can be generated - # without dart_out. - $run_pigeon \ - --input pigeons/message.dart \ - --one_language \ - --java_out stdout \ - | grep "public class Message">/dev/null - # Test dartOut in ConfigurePigeon overrides output. - $run_pigeon --input pigeons/configure_pigeon_dart_out.dart 1>/dev/null - # Make sure AST generation exits correctly. - $run_pigeon --input pigeons/message.dart --one_language --ast_out /dev/null -} - -run_flutter_unittests() { - dart run tool/run_tests.dart -t flutter_unittests --skip-generation -} - -run_mock_handler_tests() { - dart run tool/run_tests.dart -t mock_handler_tests --skip-generation -} - -run_ios_swift_unittests() { - dart run tool/run_tests.dart -t ios_swift_unittests --skip-generation -} - -run_ios_swift_e2e_tests() { - dart run tool/run_tests.dart -t ios_swift_integration_tests --skip-generation -} - -run_macos_swift_unittests() { - dart run tool/run_tests.dart -t macos_swift_unittests --skip-generation -} - -run_macos_swift_e2e_tests() { - dart run tool/run_tests.dart -t macos_swift_integration_tests --skip-generation -} - -run_android_kotlin_unittests() { - dart run tool/run_tests.dart -t android_kotlin_unittests --skip-generation -} - -run_android_kotlin_e2e_tests() { - dart run tool/run_tests.dart -t android_kotlin_integration_tests --skip-generation -} - -run_dart_compilation_tests() { - local temp_dir=$(mktmpdir) - local flutter_project_dir=$temp_dir/project - - flutter create --platforms="android" $flutter_project_dir 1> /dev/null - - test_pigeon_dart ./pigeons/async_handlers.dart $flutter_project_dir - test_pigeon_dart ./pigeons/core_tests.dart $flutter_project_dir - test_pigeon_dart ./pigeons/host2flutter.dart $flutter_project_dir - test_pigeon_dart ./pigeons/list.dart $flutter_project_dir - test_pigeon_dart ./pigeons/message.dart $flutter_project_dir - test_pigeon_dart ./pigeons/void_arg_flutter.dart $flutter_project_dir - test_pigeon_dart ./pigeons/void_arg_host.dart $flutter_project_dir - test_pigeon_dart ./pigeons/voidflutter.dart $flutter_project_dir - test_pigeon_dart ./pigeons/voidhost.dart $flutter_project_dir - - rm -rf $temp_dir -} - -run_ios_objc_unittests() { - dart run tool/run_tests.dart -t ios_objc_unittests --skip-generation -} - -# TODO(stuartmorgan): Remove once run_ios_objc_unittests works in CI; see -# related TODOs below. -run_ios_legacy_unittests() { - pushd $PWD - cd platform_tests/ios_unit_tests - flutter build ios --simulator - cd ios - xcodebuild \ - -workspace Runner.xcworkspace \ - -scheme RunnerTests \ - -sdk iphonesimulator \ - -destination 'platform=iOS Simulator,name=iPhone 8' \ - test - popd -} - -run_ios_objc_e2e_tests() { - dart run tool/run_tests.dart -t ios_objc_integration_tests --skip-generation -} - -run_android_unittests() { - pushd $PWD - cd platform_tests/alternate_language_test_plugin/example - if [ ! -f "android/gradlew" ]; then - flutter build apk --debug - fi - cd android - ./gradlew test - popd -} - -run_android_java_e2e_tests() { - dart run tool/run_tests.dart -t android_java_integration_tests --skip-generation -} - -############################################################################### -# main -############################################################################### -should_run_android_unittests=true -should_run_dart_compilation_tests=true -should_run_dart_unittests=true -should_run_flutter_unittests=true -# TODO(stuartmorgan): Enable by default once CI issues are solved; see -# https://github.com/flutter/packages/pull/2816. -should_run_ios_objc_e2e_tests=false -# TODO(stuartmorgan): Enable the new version by default and remove the legacy -# version once CI issues are solved; see -# https://github.com/flutter/packages/pull/2816. -should_run_ios_objc_unittests=false -should_run_ios_legacy_unittests=true -should_run_ios_swift_unittests=true -# Currently these are testing exactly the same thing as macos_swift_e2e_tests, -# so we don't need to run both by default. This should become `true` if any -# iOS-only tests are added (e.g., for a feature not supported by macOS). -should_run_ios_swift_e2e_tests=false -should_run_mock_handler_tests=true -should_run_macos_swift_unittests=true -should_run_macos_swift_e2e_tests=true -should_run_android_kotlin_unittests=true -# Default to false until there is CI support. See -# https://github.com/flutter/flutter/issues/111505 -should_run_android_java_e2e_tests=false -should_run_android_kotlin_e2e_tests=false -while getopts "t:l?h" opt; do - case $opt in - t) - should_run_android_unittests=false - should_run_dart_compilation_tests=false - should_run_dart_unittests=false - should_run_flutter_unittests=false - should_run_ios_objc_unittests=false - should_run_ios_objc_e2e_tests=false - should_run_ios_legacy_unittests=false - should_run_ios_swift_unittests=false - should_run_ios_swift_e2e_tests=false - should_run_mock_handler_tests=false - should_run_macos_swift_unittests=false - should_run_macos_swift_e2e_tests=false - should_run_android_kotlin_unittests=false - should_run_android_java_e2e_tests=false - should_run_android_kotlin_e2e_tests=false - case $OPTARG in - # TODO(stuartmorgan): Rename to include "java". - android_unittests) should_run_android_unittests=true ;; - android_java_e2e_tests) should_run_android_java_e2e_tests=true ;; - dart_compilation_tests) should_run_dart_compilation_tests=true ;; - dart_unittests) should_run_dart_unittests=true ;; - flutter_unittests) should_run_flutter_unittests=true ;; - ios_objc_e2e_tests) should_run_ios_objc_e2e_tests=true ;; - ios_objc_unittests) should_run_ios_objc_unittests=true ;; - ios_unittests) should_run_ios_legacy_unittests=true ;; - ios_swift_unittests) should_run_ios_swift_unittests=true ;; - ios_swift_e2e_tests) should_run_ios_swift_e2e_tests=true ;; - mock_handler_tests) should_run_mock_handler_tests=true ;; - macos_swift_unittests) should_run_macos_swift_unittests=true ;; - macos_swift_e2e_tests) should_run_macos_swift_e2e_tests=true ;; - android_kotlin_unittests) should_run_android_kotlin_unittests=true ;; - android_kotlin_e2e_tests) should_run_android_kotlin_e2e_tests=true ;; - *) - echo "unrecognized test: $OPTARG" - exit 1 - ;; - esac - ;; - l) - echo "available tests for -t: - android_unittests - Unit tests on generated Java code. - android_java_e2e_tests - Integration tests on generated Java code on Android. - android_kotlin_unittests - Unit tests on generated Kotlin code on Android. - android_kotlin_e2e_tests - Integration tests on generated Kotlin code on Android. - dart_compilation_tests - Compilation tests on generated Dart code. - dart_unittests - Unit tests on and analysis on Pigeon's implementation. - flutter_unittests - Unit tests on generated Dart code. - ios_objc_unittests - Unit tests on generated Obj-C code. - ios_unittests - Legacy unit tests on generated Obj-C code. Use ios_objc_unittests instead. - ios_objc_e2e_tests - Integration tests on generated Obj-C code. - ios_swift_unittests - Unit tests on generated Swift code. - ios_swift_e2e_tests - Integration tests on generated Swift code on iOS. - mock_handler_tests - Unit tests on generated Dart mock handler code. - macos_swift_unittests - Unit tests on generated Swift code on macOS. - macos_swift_e2e_tests - Integration tests on generated Swift code on macOS. - " - exit 1 - ;; - \h) - print_usage - exit 1 - ;; - \?) - print_usage - exit 1 - ;; - ?) - print_usage - exit 1 - ;; - esac -done - -############################################################################## -dart pub get -dart --snapshot-kind=kernel --snapshot=bin/pigeon.dart.dill bin/pigeon.dart - -# Pre-generate platform_test output files, which most tests rely on existing. -dart run tool/generate.dart - -if [ "$should_run_android_unittests" = true ]; then - get_java_linter_formatter -fi -test_command_line -if [ "$should_run_dart_unittests" = true ]; then - run_dart_unittests -fi -if [ "$should_run_flutter_unittests" = true ]; then - run_flutter_unittests -fi -if [ "$should_run_mock_handler_tests" = true ]; then - run_mock_handler_tests -fi -if [ "$should_run_dart_compilation_tests" = true ]; then - run_dart_compilation_tests -fi -if [ "$should_run_ios_objc_unittests" = true ]; then - run_ios_objc_unittests -fi -if [ "$should_run_ios_legacy_unittests" = true ]; then - run_ios_legacy_unittests -fi -if [ "$should_run_ios_swift_unittests" = true ]; then - run_ios_swift_unittests -fi -if [ "$should_run_ios_swift_e2e_tests" = true ]; then - run_ios_swift_e2e_tests -fi -if [ "$should_run_ios_objc_e2e_tests" = true ]; then - run_ios_objc_e2e_tests -fi -if [ "$should_run_android_unittests" = true ]; then - run_android_unittests -fi -if [ "$should_run_android_java_e2e_tests" = true ]; then - run_android_java_e2e_tests -fi -if [ "$should_run_macos_swift_unittests" = true ]; then - run_macos_swift_unittests -fi -if [ "$should_run_macos_swift_e2e_tests" = true ]; then - run_macos_swift_e2e_tests -fi -if [ "$should_run_android_kotlin_unittests" = true ]; then - run_android_kotlin_unittests -fi -if [ "$should_run_android_kotlin_e2e_tests" = true ]; then - run_android_kotlin_e2e_tests -fi diff --git a/packages/pigeon/tool/run_tests.dart b/packages/pigeon/tool/run_tests.dart index df88b15fa3..d5daff68e4 100644 --- a/packages/pigeon/tool/run_tests.dart +++ b/packages/pigeon/tool/run_tests.dart @@ -9,7 +9,7 @@ /// /// usage: dart run tool/run_tests.dart //////////////////////////////////////////////////////////////////////////////// -import 'dart:io' show File, Platform, exit; +import 'dart:io' show File, Directory, Platform, exit; import 'dart:math'; import 'package:args/args.dart'; @@ -39,59 +39,82 @@ class _TestInfo { final String? description; } +// Test suite names. +const String androidJavaUnitTests = 'android_java_unittests'; +const String androidJavaIntegrationTests = 'android_java_integration_tests'; +const String androidKotlinUnitTests = 'android_kotlin_unittests'; +const String androidKotlinIntegrationTests = 'android_kotlin_integration_tests'; +const String iOSObjCUnitTests = 'ios_objc_unittests'; +const String iOSObjCUnitTestsLegacy = 'ios_objc_legacy_unittests'; +const String iOSObjCIntegrationTests = 'ios_objc_integration_tests'; +const String iOSSwiftUnitTests = 'ios_swift_unittests'; +const String iOSSwiftIntegrationTests = 'ios_swift_integration_tests'; +const String macOSSwiftUnitTests = 'macos_swift_unittests'; +const String macOSSwiftIntegrationTests = 'macos_swift_integration_tests'; +const String windowsUnitTests = 'windows_unittests'; +const String windowsIntegrationTests = 'windows_integration_tests'; +const String dartUnitTests = 'dart_unittests'; +const String flutterUnitTests = 'flutter_unittests'; +const String mockHandlerTests = 'mock_handler_tests'; +const String commandLineTests = 'command_line_tests'; + const Map _tests = { - 'windows_unittests': _TestInfo( + windowsUnitTests: _TestInfo( function: _runWindowsUnitTests, description: 'Unit tests on generated Windows C++ code.'), - 'windows_integration_tests': _TestInfo( + windowsIntegrationTests: _TestInfo( function: _runWindowsIntegrationTests, description: 'Integration tests on generated Windows C++ code.'), - 'android_java_unittests': _TestInfo( + androidJavaUnitTests: _TestInfo( function: _runAndroidJavaUnitTests, description: 'Unit tests on generated Java code.'), - 'android_java_integration_tests': _TestInfo( + androidJavaIntegrationTests: _TestInfo( function: _runAndroidJavaIntegrationTests, description: 'Integration tests on generated Java code.'), - 'android_kotlin_unittests': _TestInfo( + androidKotlinUnitTests: _TestInfo( function: _runAndroidKotlinUnitTests, description: 'Unit tests on generated Kotlin code.'), - 'android_kotlin_integration_tests': _TestInfo( + androidKotlinIntegrationTests: _TestInfo( function: _runAndroidKotlinIntegrationTests, description: 'Integration tests on generated Kotlin code.'), - 'dart_compilation_tests': _TestInfo( - function: _runDartCompilationTests, - description: 'Compilation tests on generated Dart code.'), - 'dart_unittests': _TestInfo( + dartUnitTests: _TestInfo( function: _runDartUnitTests, description: "Unit tests on and analysis on Pigeon's implementation."), - 'flutter_unittests': _TestInfo( + flutterUnitTests: _TestInfo( function: _runFlutterUnitTests, description: 'Unit tests on generated Dart code.'), - 'ios_objc_unittests': _TestInfo( + iOSObjCUnitTests: _TestInfo( function: _runIOSObjCUnitTests, description: 'Unit tests on generated Objective-C code.'), - 'ios_objc_integration_tests': _TestInfo( + iOSObjCUnitTestsLegacy: _TestInfo( + function: _runIOSObjCLegacyUnitTests, + description: + 'Unit tests on generated Objective-C code (legacy test harness).'), + iOSObjCIntegrationTests: _TestInfo( function: _runIOSObjCIntegrationTests, description: 'Integration tests on generated Objective-C code.'), - 'ios_swift_unittests': _TestInfo( + iOSSwiftUnitTests: _TestInfo( function: _runIOSSwiftUnitTests, description: 'Unit tests on generated Swift code.'), - 'ios_swift_integration_tests': _TestInfo( + iOSSwiftIntegrationTests: _TestInfo( function: _runIOSSwiftIntegrationTests, description: 'Integration tests on generated Swift code.'), - 'macos_swift_unittests': _TestInfo( + macOSSwiftUnitTests: _TestInfo( function: _runMacOSSwiftUnitTests, description: 'Unit tests on generated Swift code on macOS.'), - 'macos_swift_integration_tests': _TestInfo( + macOSSwiftIntegrationTests: _TestInfo( function: _runMacOSSwiftIntegrationTests, description: 'Integration tests on generated Swift code on macOS.'), - 'mock_handler_tests': _TestInfo( + mockHandlerTests: _TestInfo( function: _runMockHandlerTests, description: 'Unit tests on generated Dart mock handler code.'), + commandLineTests: _TestInfo( + function: _runCommandLineTests, + description: 'Tests running pigeon with various command-line options.'), }; Future _runAndroidJavaUnitTests() async { - throw UnimplementedError('See run_tests.sh.'); + return _runAndroidUnitTests(_alternateLanguageTestPluginRelativePath); } Future _runAndroidJavaIntegrationTests() async { @@ -100,8 +123,12 @@ Future _runAndroidJavaIntegrationTests() async { } Future _runAndroidKotlinUnitTests() async { - const String examplePath = './$_testPluginRelativePath/example'; - const String androidProjectPath = '$examplePath/android'; + return _runAndroidUnitTests(_testPluginRelativePath); +} + +Future _runAndroidUnitTests(String testPluginPath) async { + final String examplePath = './$testPluginPath/example'; + final String androidProjectPath = '$examplePath/android'; final File gradleFile = File(p.join(androidProjectPath, 'gradlew')); if (!gradleFile.existsSync()) { final int compileCode = await runFlutterBuild(examplePath, 'apk'); @@ -134,10 +161,6 @@ Future _runMobileIntegrationTests( ); } -Future _runDartCompilationTests() async { - throw UnimplementedError('See run_tests.sh.'); -} - Future _runDartUnitTests() async { int exitCode = await runProcess('dart', ['analyze', 'bin']); if (exitCode != 0) { @@ -195,19 +218,31 @@ Future _runFlutterUnitTests() async { // shared_test_plugin_code instead of having multiple copies of generation. const String flutterUnitTestsPath = 'platform_tests/flutter_null_safe_unit_tests'; + // Files from the pigeons/ directory to generate output for. + const List inputPigeons = [ + 'flutter_unittests', + 'core_tests', + 'primitive', + 'multiple_arity', + 'non_null_fields', + 'null_fields', + 'nullable_returns', + // TODO(stuartmorgan): Eliminate these files by ensuring that everything + // they are intended to cover is in core_tests.dart (or, if necessary in + // the short term due to limitations in non-Dart generators, a single other + // file). They aren't being unit tested, only analyzed. + 'async_handlers', + 'host2flutter', + 'list', + 'message', + 'void_arg_flutter', + 'void_arg_host', + 'voidflutter', + 'voidhost', + ]; final int generateCode = await _generateDart({ - 'pigeons/flutter_unittests.dart': - '$flutterUnitTestsPath/lib/null_safe_pigeon.dart', - 'pigeons/core_tests.dart': '$flutterUnitTestsPath/lib/core_tests.gen.dart', - 'pigeons/primitive.dart': '$flutterUnitTestsPath/lib/primitive.dart', - 'pigeons/multiple_arity.dart': - '$flutterUnitTestsPath/lib/multiple_arity.gen.dart', - 'pigeons/non_null_fields.dart': - '$flutterUnitTestsPath/lib/non_null_fields.gen.dart', - 'pigeons/null_fields.dart': - '$flutterUnitTestsPath/lib/null_fields.gen.dart', - 'pigeons/nullable_returns.dart': - '$flutterUnitTestsPath/lib/nullable_returns.gen.dart', + for (final String name in inputPigeons) + 'pigeons/$name.dart': '$flutterUnitTestsPath/lib/$name.gen.dart' }); if (generateCode != 0) { return generateCode; @@ -227,7 +262,14 @@ Future _runFlutterUnitTests() async { } Future _runIOSObjCUnitTests() async { - return _runIOSUnitTests(_alternateLanguageTestPluginRelativePath); + return _runIOSPluginUnitTests(_alternateLanguageTestPluginRelativePath); +} + +// TODO(stuartmorgan): Remove this, and the ios_unit_tests directory, once +// _runIOSObjCUnitTests works in CI; see +// https://github.com/flutter/packages/pull/2816. +Future _runIOSObjCLegacyUnitTests() async { + return _runIOSProjectUnitTests('platform_tests/ios_unit_tests'); } Future _runIOSObjCIntegrationTests() async { @@ -270,13 +312,17 @@ Future _runMacOSSwiftIntegrationTests() async { } Future _runIOSSwiftUnitTests() async { - return _runIOSUnitTests(_testPluginRelativePath); + return _runIOSPluginUnitTests(_testPluginRelativePath); } -Future _runIOSUnitTests(String testPluginPath) async { +Future _runIOSPluginUnitTests(String testPluginPath) async { final String examplePath = './$testPluginPath/example'; + return _runIOSProjectUnitTests(examplePath); +} + +Future _runIOSProjectUnitTests(String testProjectPath) async { final int compileCode = await runFlutterBuild( - examplePath, + testProjectPath, 'ios', flags: ['--simulator', '--no-codesign'], ); @@ -285,7 +331,7 @@ Future _runIOSUnitTests(String testPluginPath) async { } return runXcodeBuild( - '$examplePath/ios', + '$testProjectPath/ios', sdk: 'iphonesimulator', destination: 'platform=iOS Simulator,name=iPhone 8', extraArguments: ['test'], @@ -335,6 +381,61 @@ Future _runWindowsIntegrationTests() async { ); } +Future _runCommandLineTests() async { + final Directory tempDir = Directory.systemTemp.createTempSync('pigeon'); + final String tempOutput = p.join(tempDir.path, 'pigeon_output'); + const String pigeonScript = 'bin/pigeon.dart'; + final String snapshot = p.join(tempDir.path, 'pigeon.dart.dill'); + + // Precompile to make the repeated calls faster. + if (await runProcess('dart', [ + '--snapshot-kind=kernel', + '--snapshot=$snapshot', + pigeonScript + ]) != + 0) { + print('Unable to generate $snapshot from $pigeonScript'); + return 1; + } + + final List> testArguments = >[ + // Test with no arguments. + [], + // Test one_language flag. With this flag specified, java_out can be + // generated without dart_out. + [ + '--input', + 'pigeons/message.dart', + '--one_language', + '--java_out', + tempOutput + ], + // Test dartOut in ConfigurePigeon overrides output. + ['--input', 'pigeons/configure_pigeon_dart_out.dart'], + // Make sure AST generation exits correctly. + [ + '--input', + 'pigeons/message.dart', + '--one_language', + '--ast_out', + tempOutput + ], + ]; + + int exitCode = 0; + for (final List arguments in testArguments) { + print('Testing dart $pigeonScript ${arguments.join(', ')}'); + exitCode = await runProcess('dart', [snapshot, ...arguments], + streamOutput: false, logFailure: true); + if (exitCode != 0) { + break; + } + } + + tempDir.deleteSync(recursive: true); + return exitCode; +} + Future main(List args) async { final ArgParser parser = ArgParser() ..addMultiOption(_testFlag, abbr: 't', help: 'Only run specified tests.') @@ -385,10 +486,57 @@ ${parser.usage}'''); // If no tests are provided, run a default based on the host platform. This is // the mode used by CI. if (testsToRun.isEmpty) { - if (Platform.isWindows) { - testsToRun = ['windows_unittests', 'windows_integration_tests']; + const List androidTests = [ + androidJavaUnitTests, + androidKotlinUnitTests, + // TODO(stuartmorgan): Include these once CI supports running simulator + // tests. Currently these tests aren't run in CI. + // See https://github.com/flutter/flutter/issues/111505. + // androidJavaIntegrationTests, + // androidKotlinIntegrationTests, + ]; + const List macOSTests = [ + macOSSwiftUnitTests, + macOSSwiftIntegrationTests + ]; + const List iOSTests = [ + // TODO(stuartmorgan): Replace this with iOSObjCUnitTests once the CI + // issues are resolved; see https://github.com/flutter/packages/pull/2816. + iOSObjCUnitTestsLegacy, + // TODO(stuartmorgan): Enable by default once CI issues are solved; see + // https://github.com/flutter/packages/pull/2816. + // iOSObjCIntegrationTests, + iOSSwiftUnitTests, + // Currently these are testing exactly the same thing as + // macos_swift_e2e_tests, so we don't need to run both by default. This + // should be enabled if any iOS-only tests are added (e.g., for a feature + // not supported by macOS). + // iOSSwiftIntegrationTests, + ]; + const List windowsTests = [ + windowsUnitTests, + windowsIntegrationTests, + ]; + const List dartTests = [ + dartUnitTests, + flutterUnitTests, + mockHandlerTests, + commandLineTests, + ]; + + if (Platform.isMacOS) { + testsToRun = [ + ...dartTests, + ...androidTests, + ...iOSTests, + ...macOSTests, + ]; + } else if (Platform.isWindows) { + testsToRun = windowsTests; } else { - // TODO(gaaclarke): migrate from run_tests.sh to this script. + // TODO(stuartmorgan): Make a new entrypoint for developers that runs + // all tests their host supports by default, and move some of the tests + // above here. See https://github.com/flutter/flutter/issues/115393 } }