blob: 411b4c37399cb11f45487bfd061bb267e228047a [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Analysis tests for `fx_expectations`, `fx_generated_expectations`, and `preprocess_expectations`."""
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load(
"@fuchsia_rules_common//packages:providers.bzl",
"FuchsiaPackageResourcesInfo",
)
load(
"//build/bazel/rules/components:fx_component.bzl",
"fx_component_manifest",
)
load(
"//build/bazel/rules/testing:defs.bzl",
"analysis_failure_test",
)
load(
"//src/lib/testing/expectation/rules:fx_expectations.bzl",
"fx_expectations",
)
load(
"//src/lib/testing/expectation/rules:fx_generated_expectations.bzl",
"fx_generated_expectations",
)
load(
"//src/lib/testing/expectation/rules:fx_test_component_with_expectations.bzl",
"fx_component_manifest_with_expectations",
)
load(
"//src/lib/testing/expectation/rules:preprocess.bzl",
"FuchsiaExpectationsInfo",
"preprocess_expectations",
)
visibility("private")
def _expectations_provider_test_impl(ctx):
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)
asserts.true(
env,
FuchsiaExpectationsInfo in target,
"Expected FuchsiaExpectationsInfo on target under test.",
)
info = target[FuchsiaExpectationsInfo]
asserts.equals(
env,
ctx.attr.expected_root_short_path,
info.root_file.short_path,
)
actual_default_files = sorted([
f.short_path
for f in target[DefaultInfo].files.to_list()
])
asserts.equals(
env,
[ctx.attr.expected_root_short_path],
actual_default_files,
)
actual_includes = sorted([
f.short_path
for f in info.includes.to_list()
])
asserts.equals(
env,
sorted(ctx.attr.expected_include_short_paths),
actual_includes,
)
if ctx.attr.expected_generated_includes:
actions = analysistest.target_actions(env)
asserts.equals(env, 1, len(actions))
decoded = json.decode(actions[0].content)
expected_actions = [
{"include": inc}
for inc in ctx.attr.expected_generated_includes
]
asserts.equals(env, {"actions": expected_actions}, decoded)
if env.failures:
# Fail during analysis so `bazel build` build-only suites also catch
# regressions.
fail("\n".join(env.failures))
return analysistest.end(env)
_expectations_provider_test = analysistest.make(
_expectations_provider_test_impl,
attrs = {
"expected_root_short_path": attr.string(mandatory = True),
"expected_include_short_paths": attr.string_list(mandatory = True),
"expected_generated_includes": attr.string_list(),
},
)
def _preprocess_expectations_test_impl(ctx):
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)
asserts.true(
env,
FuchsiaPackageResourcesInfo in target,
"Expected FuchsiaPackageResourcesInfo on target under test.",
)
resources = target[FuchsiaPackageResourcesInfo].resources
asserts.equals(env, 1, len(resources))
asserts.equals(env, ctx.attr.expected_dest, resources[0].dest)
actions = [
a
for a in analysistest.target_actions(env)
if a.mnemonic == "PreprocessExpectations"
]
asserts.equals(env, 1, len(actions))
action = actions[0]
argv = action.argv
asserts.true(
env,
"--cases-to-run" in argv,
"Expected `--cases-to-run` in action argv: {}".format(argv),
)
cases_idx = argv.index("--cases-to-run")
asserts.equals(env, ctx.attr.expected_cases_to_run, argv[cases_idx + 1])
input_short_paths = {
f.short_path: True
for f in action.inputs.to_list()
}
for expected_input in ctx.attr.expected_input_short_paths:
asserts.true(
env,
expected_input in input_short_paths,
"Expected `{}` in action inputs, got: {}".format(
expected_input,
sorted(input_short_paths.keys()),
),
)
if env.failures:
fail("\n".join(env.failures))
return analysistest.end(env)
_preprocess_expectations_test = analysistest.make(
_preprocess_expectations_test_impl,
attrs = {
"expected_dest": attr.string(mandatory = True),
"expected_cases_to_run": attr.string(mandatory = True),
"expected_input_short_paths": attr.string_list(mandatory = True),
},
)
def expectation_rules_test_suite(name, visibility = None):
"""Defines analysis tests for the expectation Bazel rules.
Args:
name: Name of the `test_suite` target.
visibility: Visibility of the `test_suite` target.
"""
fx_expectations(
name = "leaf_expectations",
testonly = True,
expectations = "//src/lib/testing/expectation:included_expectations.json5",
tags = ["manual"],
)
_expectations_provider_test(
name = "fx_expectations_leaf_test",
target_under_test = ":leaf_expectations",
expected_root_short_path = "src/lib/testing/expectation/included_expectations.json5",
expected_include_short_paths = [],
)
fx_expectations(
name = "chained_expectations",
testonly = True,
expectations = "//src/lib/testing/expectation:example_expectations.json5",
includes = [
":leaf_expectations",
"//src/lib/testing/expectation:example_expectations_part2.json5",
],
tags = ["manual"],
)
_expectations_provider_test(
name = "fx_expectations_transitive_includes_test",
target_under_test = ":chained_expectations",
expected_root_short_path = "src/lib/testing/expectation/example_expectations.json5",
expected_include_short_paths = [
"src/lib/testing/expectation/example_expectations_part2.json5",
"src/lib/testing/expectation/included_expectations.json5",
],
)
fx_generated_expectations(
name = "sample_generated_expectations",
testonly = True,
includes = [
"//src/lib/testing/expectation:example_expectations_part1.json5",
"//src/lib/testing/expectation:example_expectations_part2.json5",
],
tags = ["manual"],
)
_expectations_provider_test(
name = "fx_generated_expectations_test",
target_under_test = ":sample_generated_expectations",
expected_root_short_path = "src/lib/testing/expectation/rules/tests/sample_generated_expectations.json5",
expected_include_short_paths = [
"src/lib/testing/expectation/default_expectations.json5",
"src/lib/testing/expectation/example_expectations_part1.json5",
"src/lib/testing/expectation/example_expectations_part2.json5",
],
expected_generated_includes = [
"//src/lib/testing/expectation/default_expectations.json5",
"//src/lib/testing/expectation/example_expectations_part1.json5",
"//src/lib/testing/expectation/example_expectations_part2.json5",
],
)
fx_component_manifest_with_expectations(
name = "sample_manifest_with_expectations",
component_name = "custom-component-name",
includes = ["//src/lib/testing/expectation:meta/client.shard"],
manifest = "//src/lib/testing/expectation:meta/test_root.cml",
tags = ["manual"],
)
preprocess_expectations(
name = "preprocess_default_cases",
testonly = True,
compiled_manifest = ":sample_manifest_with_expectations",
expectations = ":sample_generated_expectations",
tags = ["manual"],
)
_preprocess_expectations_test(
name = "preprocess_expectations_default_test",
target_under_test = ":preprocess_default_cases",
expected_dest = "data/tests/expectations/custom-component-name/expectations.json5",
expected_cases_to_run = "All",
expected_input_short_paths = [
"src/lib/testing/expectation/default_expectations.json5",
"src/lib/testing/expectation/example_expectations_part1.json5",
"src/lib/testing/expectation/example_expectations_part2.json5",
"src/lib/testing/expectation/rules/tests/sample_generated_expectations.json5",
],
)
preprocess_expectations(
name = "preprocess_direct_file",
testonly = True,
compiled_manifest = ":sample_manifest_with_expectations",
expectations = "//src/lib/testing/expectation:included_expectations.json5",
tags = ["manual"],
)
_preprocess_expectations_test(
name = "preprocess_expectations_direct_file_test",
target_under_test = ":preprocess_direct_file",
expected_dest = "data/tests/expectations/custom-component-name/expectations.json5",
expected_cases_to_run = "All",
expected_input_short_paths = [
"src/lib/testing/expectation/included_expectations.json5",
],
)
preprocess_expectations(
name = "preprocess_no_err_logs",
testonly = True,
cases_to_run = "NoErrLogs",
compiled_manifest = ":sample_manifest_with_expectations",
expectations = ":chained_expectations",
tags = ["manual"],
)
_preprocess_expectations_test(
name = "preprocess_expectations_no_err_logs_test",
target_under_test = ":preprocess_no_err_logs",
expected_dest = "data/tests/expectations/custom-component-name/expectations.json5",
expected_cases_to_run = "NoErrLogs",
expected_input_short_paths = [
"src/lib/testing/expectation/example_expectations.json5",
"src/lib/testing/expectation/example_expectations_part2.json5",
"src/lib/testing/expectation/included_expectations.json5",
],
)
preprocess_expectations(
name = "preprocess_with_err_logs",
testonly = True,
cases_to_run = "WithErrLogs",
compiled_manifest = ":sample_manifest_with_expectations",
expectations = ":leaf_expectations",
tags = ["manual"],
)
_preprocess_expectations_test(
name = "preprocess_expectations_with_err_logs_test",
target_under_test = ":preprocess_with_err_logs",
expected_dest = "data/tests/expectations/custom-component-name/expectations.json5",
expected_cases_to_run = "WithErrLogs",
expected_input_short_paths = [
"src/lib/testing/expectation/included_expectations.json5",
],
)
fx_component_manifest(
name = "plain_manifest",
testonly = True,
includes = ["//src/lib/testing/expectation:meta/client.shard"],
manifest = "//src/lib/testing/expectation:meta/test_root.cml",
tags = ["manual"],
)
preprocess_expectations(
name = "preprocess_plain_manifest",
testonly = True,
compiled_manifest = ":plain_manifest",
expectations = ":leaf_expectations",
tags = ["manual"],
)
analysis_failure_test(
name = "preprocess_expectations_plain_manifest_failure_test",
expected_message = "was not created by `fx_component_manifest_with_expectations()`",
target_under_test = ":preprocess_plain_manifest",
)
native.test_suite(
name = name,
visibility = visibility,
tests = [
":fx_expectations_leaf_test",
":fx_expectations_transitive_includes_test",
":fx_generated_expectations_test",
":preprocess_expectations_default_test",
":preprocess_expectations_direct_file_test",
":preprocess_expectations_no_err_logs_test",
":preprocess_expectations_plain_manifest_failure_test",
":preprocess_expectations_with_err_logs_test",
],
)