chromium/build/rust/rust_unit_test.gni

# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//build/config/rust.gni")
import("//build/rust/rust_unit_tests_group.gni")

# Defines a Rust unit test.
#
# This generates an executable + a script that can be run on Chromium bots.
# Future iterations of this template may do something smarter with the test
# code in order to automatically contribute it to test steps on the bots.
#
# Parameters
#
#   sources
#   edition (optional)
#   allow_unsafe (optional)
#   configs (optional)
#   deps (optional)
#   crate_root (optional)
#   features (optional)
#   rustflags (optional)
#   inputs (optional)
#     All as in rust_static_library.
#
# Example of usage:
#
#   rust_unit_test("foo_tests") {
#     deps = [
#       "//third_party/rust/test_utils/v1:lib",
#     ]
#     sources = [ "src/lib.rs" ]
#   }
#
# Implementation note: you might assume it makes sense to implement this
# in terms of rust_target in order to avoid the duplication of logic around
# features and editions. We don't do that because rust_target actually
# depends on this template in order to build embedded unit tests
# (and therefore depending on rust_target here would lead to an infinite
# import loop).

template("rust_unit_test") {
  assert(can_build_rust_unit_tests)
  if (defined(invoker.crate_name)) {
    _crate_name = invoker.crate_name
  } else {
    _crate_name = target_name
  }
  if (defined(invoker.crate_root)) {
    _crate_root = invoker.crate_root
  } else {
    _crate_root = "src/lib.rs"
  }
  _rustflags = invoker.rustflags
  if (defined(invoker.features)) {
    foreach(i, invoker.features) {
      _rustflags += [ "--cfg=feature=\"${i}\"" ]
    }
  }
  _configs = invoker.configs
  _edition = "2021"
  if (defined(invoker.edition)) {
    _edition = invoker.edition
  }
  _configs += [ "//build/rust:edition_${_edition}" ]

  # We require that all source files are listed, even though this is
  # not a requirement for rustc. The reason is to ensure that tools
  # such as `gn deps` give the correct answer, and thus we trigger
  # the right test suites etc. on code change.
  # TODO(crbug.com/40200431) - verify this is correct
  assert(defined(invoker.sources), "sources must be listed")

  _exe_target_name = target_name + "_exe"
  rust_unit_tests_group(target_name) {
    deps = [ ":$_exe_target_name" ]
  }

  # The OUT_DIR for a crate's tests should point to the same OUT_DIR that the
  # library it's testing used. The `env_out_dir` variable can be used to specify
  # that directory.
  if (defined(invoker.env_out_dir)) {
    _env_out_dir = invoker.env_out_dir
  } else {
    _env_out_dir = target_gen_dir
  }

  executable(_exe_target_name) {
    testonly = true
    forward_variables_from(invoker,
                           "*",
                           [
                             "allow_unsafe",
                             "edition",
                             "features",
                             "rustflags",
                             "configs",
                             "crate_name",
                             "crate_root",
                             "env_out_dir",
                           ])
    if (!defined(output_name) || output_name == "") {
      output_name = _crate_name
    }

    rustflags = [
      "--cfg",
      "feature=\"test\"",
      "--test",
    ]
    rustflags += _rustflags
    configs = []
    configs = _configs
    crate_name = _crate_name
    crate_root = _crate_root
    if (!defined(rustenv)) {
      rustenv = []
    }

    rustenv += [ "OUT_DIR=" +
                 rebase_path(_env_out_dir, get_path_info(_crate_root, "dir")) ]
    metadata = {
      # Consumed by "rust_unit_tests_group" gni template.
      rust_unit_test_executables = [ _crate_name ]
    }

    # Duplicated from rust_target since we didn't use the rust_executable
    # template as it causes a GN cycle.
    if (!defined(deps)) {
      deps = []
    }
    if (!defined(invoker.no_chromium_prelude) || !invoker.no_chromium_prelude) {
      if (enable_chromium_prelude) {
        deps += [ "//build/rust/chromium_prelude" ]
      }
    }
  }
}

set_defaults("rust_unit_test") {
  configs = default_executable_configs
  deps = []
  rustflags = []
}