1"""
2Copyright (C) 2023 The Android Open Source Project
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15"""
16
17load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
18load("//build/bazel/rules/cc:cc_prebuilt_library_shared.bzl", "cc_prebuilt_library_shared")
19load("//build/bazel/rules/test_common:paths.bzl", "get_output_and_package_dir_based_path")
20load(":cc_binary_test.bzl", "strip_test_assert_flags")
21
22def _cc_prebuilt_library_shared_test_impl(ctx):
23    env = analysistest.begin(ctx)
24    target = analysistest.target_under_test(env)
25    expected_lib = ctx.attr.expected_lib
26    cc_info = target[CcInfo]
27    compilation_context = cc_info.compilation_context
28    linker_inputs = cc_info.linking_context.linker_inputs.to_list()
29    libs_to_link = []
30    for lib in linker_inputs:
31        libs_to_link += lib.libraries
32
33    asserts.true(
34        env,
35        expected_lib in [lib.dynamic_library.basename for lib in libs_to_link],
36        "\nExpected the target to include the shared library %s; but instead got:\n\t%s\n" % (expected_lib, libs_to_link),
37    )
38
39    actions = analysistest.target_actions(env)
40    strip_acts = [a for a in actions if a.mnemonic == "SolibSymlink"]
41    has_strip = len(strip_acts) > 0
42    asserts.true(
43        env,
44        has_strip,
45        "expected to find an action with CcStrip mnemonic in:\n%s" % actions,
46    )
47
48    # Checking for the expected {,system_}includes
49    assert_template = "\nExpected the %s for " + expected_lib + " to be:\n\t%s\n, but instead got:\n\t%s\n"
50    expand_paths = lambda paths: [get_output_and_package_dir_based_path(env, p) for p in paths]
51    expected_includes = expand_paths(ctx.attr.expected_includes)
52    expected_system_includes = expand_paths(ctx.attr.expected_system_includes)
53
54    includes = compilation_context.includes.to_list()
55    for include in expected_includes:
56        asserts.true(env, include in includes, assert_template % ("includes", expected_includes, includes))
57
58    system_includes = compilation_context.system_includes.to_list()
59    for include in expected_system_includes:
60        asserts.true(env, include in system_includes, assert_template % ("system_includes", expected_system_includes, system_includes))
61
62    return analysistest.end(env)
63
64_cc_prebuilt_library_shared_test = analysistest.make(
65    _cc_prebuilt_library_shared_test_impl,
66    attrs = dict(
67        expected_lib = attr.string(),
68        expected_includes = attr.string_list(),
69        expected_system_includes = attr.string_list(),
70    ),
71)
72
73def _cc_prebuilt_library_shared_simple():
74    name = "_cc_prebuilt_library_shared_simple"
75    test_name = name + "_test"
76    lib = name + ".so"
77
78    cc_prebuilt_library_shared(
79        name = name,
80        shared_library = lib,
81        tags = ["manual"],
82    )
83    _cc_prebuilt_library_shared_test(
84        name = test_name,
85        target_under_test = name,
86        expected_lib = lib,
87    )
88
89    return test_name
90
91def _cc_prebuilt_library_shared_has_all_includes():
92    name = "_cc_prebuilt_library_shared_has_all_includes"
93    test_name = name + "_test"
94    lib = name + ".so"
95    includes = ["includes"]
96    system_includes = ["system_includes"]
97
98    cc_prebuilt_library_shared(
99        name = name,
100        shared_library = lib,
101        export_includes = includes,
102        export_system_includes = system_includes,
103        tags = ["manual"],
104    )
105    _cc_prebuilt_library_shared_test(
106        name = test_name,
107        target_under_test = name,
108        expected_lib = lib,
109        expected_includes = includes,
110        expected_system_includes = system_includes,
111    )
112
113    return test_name
114
115def _cc_prebuilt_library_shared_stripped_test_impl(ctx):
116    env = analysistest.begin(ctx)
117    actions = analysistest.target_actions(env)
118    strip_acts = [a for a in actions if a.mnemonic == "CcStrip"]
119    has_strip = len(strip_acts) > 0
120    asserts.true(
121        env,
122        has_strip,
123        "expected to find an action with CcStrip mnemonic in:\n%s" % actions,
124    )
125    if has_strip:
126        strip_test_assert_flags(env, strip_acts[0], ctx.attr.strip_flags)
127    return analysistest.end(env)
128
129_cc_prebuilt_library_shared_stripped_test = analysistest.make(
130    _cc_prebuilt_library_shared_stripped_test_impl,
131    attrs = dict(
132        strip_flags = attr.string_list(),
133    ),
134)
135
136def _cc_prebuilt_library_shared_stripped_all():
137    name = "_cc_prebuilt_library_shared_stripped_all"
138    test_name = name + "_test"
139
140    cc_prebuilt_library_shared(
141        name = name,
142        shared_library = "foo.so",
143        all = True,
144        tags = ["manual"],
145    )
146    _cc_prebuilt_library_shared_stripped_test(
147        name = test_name,
148        target_under_test = name,
149        strip_flags = [
150            "--add-gnu-debuglink",
151        ],
152    )
153    return test_name
154
155def _no_input_shared_library_succeeds_test_impl(ctx):
156    env = analysistest.begin(ctx)
157    target = analysistest.target_under_test(env)
158    cc_info = target[CcInfo]
159    linker_inputs = cc_info.linking_context.linker_inputs.to_list()
160    libs_to_link = []
161    for lib in linker_inputs:
162        libs_to_link.extend(lib.libraries)
163    asserts.equals(
164        env,
165        len(libs_to_link),
166        0,
167        "\nExpected the shared library to be empty, but instead got:\n\t%s\n" % str(libs_to_link),
168    )
169
170    actions = analysistest.target_actions(env)
171    asserts.equals(
172        env,
173        len(actions),
174        0,
175        "expect no actions for no input",
176    )
177
178    return analysistest.end(env)
179
180_no_input_shared_library_succeeds_test = analysistest.make(
181    _no_input_shared_library_succeeds_test_impl,
182)
183
184def _cc_prebuilt_library_shared_no_input_succeeds():
185    name = "_cc_prebuilt_library_shared_no_input_succeeds"
186    test_name = name + "_test"
187
188    cc_prebuilt_library_shared(
189        name = name,
190        tags = ["manual"],
191    )
192    _no_input_shared_library_succeeds_test(
193        name = test_name,
194        target_under_test = name,
195    )
196
197    return test_name
198
199def cc_prebuilt_library_shared_test_suite(name):
200    native.test_suite(
201        name = name,
202        tests = [
203            _cc_prebuilt_library_shared_simple(),
204            _cc_prebuilt_library_shared_has_all_includes(),
205            _cc_prebuilt_library_shared_stripped_all(),
206            _cc_prebuilt_library_shared_no_input_succeeds(),
207        ],
208    )
209