Add support for 'loading' unit tests, which evaluate a LOADING phase. (#347)
This is a relatively simple addition to unittest that statically creates rules that either explicitly fail or not depending on if the test case is valid during LOADING phase of bazel. The test conditions are evaluated entirely in loading phase, but if we want an actual test to fail rather than just `fail()` killing the build, we can use this to assert state and report test failures.
This commit is contained in:
parent
1e1c324391
commit
7270e3b345
|
@ -352,6 +352,53 @@ Asserts that the given `condition` is true.
|
||||||
| <a id="asserts.true-msg"></a>msg | An optional message that will be printed that describes the failure. If omitted, a default will be used. | <code>"Expected condition to be true, but was false."</code> |
|
| <a id="asserts.true-msg"></a>msg | An optional message that will be printed that describes the failure. If omitted, a default will be used. | <code>"Expected condition to be true, but was false."</code> |
|
||||||
|
|
||||||
|
|
||||||
|
<a id="#loadingtest.make"></a>
|
||||||
|
|
||||||
|
## loadingtest.make
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
loadingtest.make(<a href="#loadingtest.make-name">name</a>)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Creates a loading phase test environment and test_suite.
|
||||||
|
|
||||||
|
**PARAMETERS**
|
||||||
|
|
||||||
|
|
||||||
|
| Name | Description | Default Value |
|
||||||
|
| :------------- | :------------- | :------------- |
|
||||||
|
| <a id="loadingtest.make-name"></a>name | name of the suite of tests to create | none |
|
||||||
|
|
||||||
|
**RETURNS**
|
||||||
|
|
||||||
|
loading phase environment passed to other loadingtest functions
|
||||||
|
|
||||||
|
|
||||||
|
<a id="#loadingtest.equals"></a>
|
||||||
|
|
||||||
|
## loadingtest.equals
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
loadingtest.equals(<a href="#loadingtest.equals-env">env</a>, <a href="#loadingtest.equals-test_case">test_case</a>, <a href="#loadingtest.equals-expected">expected</a>, <a href="#loadingtest.equals-actual">actual</a>)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Creates a test case for asserting state at LOADING phase.
|
||||||
|
|
||||||
|
**PARAMETERS**
|
||||||
|
|
||||||
|
|
||||||
|
| Name | Description | Default Value |
|
||||||
|
| :------------- | :------------- | :------------- |
|
||||||
|
| <a id="loadingtest.equals-env"></a>env | Loading test env created from loadingtest.make | none |
|
||||||
|
| <a id="loadingtest.equals-test_case"></a>test_case | Name of the test case | none |
|
||||||
|
| <a id="loadingtest.equals-expected"></a>expected | Expected value to test | none |
|
||||||
|
| <a id="loadingtest.equals-actual"></a>actual | Actual value received. | none |
|
||||||
|
|
||||||
|
**RETURNS**
|
||||||
|
|
||||||
|
None, creates test case
|
||||||
|
|
||||||
|
|
||||||
<a id="#register_unittest_toolchains"></a>
|
<a id="#register_unittest_toolchains"></a>
|
||||||
|
|
||||||
## register_unittest_toolchains
|
## register_unittest_toolchains
|
||||||
|
|
|
@ -564,6 +564,67 @@ def _target_under_test(env):
|
||||||
fail("test rule does not have a target_under_test")
|
fail("test rule does not have a target_under_test")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _loading_test_impl(ctx):
|
||||||
|
tc = ctx.toolchains[TOOLCHAIN_TYPE].unittest_toolchain_info
|
||||||
|
content = tc.success_templ
|
||||||
|
if ctx.attr.failure_message:
|
||||||
|
content = tc.failure_templ % ctx.attr.failure_message
|
||||||
|
|
||||||
|
testbin = ctx.actions.declare_file("loading_test_" + ctx.label.name + tc.file_ext)
|
||||||
|
ctx.actions.write(
|
||||||
|
output = testbin,
|
||||||
|
content = content,
|
||||||
|
is_executable = True,
|
||||||
|
)
|
||||||
|
return [DefaultInfo(executable = testbin)]
|
||||||
|
|
||||||
|
_loading_test = rule(
|
||||||
|
implementation = _loading_test_impl,
|
||||||
|
attrs = {
|
||||||
|
"failure_message": attr.string(),
|
||||||
|
},
|
||||||
|
toolchains = [TOOLCHAIN_TYPE],
|
||||||
|
test = True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _loading_make(name):
|
||||||
|
"""Creates a loading phase test environment and test_suite.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: name of the suite of tests to create
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
loading phase environment passed to other loadingtest functions
|
||||||
|
"""
|
||||||
|
native.test_suite(
|
||||||
|
name = name + "_tests",
|
||||||
|
tags = [name + "_test_case"],
|
||||||
|
)
|
||||||
|
return struct(name = name)
|
||||||
|
|
||||||
|
def _loading_assert_equals(env, test_case, expected, actual):
|
||||||
|
"""Creates a test case for asserting state at LOADING phase.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
env: Loading test env created from loadingtest.make
|
||||||
|
test_case: Name of the test case
|
||||||
|
expected: Expected value to test
|
||||||
|
actual: Actual value received.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None, creates test case
|
||||||
|
"""
|
||||||
|
|
||||||
|
msg = None
|
||||||
|
if expected != actual:
|
||||||
|
msg = 'Expected "%s", but got "%s"' % (expected, actual)
|
||||||
|
|
||||||
|
_loading_test(
|
||||||
|
name = "%s_%s" % (env.name, test_case),
|
||||||
|
failure_message = msg,
|
||||||
|
tags = [env.name + "_test_case"],
|
||||||
|
)
|
||||||
|
|
||||||
asserts = struct(
|
asserts = struct(
|
||||||
expect_failure = _expect_failure,
|
expect_failure = _expect_failure,
|
||||||
equals = _assert_equals,
|
equals = _assert_equals,
|
||||||
|
@ -590,3 +651,8 @@ analysistest = struct(
|
||||||
target_bin_dir_path = _target_bin_dir_path,
|
target_bin_dir_path = _target_bin_dir_path,
|
||||||
target_under_test = _target_under_test,
|
target_under_test = _target_under_test,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
loadingtest = struct(
|
||||||
|
make = _loading_make,
|
||||||
|
equals = _loading_assert_equals,
|
||||||
|
)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
"""Unit tests for unittest.bzl."""
|
"""Unit tests for unittest.bzl."""
|
||||||
|
|
||||||
load("//lib:partial.bzl", "partial")
|
load("//lib:partial.bzl", "partial")
|
||||||
load("//lib:unittest.bzl", "analysistest", "asserts", "unittest")
|
load("//lib:unittest.bzl", "analysistest", "asserts", "loadingtest", "unittest")
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
####### basic_failing_test ########
|
####### basic_failing_test ########
|
||||||
|
@ -308,6 +308,13 @@ inspect_output_dirs_test = analysistest.make(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
# buildifier: disable=unnamed-macro
|
||||||
|
@ -377,3 +384,6 @@ def unittest_passing_tests_suite():
|
||||||
name = "inspect_output_dirs_fake_target",
|
name = "inspect_output_dirs_fake_target",
|
||||||
tags = ["manual"],
|
tags = ["manual"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
loading_env = loadingtest.make("selftest")
|
||||||
|
_loading_phase_test(loading_env)
|
||||||
|
|
Loading…
Reference in New Issue