xref: /aosp_15_r20/external/bazelbuild-kotlin-rules/kotlin/common/testing/testing_rules.bzl (revision 3a22c0a33dd99bcca39a024d43e6fbcc55c2806e)
1# Copyright 2022 Google LLC. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the License);
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""kt_testing_rules"""
16
17load("//:visibility.bzl", "RULES_KOTLIN")
18load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
19load(":analysis.bzl", "kt_analysis")
20
21visibility(RULES_KOTLIN)
22
23# Mark targets that's aren't expected to build, but are needed for analysis test assertions.
24_ONLY_FOR_ANALYSIS_TAGS = ["manual", "nobuilder", "notap"]
25
26def _wrap_for_analysis(inner_rule):
27    """Wrap an existing rule to make it easier to use in analysis tests.
28
29    Args:
30        inner_rule: [rule|macro]
31
32    Returns:
33        [macro] Calls inner_rule with appropate tags, returning the target name
34    """
35
36    def wrapper(name, tags = [], **kwargs):
37        inner_rule(
38            name = name,
39            tags = tags + _ONLY_FOR_ANALYSIS_TAGS,
40            **kwargs
41        )
42        return name
43
44    return wrapper
45
46_assert_failure_test = analysistest.make(
47    impl = lambda ctx: _assert_failure_test_impl(ctx),
48    expect_failure = True,
49    attrs = dict(
50        msg_contains = attr.string(mandatory = True),
51    ),
52)
53
54def _assert_failure_test_impl(ctx):
55    kt_analysis.check_endswith_test(ctx)
56
57    env = analysistest.begin(ctx)
58    asserts.expect_failure(env, ctx.attr.msg_contains)
59    return analysistest.end(env)
60
61_coverage_instrumentation_test = analysistest.make(
62    impl = lambda ctx: _coverage_instrumentation_test_impl(ctx),
63    attrs = dict(
64        expected_instrumented_file_names = attr.string_list(),
65    ),
66    config_settings = {
67        "//command_line_option:collect_code_coverage": "1",
68        "//command_line_option:instrument_test_targets": "1",
69        "//command_line_option:instrumentation_filter": "+",
70    },
71)
72
73def _coverage_instrumentation_test_impl(ctx):
74    env = analysistest.begin(ctx)
75    target_under_test = analysistest.target_under_test(env)
76    instrumented_files_info = target_under_test[InstrumentedFilesInfo]
77    instrumented_files = instrumented_files_info.instrumented_files.to_list()
78    asserts.equals(
79        env,
80        ctx.attr.expected_instrumented_file_names,
81        [file.basename for file in instrumented_files],
82    )
83    return analysistest.end(env)
84
85def _create_file(name, content = ""):
86    """Declare a generated file with optional content.
87
88    Args:
89        name: [string] The relative file path
90        content: [string]
91
92    Returns:
93        [File] The label of the file
94    """
95
96    if content.startswith("\n"):
97        content = content[1:-1]
98
99    native.genrule(
100        name = "gen_" + name,
101        outs = [name],
102        cmd = """
103cat > $@ <<EOF
104%s
105EOF
106""" % content,
107    )
108
109    return name
110
111_create_dir = rule(
112    implementation = lambda ctx: _create_dir_impl(ctx),
113    attrs = dict(
114        subdir = attr.string(),
115        srcs = attr.label_list(allow_files = True),
116    ),
117)
118
119def _create_dir_impl(ctx):
120    dir = ctx.actions.declare_directory(ctx.attr.name)
121
122    command = "mkdir -p {0} " + ("&& cp {1} {0}" if ctx.files.srcs else "# {1}")
123    ctx.actions.run_shell(
124        command = command.format(
125            dir.path + "/" + ctx.attr.subdir,
126            " ".join([s.path for s in ctx.files.srcs]),
127        ),
128        inputs = ctx.files.srcs,
129        outputs = [dir],
130    )
131
132    return [DefaultInfo(files = depset([dir]))]
133
134kt_testing_rules = struct(
135    # go/keep-sorted start
136    ONLY_FOR_ANALYSIS_TAGS = _ONLY_FOR_ANALYSIS_TAGS,
137    assert_failure_test = _assert_failure_test,
138    coverage_instrumentation_test = _coverage_instrumentation_test,
139    create_dir = _wrap_for_analysis(_create_dir),
140    create_file = _create_file,
141    wrap_for_analysis = _wrap_for_analysis,
142    # go/keep-sorted end
143)
144