diff --git a/lib/BUILD b/lib/BUILD index ee961d5..dd56187 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -70,6 +70,7 @@ bzl_library( deps = [ ":new_sets", ":sets", + ":types", ], ) diff --git a/lib/unittest.bzl b/lib/unittest.bzl index 793955f..de81a4d 100644 --- a/lib/unittest.bzl +++ b/lib/unittest.bzl @@ -21,6 +21,7 @@ assertions used to within tests. load(":new_sets.bzl", new_sets = "sets") load(":sets.bzl", "sets") +load(":types.bzl", "types") # The following function should only be called from WORKSPACE files and workspace macros. def register_unittest_toolchains(): @@ -119,6 +120,16 @@ def _make(impl, attrs = None): toolchains = [TOOLCHAIN_TYPE], ) +_ActionInfo = provider(fields = ["actions"]) + +def _action_retrieving_aspect_impl(target, ctx): + return [_ActionInfo(actions = target.actions)] + +_action_retrieving_aspect = aspect( + attr_aspects = [], + implementation = _action_retrieving_aspect_impl, +) + # TODO(cparsons): Provide more full documentation on analysis testing in README. def _make_analysis_test(impl, expect_failure = False, config_settings = {}): """Creates an analysis test rule from its implementation function. @@ -170,9 +181,16 @@ def _make_analysis_test(impl, expect_failure = False, config_settings = {}): test_transition = analysis_test_transition( settings = changed_settings, ) - attrs["target_under_test"] = attr.label(cfg = test_transition, mandatory = True) + attrs["target_under_test"] = attr.label( + aspects = [_action_retrieving_aspect], + cfg = test_transition, + mandatory = True, + ) else: - attrs["target_under_test"] = attr.label(mandatory = True) + attrs["target_under_test"] = attr.label( + aspects = [_action_retrieving_aspect], + mandatory = True, + ) return rule( impl, @@ -396,10 +414,10 @@ def _expect_failure(env, expected_failure_msg = ""): `expect_failures = True` is specified. Args: - env: The test environment returned by `unittest.begin`. + env: The test environment returned by `analysistest.begin`. expected_failure_msg: The error message to expect as a result of analysis failures. """ - dep = getattr(env.ctx.attr, "target_under_test")[0] + dep = _target_under_test(env) if AnalysisFailureInfo in dep: dep_failure = dep[AnalysisFailureInfo] actual_errors = "" @@ -412,6 +430,31 @@ def _expect_failure(env, expected_failure_msg = ""): else: _fail(env, "Expected failure of target_under_test, but found success") +def _target_actions(env): + """Returns a list of actions registered by the target under test. + + Args: + env: The test environment returned by `analysistest.begin`. + """ + + # Validate? + dep = _target_under_test(env) + return dep[_ActionInfo].actions + +def _target_under_test(env): + """Returns the target under test. + + Args: + env: The test environment returned by `analysistest.begin`. + """ + result = getattr(env.ctx.attr, "target_under_test") + if types.is_list(result): + if result: + return result[0] + else: + fail("test rule does not have a target_under_test") + return result + asserts = struct( expect_failure = _expect_failure, equals = _assert_equals, @@ -434,4 +477,6 @@ analysistest = struct( begin = _begin, end = _end_analysis_test, fail = _fail, + target_actions = _target_actions, + target_under_test = _target_under_test, ) diff --git a/tests/unittest_tests.bzl b/tests/unittest_tests.bzl index 9bdecc6..20fd890 100644 --- a/tests/unittest_tests.bzl +++ b/tests/unittest_tests.bzl @@ -35,7 +35,7 @@ def _change_setting_test(ctx): """Test to verify that an analysis test may change configuration.""" env = analysistest.begin(ctx) - dep_min_os_version = ctx.attr.target_under_test[0][_ChangeSettingInfo].min_os_version + dep_min_os_version = analysistest.target_under_test(env)[_ChangeSettingInfo].min_os_version asserts.equals(env, "1234.5678", dep_min_os_version) return analysistest.end(env) @@ -132,6 +132,35 @@ change_setting_with_failure_test = analysistest.make( }, ) +#################################### +####### inspect_actions_test ####### +#################################### +def _inspect_actions_test(ctx): + """Test verifying actions registered by a target.""" + env = analysistest.begin(ctx) + + actions = analysistest.target_actions(env) + asserts.equals(env, 1, len(actions)) + action_output = actions[0].outputs.to_list()[0] + asserts.equals(env, "out.txt", action_output.basename) + return analysistest.end(env) + +def _inspect_actions_fake_rule(ctx): + out_file = ctx.actions.declare_file("out.txt") + ctx.actions.run_shell( + command = "echo 'hello' > %s" % out_file.basename, + outputs = [out_file], + ) + return [DefaultInfo(files = depset([out_file]))] + +inspect_actions_fake_rule = rule( + implementation = _inspect_actions_fake_rule, +) + +inspect_actions_test = analysistest.make( + _inspect_actions_test, +) + ######################################### def unittest_passing_tests_suite(): @@ -171,3 +200,12 @@ def unittest_passing_tests_suite(): name = "change_setting_with_failure_fake_target", tags = ["manual"], ) + + inspect_actions_test( + name = "inspect_actions_test", + target_under_test = ":inspect_actions_fake_target", + ) + inspect_actions_fake_rule( + name = "inspect_actions_fake_target", + tags = ["manual"], + )