Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions lib/types.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ _an_int_type = type(1)
_a_depset_type = type(depset())
_a_struct_type = type(struct())

# Unique types that do not have a load-phase type but can still be evaluated
# within the analysis phase. While not perfect, these do centralize the ability
# to express a type and provide a stable test against those types since these
# type strings must be defined at load-time.
_a_file_type = "File"
_a_target_type = "Target"
_a_label_type = "Label"

def _a_function():
pass

Expand Down Expand Up @@ -138,6 +146,39 @@ def _is_set(v):
"""
return type(v) == _a_struct_type and hasattr(v, "_values") and _is_dict(v._values)

def _is_file(v):
"""Returns True if v is a "File" type.

Args:
v: The value whose type should be checked.

Returns:
True if v is a File.
"""
return type(v) == _a_file_type

def _is_target(v):
"""Returns True if v is a "Target" type.

Args:
v: The value whose type should be checked.

Returns:
True if v is a Target.
"""
return type(v) == _a_target_type

def _is_label(v):
"""Returns True if v is a "Label" type.

Args:
v: The value whose type should be checked.

Returns:
True if v is a Label.
"""
return type(v) == _a_label_type

types = struct(
is_list = _is_list,
is_string = _is_string,
Expand All @@ -149,4 +190,7 @@ types = struct(
is_function = _is_function,
is_depset = _is_depset,
is_set = _is_set,
is_file = _is_file,
is_target = _is_target,
is_label = _is_label,
)
91 changes: 91 additions & 0 deletions tests/types_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ load("//lib:new_sets.bzl", "sets")
load("//lib:types.bzl", "types")
load("//lib:unittest.bzl", "asserts", "unittest")

# A placeholder target for unit tests that need a target.
_target_test_hollow_target = "types_test_hollow_target"

def _a_function():
"""A dummy function for testing."""
pass
Expand Down Expand Up @@ -231,7 +234,92 @@ def _is_set_test(ctx):

is_set_test = unittest.make(_is_set_test)

def _make_test_file(ctx):
"""Makes a file object in the analysis phase.

Declaring a file for the sake of analysis but we never actually need to
provide the file through an output group or DefaultInfo.
"""
test_file = ctx.actions.declare_file(ctx.label.name + "_test_file")
ctx.actions.write(
output = test_file,
content = "test_file",
)

return test_file

def _is_file_test(ctx):
"""Unit test for types.is_file."""
env = unittest.begin(ctx)

# Ensuring a file does indeed match.
asserts.true(env, types.is_file(_make_test_file(ctx)))

asserts.false(env, types.is_file(99))
asserts.false(env, types.is_file(""))
asserts.false(env, types.is_file(set()))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and everywhere below - please remove usage of set() because it requires Bazel 8.x (skylib is supposed to be compatible down to Bazel 7).

asserts.false(env, types.is_file(list()))
asserts.false(env, types.is_file(struct()))

return unittest.end(env)

is_file_test = unittest.make(_is_file_test)

def _is_target_test(ctx):
"""Unit test for types.is_target."""
env = unittest.begin(ctx)

# Ensuring a target does indeed match.
asserts.true(env, types.is_target(ctx.attr._test_target))

asserts.false(env, types.is_target(_make_test_file(ctx)))
asserts.false(env, types.is_target(99))
asserts.false(env, types.is_target(""))
asserts.false(env, types.is_target(set()))
asserts.false(env, types.is_target(list()))
asserts.false(env, types.is_target(struct()))

return unittest.end(env)

is_target_test = unittest.make(
_is_target_test,
attrs = {
"_test_target": attr.label(
default = _target_test_hollow_target,
),
},
)

def _is_label_test(ctx):
"""Unit test for types.is_label."""
env = unittest.begin(ctx)

asserts.true(env, types.is_label(ctx.label))

# Ensuring a target does not match.
asserts.false(env, types.is_label(ctx.attr._test_target))
asserts.false(env, types.is_target(_make_test_file(ctx)))
asserts.false(env, types.is_target(99))
asserts.false(env, types.is_target(""))
asserts.false(env, types.is_target(set()))
asserts.false(env, types.is_target(list()))
asserts.false(env, types.is_target(struct()))

return unittest.end(env)

is_label_test = unittest.make(
_is_label_test,
attrs = {
"_test_target": attr.label(
default = _target_test_hollow_target,
),
},
)

def types_test_suite():
# Used for target type-testing.
native.filegroup(name = _target_test_hollow_target)

"""Creates the test targets and test suite for types.bzl tests."""
unittest.suite(
"types_tests",
Expand All @@ -245,4 +333,7 @@ def types_test_suite():
is_function_test,
is_depset_test,
is_set_test,
is_file_test,
is_target_test,
is_label_test,
)