# Copyright 2019 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. """Unit tests for unittest.bzl.""" load("//lib:partial.bzl", "partial") load("//lib:unittest.bzl", "analysistest", "asserts", "loadingtest", "unittest") ################################### ####### basic_failing_test ######## ################################### def _basic_failing_test(ctx): """Unit tests for a basic library verification test that fails.""" env = unittest.begin(ctx) asserts.equals(env, 1, 2) return unittest.end(env) basic_failing_test = unittest.make(_basic_failing_test) ################################### ####### failure_message_test ###### ################################### def _failure_message_test(ctx): """Failing unit test with arbitrary content in the message.""" env = unittest.begin(ctx) if not ctx.attr.message: unittest.fail(env, "Message must be non-empty.") asserts.equals(env, "", ctx.attr.message) return unittest.end(env) failure_message_test = unittest.make( _failure_message_test, attrs = { "message": attr.string(), }, ) ################################### ####### basic_passing_test ######## ################################### def _basic_passing_test(ctx): """Unit tests for a basic library verification test.""" env = unittest.begin(ctx) asserts.equals(env, 1, 1) return unittest.end(env) basic_passing_test = unittest.make(_basic_passing_test) ################################################# ####### basic_passing_short_timeout_test ######## ################################################# def _basic_passing_short_timeout_test(ctx): """Unit tests for a basic library verification test.""" env = unittest.begin(ctx) asserts.equals(env, ctx.attr.timeout, "short") return unittest.end(env) basic_passing_short_timeout_test = unittest.make(_basic_passing_short_timeout_test) ################################### ####### change_setting_test ####### ################################### def _change_setting_test(ctx): """Test to verify that an analysis test may change configuration.""" env = analysistest.begin(ctx) 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) _ChangeSettingInfo = provider( doc = "min_os_version for change_setting_test", fields = ["min_os_version"], ) def _change_setting_fake_rule(ctx): return [_ChangeSettingInfo(min_os_version = ctx.fragments.cpp.minimum_os_version())] change_setting_fake_rule = rule( implementation = _change_setting_fake_rule, fragments = ["cpp"], ) change_setting_test = analysistest.make( _change_setting_test, config_settings = { "//command_line_option:minimum_os_version": "1234.5678", }, ) #################################### ####### failure_testing_test ####### #################################### def _failure_testing_test(ctx): """Test to verify that an analysis test may verify a rule fails with fail().""" env = analysistest.begin(ctx) asserts.expect_failure(env, "This rule should never work") return analysistest.end(env) def _failure_testing_fake_rule(ctx): _ignore = [ctx] # @unused fail("This rule should never work") failure_testing_fake_rule = rule( implementation = _failure_testing_fake_rule, ) failure_testing_test = analysistest.make( _failure_testing_test, expect_failure = True, ) ############################################ ####### fail_unexpected_passing_test ####### ############################################ def _fail_unexpected_passing_test(ctx): """Test that fails by expecting an error that never occurs.""" env = analysistest.begin(ctx) asserts.expect_failure(env, "Oh no, going to fail") return analysistest.end(env) def _fail_unexpected_passing_fake_rule(ctx): _ignore = [ctx] # @unused return [] fail_unexpected_passing_fake_rule = rule( implementation = _fail_unexpected_passing_fake_rule, ) fail_unexpected_passing_test = analysistest.make( _fail_unexpected_passing_test, expect_failure = True, ) ################################################ ####### change_setting_with_failure_test ####### ################################################ def _change_setting_with_failure_test(ctx): """Test verifying failure while changing configuration.""" env = analysistest.begin(ctx) asserts.expect_failure(env, "unexpected minimum_os_version!!!") return analysistest.end(env) def _change_setting_with_failure_fake_rule(ctx): if ctx.fragments.cpp.minimum_os_version() == "error_error": fail("unexpected minimum_os_version!!!") return [] change_setting_with_failure_fake_rule = rule( implementation = _change_setting_with_failure_fake_rule, fragments = ["cpp"], ) change_setting_with_failure_test = analysistest.make( _change_setting_with_failure_test, expect_failure = True, config_settings = { "//command_line_option:minimum_os_version": "error_error", }, ) #################################### ####### 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, ) #################################### ####### inspect_aspect_test ####### #################################### _AddedByAspectInfo = provider( doc = "Example provider added by example aspect", fields = { "value": "(str)", }, ) def _example_aspect_impl(target, ctx): _ignore = [target, ctx] # @unused return [ _AddedByAspectInfo(value = "attached by aspect"), ] example_aspect = aspect( implementation = _example_aspect_impl, ) def _inspect_aspect_test(ctx): """Test verifying aspect run on a target.""" env = analysistest.begin(ctx) tut = env.ctx.attr.target_under_test asserts.equals(env, "attached by aspect", tut[_AddedByAspectInfo].value) return analysistest.end(env) def _inspect_aspect_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_aspect_fake_rule = rule( implementation = _inspect_aspect_fake_rule, ) inspect_aspect_test = analysistest.make( _inspect_aspect_test, extra_target_under_test_aspects = [example_aspect], ) ######################################## ####### inspect_output_dirs_test ####### ######################################## _OutputDirInfo = provider( doc = "bin_path for inspect_output_dirs_test", fields = ["bin_path"], ) def _inspect_output_dirs_test(ctx): """Test verifying output directories used by a test.""" env = analysistest.begin(ctx) # Assert that the output bin dir observed by the aspect added by analysistest # is the same as those observed by the rule directly, even when that's # under a config transition and therefore not the same as the bin dir # used by the test rule. bin_path = analysistest.target_bin_dir_path(env) target_under_test = analysistest.target_under_test(env) asserts.false(env, not bin_path, "bin dir path not found.") asserts.false( env, bin_path == ctx.bin_dir.path, "test bin dir (%s) expected to differ with target_under_test bin dir (%s)." % (bin_path, ctx.bin_dir.path), ) asserts.equals(env, bin_path, target_under_test[_OutputDirInfo].bin_path) return analysistest.end(env) def _inspect_output_dirs_fake_rule(ctx): return [ _OutputDirInfo( bin_path = ctx.bin_dir.path, ), ] inspect_output_dirs_fake_rule = rule( implementation = _inspect_output_dirs_fake_rule, ) inspect_output_dirs_test = analysistest.make( _inspect_output_dirs_test, # The output directories differ between the test and target under test when # the target under test is under a config transition. config_settings = { "//command_line_option:minimum_os_version": "1234.5678", }, ) def _loading_phase_test(env): loadingtest.equals(env, "self_glob", ["unittest_tests.bzl"], native.glob(["unittest_tests.bzl"])) # now use our own calls to assert we created a test case rule and test_suite for it. loadingtest.equals(env, "test_exists", True, native.existing_rule(env.name + "_self_glob") != None) loadingtest.equals(env, "suite_exists", True, native.existing_rule(env.name + "_tests") != None) ######################################### # buildifier: disable=unnamed-macro def unittest_passing_tests_suite(): """Creates the test targets and test suite for passing unittest.bzl tests. Not all tests are included. Some unittest.bzl tests verify a test fails when assertions are not met. Such tests must be run in an e2e shell test. This suite only includes tests which verify success tests. """ unittest.suite( "unittest_tests", basic_passing_test, partial.make(basic_passing_short_timeout_test, timeout = "short"), ) change_setting_test( name = "change_setting_test", target_under_test = ":change_setting_fake_target", ) change_setting_fake_rule( name = "change_setting_fake_target", tags = ["manual"], ) failure_testing_test( name = "failure_testing_test", target_under_test = ":failure_testing_fake_target", ) failure_testing_fake_rule( name = "failure_testing_fake_target", tags = ["manual"], ) change_setting_with_failure_test( name = "change_setting_with_failure_test", target_under_test = ":change_setting_with_failure_fake_target", ) change_setting_with_failure_fake_rule( 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"], ) inspect_aspect_test( name = "inspect_aspect_test", target_under_test = ":inspect_aspect_fake_target", ) inspect_aspect_fake_rule( name = "inspect_aspect_fake_target", tags = ["manual"], ) inspect_output_dirs_test( name = "inspect_output_dirs_test", target_under_test = ":inspect_output_dirs_fake_target", ) inspect_output_dirs_fake_rule( name = "inspect_output_dirs_fake_target", tags = ["manual"], ) loading_env = loadingtest.make("selftest") _loading_phase_test(loading_env)