blob: 3a771afde58e134d81593284f767fab3045fdcd9 [file] [log] [blame]
# Copyright 2025 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for attr_builders."""
load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
load("@rules_testing//lib:test_suite.bzl", "test_suite")
load("@rules_testing//lib:truth.bzl", "truth")
load("//python/private:attr_builders.bzl", "attrb") # buildifier: disable=bzl-visibility
load("//python/private:common_labels.bzl", "labels") # buildifier: disable=bzl-visibility
def _expect_cfg_defaults(expect, cfg):
expect.where(expr = "cfg.outputs").that_collection(cfg.outputs()).contains_exactly([])
expect.where(expr = "cfg.inputs").that_collection(cfg.inputs()).contains_exactly([])
expect.where(expr = "cfg.implementation").that_bool(cfg.implementation()).equals(None)
expect.where(expr = "cfg.target").that_bool(cfg.target()).equals(True)
expect.where(expr = "cfg.exec_group").that_str(cfg.exec_group()).equals(None)
expect.where(expr = "cfg.which_cfg").that_str(cfg.which_cfg()).equals("target")
_some_aspect = aspect(implementation = lambda target, ctx: None)
_SomeInfo = provider("MyInfo", fields = [])
_tests = []
def _report_failures(name, env):
failures = env.failures
def _report_failures_impl(env, target):
_ = target # @unused
env._failures.extend(failures)
analysis_test(
name = name,
target = labels.NONE,
impl = _report_failures_impl,
)
# Calling attr.xxx() outside of the loading phase is an error, but rules_testing
# creates the expect/truth helpers during the analysis phase. To make the truth
# helpers available during the loading phase, fake out the ctx just enough to
# satify rules_testing.
def _loading_phase_expect(test_name):
env = struct(
ctx = struct(
workspace_name = "bogus",
label = Label(test_name),
attr = struct(
_impl_name = test_name,
),
),
failures = [],
)
return env, truth.expect(env)
def _expect_builds(expect, builder, attribute_type):
expect.that_str(str(builder.build())).contains(attribute_type)
def _test_cfg_arg(name):
env, _ = _loading_phase_expect(name)
def build_cfg(cfg):
attrb.Label(cfg = cfg).build()
build_cfg(None)
build_cfg("target")
build_cfg("exec")
build_cfg(dict(exec_group = "eg"))
build_cfg(dict(implementation = (lambda settings, attr: None)))
build_cfg(config.exec())
build_cfg(transition(
implementation = (lambda settings, attr: None),
inputs = [],
outputs = [],
))
# config.target is Bazel 8+
if hasattr(config, "target"):
build_cfg(config.target())
# config.none is Bazel 8+
if hasattr(config, "none"):
build_cfg("none")
build_cfg(config.none())
_report_failures(name, env)
_tests.append(_test_cfg_arg)
def _test_bool(name):
env, expect = _loading_phase_expect(name)
subject = attrb.Bool()
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.default()).equals(False)
expect.that_bool(subject.mandatory()).equals(False)
_expect_builds(expect, subject, "attr.bool")
subject.set_default(True)
subject.set_mandatory(True)
subject.set_doc("doc")
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.default()).equals(True)
expect.that_bool(subject.mandatory()).equals(True)
_expect_builds(expect, subject, "attr.bool")
_report_failures(name, env)
_tests.append(_test_bool)
def _test_int(name):
env, expect = _loading_phase_expect(name)
subject = attrb.Int()
expect.that_int(subject.default()).equals(0)
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_collection(subject.values()).contains_exactly([])
_expect_builds(expect, subject, "attr.int")
subject.set_default(42)
subject.set_doc("doc")
subject.set_mandatory(True)
subject.values().append(42)
expect.that_int(subject.default()).equals(42)
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_collection(subject.values()).contains_exactly([42])
_expect_builds(expect, subject, "attr.int")
_report_failures(name, env)
_tests.append(_test_int)
def _test_int_list(name):
env, expect = _loading_phase_expect(name)
subject = attrb.IntList()
expect.that_bool(subject.allow_empty()).equals(True)
expect.that_collection(subject.default()).contains_exactly([])
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
_expect_builds(expect, subject, "attr.int_list")
subject.default().append(99)
subject.set_doc("doc")
subject.set_mandatory(True)
expect.that_collection(subject.default()).contains_exactly([99])
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
_expect_builds(expect, subject, "attr.int_list")
_report_failures(name, env)
_tests.append(_test_int_list)
def _test_label(name):
env, expect = _loading_phase_expect(name)
subject = attrb.Label()
expect.that_str(subject.default()).equals(None)
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.executable()).equals(False)
expect.that_bool(subject.allow_files()).equals(None)
expect.that_bool(subject.allow_single_file()).equals(None)
expect.that_collection(subject.providers()).contains_exactly([])
expect.that_collection(subject.aspects()).contains_exactly([])
_expect_cfg_defaults(expect, subject.cfg)
_expect_builds(expect, subject, "attr.label")
subject.set_default("//foo:bar")
subject.set_doc("doc")
subject.set_mandatory(True)
subject.set_executable(True)
subject.add_allow_files(".txt")
subject.cfg.set_target()
subject.providers().append(_SomeInfo)
subject.aspects().append(_some_aspect)
subject.cfg.outputs().append(Label("//some:output"))
subject.cfg.inputs().append(Label("//some:input"))
impl = lambda: None
subject.cfg.set_implementation(impl)
expect.that_str(subject.default()).equals("//foo:bar")
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_bool(subject.executable()).equals(True)
expect.that_collection(subject.allow_files()).contains_exactly([".txt"])
expect.that_bool(subject.allow_single_file()).equals(None)
expect.that_collection(subject.providers()).contains_exactly([_SomeInfo])
expect.that_collection(subject.aspects()).contains_exactly([_some_aspect])
expect.that_collection(subject.cfg.outputs()).contains_exactly([Label("//some:output")])
expect.that_collection(subject.cfg.inputs()).contains_exactly([Label("//some:input")])
expect.that_bool(subject.cfg.implementation()).equals(impl)
_expect_builds(expect, subject, "attr.label")
_report_failures(name, env)
_tests.append(_test_label)
def _test_label_keyed_string_dict(name):
env, expect = _loading_phase_expect(name)
subject = attrb.LabelKeyedStringDict()
expect.that_dict(subject.default()).contains_exactly({})
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.allow_files()).equals(False)
expect.that_collection(subject.providers()).contains_exactly([])
expect.that_collection(subject.aspects()).contains_exactly([])
_expect_cfg_defaults(expect, subject.cfg)
_expect_builds(expect, subject, "attr.label_keyed_string_dict")
subject.default()["key"] = "//some:label"
subject.set_doc("doc")
subject.set_mandatory(True)
subject.set_allow_files(True)
subject.cfg.set_target()
subject.providers().append(_SomeInfo)
subject.aspects().append(_some_aspect)
subject.cfg.outputs().append("//some:output")
subject.cfg.inputs().append("//some:input")
impl = lambda: None
subject.cfg.set_implementation(impl)
expect.that_dict(subject.default()).contains_exactly({"key": "//some:label"})
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_bool(subject.allow_files()).equals(True)
expect.that_collection(subject.providers()).contains_exactly([_SomeInfo])
expect.that_collection(subject.aspects()).contains_exactly([_some_aspect])
expect.that_collection(subject.cfg.outputs()).contains_exactly(["//some:output"])
expect.that_collection(subject.cfg.inputs()).contains_exactly(["//some:input"])
expect.that_bool(subject.cfg.implementation()).equals(impl)
_expect_builds(expect, subject, "attr.label_keyed_string_dict")
subject.add_allow_files(".txt")
expect.that_collection(subject.allow_files()).contains_exactly([".txt"])
_expect_builds(expect, subject, "attr.label_keyed_string_dict")
_report_failures(name, env)
_tests.append(_test_label_keyed_string_dict)
def _test_label_list(name):
env, expect = _loading_phase_expect(name)
subject = attrb.LabelList()
expect.that_collection(subject.default()).contains_exactly([])
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.allow_files()).equals(False)
expect.that_collection(subject.providers()).contains_exactly([])
expect.that_collection(subject.aspects()).contains_exactly([])
_expect_cfg_defaults(expect, subject.cfg)
_expect_builds(expect, subject, "attr.label_list")
subject.default().append("//some:label")
subject.set_doc("doc")
subject.set_mandatory(True)
subject.set_allow_files([".txt"])
subject.providers().append(_SomeInfo)
subject.aspects().append(_some_aspect)
expect.that_collection(subject.default()).contains_exactly(["//some:label"])
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_collection(subject.allow_files()).contains_exactly([".txt"])
expect.that_collection(subject.providers()).contains_exactly([_SomeInfo])
expect.that_collection(subject.aspects()).contains_exactly([_some_aspect])
_expect_builds(expect, subject, "attr.label_list")
_report_failures(name, env)
_tests.append(_test_label_list)
def _test_output(name):
env, expect = _loading_phase_expect(name)
subject = attrb.Output()
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
_expect_builds(expect, subject, "attr.output")
subject.set_doc("doc")
subject.set_mandatory(True)
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
_expect_builds(expect, subject, "attr.output")
_report_failures(name, env)
_tests.append(_test_output)
def _test_output_list(name):
env, expect = _loading_phase_expect(name)
subject = attrb.OutputList()
expect.that_bool(subject.allow_empty()).equals(True)
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
_expect_builds(expect, subject, "attr.output_list")
subject.set_allow_empty(False)
subject.set_doc("doc")
subject.set_mandatory(True)
expect.that_bool(subject.allow_empty()).equals(False)
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
_expect_builds(expect, subject, "attr.output_list")
_report_failures(name, env)
_tests.append(_test_output_list)
def _test_string(name):
env, expect = _loading_phase_expect(name)
subject = attrb.String()
expect.that_str(subject.default()).equals("")
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_collection(subject.values()).contains_exactly([])
_expect_builds(expect, subject, "attr.string")
subject.set_doc("doc")
subject.set_mandatory(True)
subject.values().append("green")
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_collection(subject.values()).contains_exactly(["green"])
_expect_builds(expect, subject, "attr.string")
_report_failures(name, env)
_tests.append(_test_string)
def _test_string_dict(name):
env, expect = _loading_phase_expect(name)
subject = attrb.StringDict()
expect.that_dict(subject.default()).contains_exactly({})
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.allow_empty()).equals(True)
_expect_builds(expect, subject, "attr.string_dict")
subject.default()["key"] = "value"
subject.set_doc("doc")
subject.set_mandatory(True)
subject.set_allow_empty(False)
expect.that_dict(subject.default()).contains_exactly({"key": "value"})
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_bool(subject.allow_empty()).equals(False)
_expect_builds(expect, subject, "attr.string_dict")
_report_failures(name, env)
_tests.append(_test_string_dict)
def _test_string_keyed_label_dict(name):
env, expect = _loading_phase_expect(name)
subject = attrb.StringKeyedLabelDict()
expect.that_dict(subject.default()).contains_exactly({})
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.allow_files()).equals(False)
expect.that_collection(subject.providers()).contains_exactly([])
expect.that_collection(subject.aspects()).contains_exactly([])
_expect_cfg_defaults(expect, subject.cfg)
_expect_builds(expect, subject, "attr.string_keyed_label_dict")
subject.default()["key"] = "//some:label"
subject.set_doc("doc")
subject.set_mandatory(True)
subject.set_allow_files([".txt"])
subject.providers().append(_SomeInfo)
subject.aspects().append(_some_aspect)
expect.that_dict(subject.default()).contains_exactly({"key": "//some:label"})
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_collection(subject.allow_files()).contains_exactly([".txt"])
expect.that_collection(subject.providers()).contains_exactly([_SomeInfo])
expect.that_collection(subject.aspects()).contains_exactly([_some_aspect])
_expect_builds(expect, subject, "attr.string_keyed_label_dict")
_report_failures(name, env)
_tests.append(_test_string_keyed_label_dict)
def _test_string_list(name):
env, expect = _loading_phase_expect(name)
subject = attrb.StringList()
expect.that_collection(subject.default()).contains_exactly([])
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.allow_empty()).equals(True)
_expect_builds(expect, subject, "attr.string_list")
subject.set_doc("doc")
subject.set_mandatory(True)
subject.default().append("blue")
subject.set_allow_empty(False)
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_bool(subject.allow_empty()).equals(False)
expect.that_collection(subject.default()).contains_exactly(["blue"])
_expect_builds(expect, subject, "attr.string_list")
_report_failures(name, env)
_tests.append(_test_string_list)
def _test_string_list_dict(name):
env, expect = _loading_phase_expect(name)
subject = attrb.StringListDict()
expect.that_dict(subject.default()).contains_exactly({})
expect.that_str(subject.doc()).equals("")
expect.that_bool(subject.mandatory()).equals(False)
expect.that_bool(subject.allow_empty()).equals(True)
_expect_builds(expect, subject, "attr.string_list_dict")
subject.set_doc("doc")
subject.set_mandatory(True)
subject.default()["key"] = ["red"]
subject.set_allow_empty(False)
expect.that_str(subject.doc()).equals("doc")
expect.that_bool(subject.mandatory()).equals(True)
expect.that_bool(subject.allow_empty()).equals(False)
expect.that_dict(subject.default()).contains_exactly({"key": ["red"]})
_expect_builds(expect, subject, "attr.string_list_dict")
_report_failures(name, env)
_tests.append(_test_string_list_dict)
def attr_builders_test_suite(name):
test_suite(
name = name,
tests = _tests,
)