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