Skip to content

Commit

Permalink
breaks internal tests
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 607261014
  • Loading branch information
A Googler authored and Blaze Rules Copybara committed Feb 15, 2024
1 parent c9abae8 commit 1d2ce3f
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 71 deletions.
5 changes: 0 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@
they have the usual target under test aspects applied. This allows
testing multiple targets in one test with a mixture of configurations.
([#67](https://github.com/bazelbuild/rules_testing/issues/67))
* `analysis_test` now takes the parameter `provider_subject_factories`.
If you want to perform assertions on custom providers, you no longer need
to use the factory parameter each time you want to retrieve the provider.
instead, you now write `analysis_test(..., provider_subject_factories = [
type = FooInfo, name = "FooInfo", factory = FooSubjectFactory])`.

## [0.5.0] - 2023-10-04

Expand Down
21 changes: 3 additions & 18 deletions lib/private/analysis_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:types.bzl", "types")
load("//lib:truth.bzl", "truth")
load("//lib:util.bzl", "recursive_testing_aspect", "testing_aspect")
load("//lib/private:target_subject.bzl", "PROVIDER_SUBJECT_FACTORIES")
load("//lib/private:util.bzl", "get_test_name_from_function")

def _fail(env, msg):
Expand All @@ -38,7 +37,7 @@ def _fail(env, msg):
print(full_msg)
env.failures.append(full_msg)

def _begin_analysis_test(ctx, provider_subject_factories):
def _begin_analysis_test(ctx):
"""Begins a unit test.
This should be the first function called in a unit test implementation
Expand All @@ -49,10 +48,6 @@ def _begin_analysis_test(ctx, provider_subject_factories):
Args:
ctx: The Starlark context. Pass the implementation function's `ctx` argument
in verbatim.
provider_subject_factories: list of ProviderSubjectFactory structs, these are
additional provider factories on top of built in ones.
See analysis_test's provider_subject_factory arg for more details on
the type.
Returns:
An analysis_test "environment" struct. The following fields are public:
Expand Down Expand Up @@ -91,7 +86,6 @@ def _begin_analysis_test(ctx, provider_subject_factories):
truth_env = struct(
ctx = ctx,
fail = lambda msg: _fail(failures_env, msg),
provider_subject_factories = PROVIDER_SUBJECT_FACTORIES + provider_subject_factories,
)
analysis_test_env = struct(
ctx = ctx,
Expand Down Expand Up @@ -132,8 +126,7 @@ def analysis_test(
fragments = [],
config_settings = {},
extra_target_under_test_aspects = [],
collect_actions_recursively = False,
provider_subject_factories = []):
collect_actions_recursively = False):
"""Creates an analysis test from its implementation function.
An analysis test verifies the behavior of a "real" rule target by examining
Expand Down Expand Up @@ -196,7 +189,6 @@ def analysis_test(
analysis test target itself (e.g. common attributes like `tags`,
`target_compatible_with`, or attributes from `attrs`). Note that these
are for the analysis test target itself, not the target under test.
fragments: An optional list of fragment names that can be used to give rules access to
language-specific parts of configuration.
config_settings: A dictionary of configuration settings to change for the target under
Expand All @@ -210,13 +202,6 @@ def analysis_test(
in addition to those set up by default for the test harness itself.
collect_actions_recursively: If true, runs testing_aspect over all attributes, otherwise
it is only applied to the target under test.
provider_subject_factories: Optional list of ProviderSubjectFactory structs,
these are additional provider factories on top of built in ones.
A ProviderSubjectFactory is a struct with the following fields:
* type: A provider object, e.g. the callable FooInfo object
* name: A human-friendly name of the provider (eg. "FooInfo")
* factory: A callable to convert an instance of the provider to a
subject; see TargetSubject.provider()'s factory arg for the signature.
Returns:
(None)
Expand Down Expand Up @@ -305,7 +290,7 @@ def analysis_test(
)

def wrapped_impl(ctx):
env, target = _begin_analysis_test(ctx, provider_subject_factories)
env, target = _begin_analysis_test(ctx)
impl(env, target)
return _end_analysis_test(env)

Expand Down
66 changes: 21 additions & 45 deletions lib/private/target_subject.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def _target_subject_has_provider(self, provider):
if self.meta.has_provider(self.target, provider):
return
self.meta.add_failure(
"expected to have provider: {}".format(_provider_subject_factory(self, provider).name),
"expected to have provider: {}".format(_provider_name(provider)),
"but provider was not found",
)

Expand Down Expand Up @@ -233,30 +233,23 @@ def _target_subject_provider(self, provider_key, factory = None):
the subject for the found provider. Required if the provider key is
not an inherently supported provider. It must have the following
signature: `def factory(value, /, *, meta)`.
Additional types of providers can be pre-registered by using the
`provider_subject_factories` arg of `analysis_test`.
Returns:
A subject wrapper of the provider value.
"""
if factory:
provider_subject_factory = struct(
type = provider_key,
# str(provider_key) just returns "<provider>", which isn't helpful.
# For lack of a better option, just call it unknown
provider_name = "<Unknown provider>",
factory = factory,
)
else:
provider_subject_factory = _provider_subject_factory(self, provider_key)
if not factory:
for key, value in _PROVIDER_SUBJECT_FACTORIES:
if key == provider_key:
factory = value
break

if not provider_subject_factory.factory:
fail("Unsupported provider: {}".format(provider_subject_factory.name))
if not factory:
fail("Unsupported provider: {}".format(provider_key))
info = self.target[provider_key]

return provider_subject_factory.factory(
return factory(
info,
meta = self.meta.derive("provider({})".format(provider_subject_factory.name)),
meta = self.meta.derive("provider({})".format(provider_key)),
)

def _target_subject_action_generating(self, short_path):
Expand Down Expand Up @@ -392,36 +385,19 @@ def _target_subject_attr(self, name, *, factory = None):
meta = self.meta.derive("attr({})".format(name)),
)

def _provider_subject_factory(self, provider):
for provider_subject_factory in self.meta.env.provider_subject_factories:
if provider_subject_factory.type == provider:
return provider_subject_factory

return struct(
type = provider,
name = "<Unknown provider>",
factory = None,
)

# Providers aren't hashable, so we have to use a list of structs.
PROVIDER_SUBJECT_FACTORIES = [
struct(
type = InstrumentedFilesInfo,
name = "InstrumentedFilesInfo",
factory = InstrumentedFilesInfoSubject.new,
),
struct(
type = RunEnvironmentInfo,
name = "RunEnvironmentInfo",
factory = RunEnvironmentInfoSubject.new,
),
struct(
type = testing.ExecutionInfo,
name = "testing.ExecutionInfo",
factory = ExecutionInfoSubject.new,
),
# Providers aren't hashable, so we have to use a list of (key, value)
_PROVIDER_SUBJECT_FACTORIES = [
(InstrumentedFilesInfo, InstrumentedFilesInfoSubject.new),
(RunEnvironmentInfo, RunEnvironmentInfoSubject.new),
(testing.ExecutionInfo, ExecutionInfoSubject.new),
]

def _provider_name(provider):
# This relies on implementation details of how Starlark represents
# providers, and isn't entirely accurate, but works well enough
# for error messages.
return str(provider).split("<function ")[1].split(">")[0]

# We use this name so it shows up nice in docs.
# buildifier: disable=name-conventions
TargetSubject = struct(
Expand Down
3 changes: 0 additions & 3 deletions tests/truth_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,18 @@ _IS_BAZEL_6_OR_HIGHER = (testing.ExecutionInfo == testing.ExecutionInfo)
_suite = []

def _fake_env(env):
provider_subject_factories = env.expect.meta.env.provider_subject_factories
failures = []
env1 = struct(
ctx = env.ctx,
failures = failures,
fail = lambda msg: failures.append(msg), # Silent fail
provider_subject_factories = provider_subject_factories,
)
env2 = struct(
ctx = env.ctx,
failures = failures,
fail = lambda msg: failures.append(msg), # Silent fail
expect = truth.expect(env1),
reset = lambda: failures.clear(),
provider_subject_factories = provider_subject_factories,
)
return env2

Expand Down

0 comments on commit 1d2ce3f

Please sign in to comment.