diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 603682f3cc278..82946931baeda 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -6,6 +6,8 @@ if (is_fuchsia) { import("//build/fuchsia/sdk.gni") } +import("$flutter_root/testing/testing.gni") + source_set("flow") { sources = [ "compositor_context.cc", @@ -100,6 +102,10 @@ source_set("flow") { } } +test_fixtures("flow_fixtures") { + fixtures = [] +} + executable("flow_unittests") { testonly = true @@ -114,6 +120,7 @@ executable("flow_unittests") { deps = [ ":flow", + ":flow_fixtures", "$flutter_root/fml", "//third_party/dart/runtime:libdart_jit", # for tracing "//third_party/googletest:gtest", diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 26f51d99c9c87..0b50035a9e157 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/fuchsia/sdk.gni") +import("$flutter_root/testing/testing.gni") source_set("fml") { sources = [ @@ -182,6 +183,10 @@ source_set("fml") { } } +test_fixtures("fml_fixtures") { + fixtures = [] +} + executable("fml_unittests") { testonly = true @@ -208,6 +213,7 @@ executable("fml_unittests") { ] deps = [ + ":fml_fixtures", "$flutter_root/fml", "$flutter_root/testing", "//third_party/dart/runtime:libdart_jit", diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 11affdaaf28cc..61380101eaea0 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -96,7 +96,7 @@ source_set("runtime") { } test_fixtures("runtime_fixtures") { - fixtures = [ "fixtures/runtime_test.dart" ] + dart_main = "fixtures/runtime_test.dart" } source_set("runtime_unittests_common") { diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 27fca16561896..53deba81b5241 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -147,7 +147,7 @@ shell_gpu_configuration("shell_unittests_gpu_configuration") { } test_fixtures("shell_unittests_fixtures") { - fixtures = [ "fixtures/shell_test.dart" ] + dart_main = "fixtures/shell_test.dart" } shell_host_executable("shell_unittests") { diff --git a/shell/platform/common/cpp/client_wrapper/BUILD.gn b/shell/platform/common/cpp/client_wrapper/BUILD.gn index 4028b76650ef0..8f79589ba6473 100644 --- a/shell/platform/common/cpp/client_wrapper/BUILD.gn +++ b/shell/platform/common/cpp/client_wrapper/BUILD.gn @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("$flutter_root/testing/testing.gni") import("publish.gni") _wrapper_includes = [ @@ -75,6 +76,10 @@ source_set("client_wrapper_library_stubs") { ] } +test_fixtures("client_wrapper_fixtures") { + fixtures = [] +} + executable("client_wrapper_unittests") { testonly = true @@ -91,6 +96,7 @@ executable("client_wrapper_unittests") { deps = [ ":client_wrapper", + ":client_wrapper_fixtures", ":client_wrapper_library_stubs", "$flutter_root/testing", diff --git a/shell/platform/darwin/BUILD.gn b/shell/platform/darwin/BUILD.gn index 858bd39dc1708..812313502a8a9 100644 --- a/shell/platform/darwin/BUILD.gn +++ b/shell/platform/darwin/BUILD.gn @@ -4,6 +4,7 @@ assert(is_mac || is_ios) +import("$flutter_root/testing/testing.gni") import("framework_shared.gni") group("darwin") { @@ -61,6 +62,10 @@ source_set("framework_shared") { public_configs = [ "$flutter_root:config" ] } +test_fixtures("flutter_channels_fixtures") { + fixtures = [] +} + executable("flutter_channels_unittests") { testonly = true @@ -71,6 +76,7 @@ executable("flutter_channels_unittests") { deps = [ ":flutter_channels", + ":flutter_channels_fixtures", "$flutter_root/testing", "//third_party/dart/runtime:libdart_jit", ] diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index a1519da001fee..cc60500a1a358 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -57,7 +57,7 @@ source_set("embedder") { } test_fixtures("fixtures") { - fixtures = [ "fixtures/main.dart" ] + dart_main = "fixtures/main.dart" } executable("embedder_unittests") { diff --git a/shell/platform/glfw/client_wrapper/BUILD.gn b/shell/platform/glfw/client_wrapper/BUILD.gn index 1ba2c7e431237..2ebad7ee523d0 100644 --- a/shell/platform/glfw/client_wrapper/BUILD.gn +++ b/shell/platform/glfw/client_wrapper/BUILD.gn @@ -3,6 +3,7 @@ # found in the LICENSE file. import("$flutter_root/shell/platform/common/cpp/client_wrapper/publish.gni") +import("$flutter_root/testing/testing.gni") _wrapper_includes = [ "include/flutter/flutter_window.h", @@ -63,6 +64,10 @@ source_set("client_wrapper_library_stubs_glfw") { ] } +test_fixtures("client_wrapper_glfw_fixtures") { + fixtures = [] +} + executable("client_wrapper_glfw_unittests") { testonly = true @@ -73,6 +78,7 @@ executable("client_wrapper_glfw_unittests") { deps = [ ":client_wrapper_glfw", + ":client_wrapper_glfw_fixtures", ":client_wrapper_library_stubs_glfw", "$flutter_root/shell/platform/common/cpp/client_wrapper:client_wrapper_library_stubs", "$flutter_root/testing", diff --git a/testing/build/gen_fixtures_location_symbol.py b/testing/build/gen_fixtures_location_symbol.py deleted file mode 100644 index 01f41d2818759..0000000000000 --- a/testing/build/gen_fixtures_location_symbol.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# 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. - -import argparse -import subprocess -import sys -import os - - -def main(): - parser = argparse.ArgumentParser( - description='Create the symbol specifying the location of test fixtures.') - - parser.add_argument('--fixtures_location_file', type=str, required=True) - parser.add_argument('--fixtures_location', type=str, required=True) - - args = parser.parse_args() - - with open(args.fixtures_location_file, 'w') as file: - file.write('namespace flutter {namespace testing {const char* GetFixturesPath() {return "%s";}}}' - % args.fixtures_location) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/testing/testing.gni b/testing/testing.gni index 1488a77782725..2356f45bfa7de 100644 --- a/testing/testing.gni +++ b/testing/testing.gni @@ -6,153 +6,259 @@ import("//build/compiled_action.gni") import("//third_party/dart/build/dart/dart_action.gni") import("$flutter_root/common/config.gni") -# Builds test fixtures for a unit test. -# -# Generates a directory structure containing an assets directory and the Dart -# code to execute compiled to kernel. Generates: -# * an asserts directory at `$target_name/assets`. -# * a C++ implementation for `flutter/testing/testing.h`, defining -# `testing::GetFixturesPath()`, which returns the assets path. -# * a kernel snapshot at `$target_name/assets/$kernel_out`. +is_aot_test = + flutter_runtime_mode == "profile" || flutter_runtime_mode == "release" + +# Creates a translation unit that defines the flutter::testing::GetFixturesPath +# method that tests can use to locate their fixtures. # -# Rule attributes: -# * fixtures: list of Dart files, including a main entrypoint. -# * kernel_out: the output path, relative to the assets directory, of the -# generated kernel snapshot. By default, `kernel_blob.bin`. -template("test_fixtures") { +# Arguments +# assets_dir (required): The assets directory +template("fixtures_location") { testonly = true - assert(defined(invoker.fixtures), "Test fixtures must be specified.") - if (flutter_runtime_mode == "profile" || flutter_runtime_mode == "release") { - kernel_out = "kernel_snapshot.dill" - } else { - kernel_out = "kernel_blob.bin" - } - if (defined(invoker.kernel_out)) { - kernel_out = invoker.kernel_out - } - - fixtures_location = "$target_gen_dir/$target_name/assets" - fixtures_location_file = - "$target_gen_dir/$target_name/test_fixtures_location.cc" + assert(defined(invoker.assets_dir), "The assets directory.") - fixtures_name_target_name = target_name + "_gen_fixtures_name" - action(fixtures_name_target_name) { - script = "$flutter_root/testing/build/gen_fixtures_location_symbol.py" + location_path = rebase_path(invoker.assets_dir) + location_source = "namespace flutter {namespace testing {const char* GetFixturesPath() {return \"$location_path\";}}}" + location_source_path = "$target_gen_dir/fixtures_location$target_name.cc" - outputs = [ - fixtures_location_file, - ] + write_file(location_source_path, location_source) - args = [ - "--fixtures_location_file", - rebase_path(fixtures_location_file), - "--fixtures_location", - rebase_path(fixtures_location), + source_set(target_name) { + public = [] + sources = [ + location_source_path, ] } +} - fixtures_source_set_target_name = target_name + "_gen_fixtures_source_set" - source_set(fixtures_source_set_target_name) { +# Generates the Dart kernel snapshot. +# +# Arguments +# dart_main (required): The Main Dart file. +# +# dart_kernel (required): The path to the ouput kernel snapshot in the out +# directory. +template("dart_snapshot_kernel") { + testonly = true + + assert(defined(invoker.dart_main), "The Dart Main file must be specified") + assert(defined(invoker.dart_kernel), + "The Dart Kernel file location must be specified") + + dart_action(target_name) { testonly = true - sources = [ - fixtures_location_file, - ] deps = [ - ":$fixtures_name_target_name", + # This generates the Frontend server snapshot used in this Dart action as + # well as the patched SDK. + "//third_party/dart/utils/kernel-service:frontend_server", ] - } - fixtures_kernel_target_name = target_name + "_kernel" - dart_action(fixtures_kernel_target_name) { - testonly = true + if (is_aot_test) { + deps += [ "$flutter_root/lib/snapshot:strong_platform" ] + } + script = "$root_out_dir/frontend_server.dart.snapshot" - fixture_paths = [] - foreach(fixture, invoker.fixtures) { - fixture_paths += [ rebase_path(fixture) ] - } - inputs = fixture_paths + inputs = [ + invoker.dart_main, + ] + outputs = [ - "$fixtures_location/$kernel_out", + invoker.dart_kernel, ] - deps = [ - "//third_party/dart/utils/kernel-service:frontend_server", + snapshot_depfile = "$target_gen_dir/snapshot_$target_name.depfile.d" + depfile = snapshot_depfile + + args = [ + "--sdk-root", + rebase_path("$root_out_dir/flutter_patched_sdk"), + "--target", + "flutter", + "--output-dill", + rebase_path(invoker.dart_kernel, root_out_dir), + "--depfile", + rebase_path(snapshot_depfile), ] - if (flutter_runtime_mode == "profile" || flutter_runtime_mode == "release") { - args = [ - "--sdk-root", - rebase_path("$root_out_dir/flutter_patched_sdk"), - "--strong", - "--target=flutter", - "--aot", - "--tfa", - "-Ddart.vm.product=true", - "--output-dill", - rebase_path("$fixtures_location/$kernel_out"), - ] + fixture_paths - - deps += [ "//flutter/lib/snapshot:strong_platform" ] - } else { - args = [ - "--sdk-root", - rebase_path("$root_out_dir/flutter_patched_sdk"), - "--target", - "flutter", - "--output-dill", - rebase_path("$fixtures_location/$kernel_out"), - ] + fixture_paths + if (flutter_runtime_mode == "release") { + args += [ "-Ddart.vm.product=true" ] + } + + if (is_aot_test) { + args += [ + "--aot", + + # type flow analysis + "--tfa", + ] } + + args += [ rebase_path(invoker.dart_main) ] } +} - fixtures_aot_target_name = target_name + "_aot" - compiled_action(fixtures_aot_target_name) { +# Generates an AOT snapshot from a kernel snapshot. +# +# Arguments: +# +# dart_kernel (required): The path to the kernel snapshot. +template("dart_snapshot_aot") { + testonly = true + + assert(defined(invoker.dart_kernel), + "The Dart Kernel file location must be specified") + + compiled_action(target_name) { testonly = true + tool = "//third_party/dart/runtime/bin:gen_snapshot" inputs = [ - "$fixtures_location/$kernel_out", + invoker.dart_kernel, ] + vm_snapshot_data = "$target_gen_dir/assets/vm_snapshot_data" + vm_snapshot_instr = "$target_gen_dir/assets/vm_snapshot_instr" + isolate_snapshot_data = "$target_gen_dir/assets/isolate_snapshot_data" + isolate_snapshot_instr = "$target_gen_dir/assets/isolate_snapshot_instr" + outputs = [ - "$fixtures_location/vm_snapshot_data", - "$fixtures_location/vm_snapshot_instr", - "$fixtures_location/isolate_snapshot_data", - "$fixtures_location/isolate_snapshot_instr", + vm_snapshot_data, + vm_snapshot_instr, + isolate_snapshot_data, + isolate_snapshot_instr, ] args = [ "--causal_async_stacks", "--deterministic", "--snapshot_kind=app-aot-blobs", - "--vm_snapshot_data=" + - rebase_path("$fixtures_location/vm_snapshot_data"), - "--vm_snapshot_instructions=" + - rebase_path("$fixtures_location/vm_snapshot_instr"), - "--isolate_snapshot_data=" + - rebase_path("$fixtures_location/isolate_snapshot_data"), - "--isolate_snapshot_instructions=" + - rebase_path("$fixtures_location/isolate_snapshot_instr"), - rebase_path("$fixtures_location/$kernel_out"), + "--vm_snapshot_data=" + rebase_path(vm_snapshot_data), + "--vm_snapshot_instructions=" + rebase_path(vm_snapshot_instr), + "--isolate_snapshot_data=" + rebase_path(isolate_snapshot_data), + "--isolate_snapshot_instructions=" + rebase_path(isolate_snapshot_instr), + rebase_path(invoker.dart_kernel), ] - deps = [ - ":$fixtures_kernel_target_name", - ] + forward_variables_from(invoker, [ "deps" ]) + } +} + +# Generates a kernel or AOT snapshot as necessary from the main Dart file. +# Other Dart dependencies referenced by that main Dart file will be tracked. +# +# Arguments: +# +# dart_main (required): The path to the main Dart file. +template("dart_snapshot") { + assert(defined(invoker.dart_main), "The main Dart file must be specified.") + + testonly = true + + dart_snapshot_kernel_target_name = "dart_snapshot_kernel_$target_name" + dart_snapshot_kernel_path = "$target_gen_dir/assets/kernel_blob.bin" + dart_snapshot_kernel(dart_snapshot_kernel_target_name) { + dart_main = invoker.dart_main + dart_kernel = dart_snapshot_kernel_path + } + + snapshot_deps = [ ":$dart_snapshot_kernel_target_name" ] + + if (is_aot_test) { + dart_snapshot_aot_target_name = "dart_snapshot_aot_$target_name" + dart_snapshot_aot(dart_snapshot_aot_target_name) { + dart_kernel = dart_snapshot_kernel_path + deps = [ + ":$dart_snapshot_kernel_target_name", + ] + } + snapshot_deps += [ ":$dart_snapshot_aot_target_name" ] } group(target_name) { testonly = true - deps = [ - ":$fixtures_source_set_target_name", - ] - if (flutter_runtime_mode == "profile" || flutter_runtime_mode == "release") { - deps += [ ":$fixtures_aot_target_name" ] - } else { - deps += [ ":$fixtures_kernel_target_name" ] + + deps = snapshot_deps + } +} + +# Copies a (potentially empty) list of fixtures to the fixtures directory for +# the unit test. +# +# Arguments: +# +# fixtures (required): The list of fixtures to copy. +template("copy_fixtures") { + testonly = true + + assert(defined(invoker.fixtures), "The test fixtures must be specified.") + + has_fixtures = false + foreach(fixture, invoker.fixtures) { + has_fixtures = true + } + + if (has_fixtures) { + copy(target_name) { + sources = invoker.fixtures + outputs = [ + "$target_gen_dir/assets/{{source_file_part}}", + ] + } + } else { + group(target_name) { + # The copy target cannot accept an empty list. + } + } +} + +# Specifies the fixtures to copy to a location known by the specific unit test. +# Test executable can only depend on one such target. You can use either one of +# both arguments to expand this template. If you have none, then you'll see the +# unused invoker scope error. In such cases specify the fixtures using an empty +# array. +# +# Arguments: +# +# fixtures (optional): The list of test fixtures. An empty list may be +# specified. +# +# dart_main (optional): The path to the main Dart file. If specified, it is +# snapshotted. +template("test_fixtures") { + # Even if no fixtures are present, the location of the fixtures directory + # must always be known to tests. + fixtures_location_target_name = "fixtures_location_$target_name" + fixtures_location(fixtures_location_target_name) { + assets_dir = "$target_gen_dir/assets" + } + test_deps = [ ":$fixtures_location_target_name" ] + + # If the fixtures are specified, copy them to the assets directory. + if (defined(invoker.fixtures)) { + copy_fixtures_target_name = "copy_fixtures_$target_name" + copy_fixtures(copy_fixtures_target_name) { + fixtures = invoker.fixtures } + test_deps += [ ":$copy_fixtures_target_name" ] + } + + # If a Dart file is specified, snapshot it and place it in the generated + # assets directory. + if (defined(invoker.dart_main)) { + dart_snapshot_target_name = "dart_snapshot_$target_name" + dart_snapshot(dart_snapshot_target_name) { + dart_main = invoker.dart_main + } + test_deps += [ ":$dart_snapshot_target_name" ] + } + + group(target_name) { + testonly = true + deps = test_deps } }