1"""Copyright (C) 2022 The Android Open Source Project
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7     http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14"""
15
16load("@bazel_skylib//lib:paths.bzl", "paths")
17load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
18load("//build/bazel/rules:hidl_file_utils.bzl", "INTERFACE_HEADER_PREFIXES", "TYPE_HEADER_PREFIXES")
19load("//build/bazel/rules/hidl:hidl_interface.bzl", "INTERFACE_SUFFIX")
20load("//build/bazel/rules/hidl:hidl_library.bzl", "hidl_library")
21load("//build/bazel/rules/hidl:hidl_package_root.bzl", "hidl_package_root")
22load(":cc_hidl_library.bzl", "CC_HEADER_SUFFIX", "cc_hidl_library")
23
24HIDL_GEN = "prebuilts/build-tools/linux-x86/bin/hidl-gen"
25
26SRC_TYPE_NAME_1 = "types_1.hal"
27GEN_TYPE_NAME_1 = "types_1.h"
28SRC_INTERFACE_NAME_1 = "IInterface_1.hal"
29GEN_INTERFACE_NAME_1 = "Interface_1.h"
30ROOT_1 = "android.hardware"
31ROOT_INTERFACE_FILE_LABEL_1 = "//hardware/interfaces:current.txt"
32ROOT_INTERFACE_FILE_1 = "hardware/interfaces/current.txt"
33ROOT_INTERFACE_PATH_1 = "hardware/interfaces"
34INTERFACE_PACKAGE_NAME_1 = "android.hardware.int1"
35ROOT_ARGUMENT_1 = "android.hardware:hardware/interfaces"
36
37SRC_TYPE_NAME_2 = "types_2.hal"
38SRC_INTERFACE_NAME_2 = "IInterface_2.hal"
39ROOT_2 = "android.hidl"
40ROOT_INTERFACE_FILE_LABEL_2 = "//system/libhidl/transport:current.txt"
41ROOT_INTERFACE_FILE_2 = "system/libhidl/transport/current.txt"
42ROOT_INTERFACE_PATH_2 = "system/libhidl/transport"
43ROOT_ARGUMENT_2 = "android.hidl:system/libhidl/transport"
44INTERFACE_PACKAGE_NAME_2 = "android.hidl.int2"
45
46INTERFACE_PACKAGE_NAME_CORE = "android.hidl.base"
47
48INTERFACE_VERSION_1_0 = "1.0"
49INTERFACE_VERSION_1_1 = "1.1"
50
51def _setup_roots():
52    hidl_package_root(
53        name = ROOT_1,
54        current = ROOT_INTERFACE_FILE_LABEL_1,
55        path = ROOT_INTERFACE_PATH_1,
56        tags = ["manual"],
57    )
58
59    hidl_package_root(
60        name = ROOT_2,
61        current = ROOT_INTERFACE_FILE_LABEL_2,
62        path = ROOT_INTERFACE_PATH_2,
63        tags = ["manual"],
64    )
65
66def _cc_code_gen_test_impl(ctx):
67    env = analysistest.begin(ctx)
68    actions = analysistest.target_actions(env)
69    package_root = paths.dirname(ctx.build_file_path)
70    header_gen_actions = [a for a in actions if a.mnemonic == "HidlGenCcHeader"]
71    asserts.true(
72        env,
73        len(header_gen_actions) == 1,
74        "Cc header gen action not found: %s" % actions,
75    )
76
77    header_gen_action = header_gen_actions[0]
78
79    asserts.equals(
80        env,
81        expected = sorted([
82            paths.join(package_root, SRC_TYPE_NAME_1),
83            paths.join(package_root, SRC_INTERFACE_NAME_1),
84            paths.join(package_root, SRC_TYPE_NAME_2),
85            paths.join(package_root, SRC_INTERFACE_NAME_2),
86            ROOT_INTERFACE_FILE_1,
87            ROOT_INTERFACE_FILE_2,
88            paths.join(HIDL_GEN),
89        ]),
90        actual = sorted([
91            file.short_path
92            for file in header_gen_action.inputs.to_list()
93        ]),
94    )
95
96    path = paths.join(package_root, INTERFACE_PACKAGE_NAME_1.replace(".", "/"), INTERFACE_VERSION_1_0)
97    asserts.equals(
98        env,
99        expected = sorted(
100            [
101                paths.join(path, prefix + GEN_TYPE_NAME_1)
102                for prefix in TYPE_HEADER_PREFIXES
103            ] +
104            [
105                paths.join(path, prefix + GEN_INTERFACE_NAME_1)
106                for prefix in INTERFACE_HEADER_PREFIXES
107            ],
108        ),
109        actual = sorted([
110            file.short_path
111            for file in header_gen_action.outputs.to_list()
112        ]),
113    )
114
115    cmd = header_gen_action.argv
116    asserts.true(
117        env,
118        HIDL_GEN == cmd[0],
119        "hidl-gen is not called: %s" % cmd,
120    )
121
122    asserts.true(
123        env,
124        "-R" in cmd,
125        "Calling hidl-gen without -R: %s" % cmd,
126    )
127
128    index = cmd.index("-p")
129    asserts.true(
130        env,
131        index > 0,
132        "Calling hidl-gen without -p: %s" % cmd,
133    )
134
135    asserts.true(
136        env,
137        cmd[index + 1] == ".",
138        ". needs to follow -p: %s" % cmd,
139    )
140
141    index = cmd.index("-o")
142    asserts.true(
143        env,
144        index > 0,
145        "Calling hidl-gen without -o: %s" % cmd,
146    )
147
148    asserts.true(
149        env,
150        cmd[index + 1].endswith(package_root),
151        "Incorrect output path: %s" % cmd,
152    )
153
154    index = cmd.index("-L")
155    asserts.true(
156        env,
157        index > 0,
158        "Calling hidl-gen without -L: %s" % cmd,
159    )
160
161    asserts.true(
162        env,
163        cmd[index + 1] == "c++-headers",
164        "Incorrect language: %s" % cmd,
165    )
166
167    roots = []
168    cmd_len = len(cmd)
169    for i in range(cmd_len):
170        if cmd[i] == "-r":
171            roots.append(cmd[i + 1])
172
173    asserts.equals(
174        env,
175        expected = sorted([
176            ROOT_ARGUMENT_1,
177            ROOT_ARGUMENT_2,
178        ]),
179        actual = sorted(roots),
180    )
181
182    asserts.true(
183        env,
184        cmd[cmd_len - 1] == INTERFACE_PACKAGE_NAME_1 + "@" + INTERFACE_VERSION_1_0,
185        "The last arg should be the FQ name of the interface: %s" % cmd,
186    )
187
188    return analysistest.end(env)
189
190cc_code_gen_test = analysistest.make(
191    _cc_code_gen_test_impl,
192)
193
194def _test_cc_code_gen():
195    test_name = "cc_code_gen_test"
196    cc_name = INTERFACE_PACKAGE_NAME_1 + "@" + INTERFACE_VERSION_1_0
197    interface_name = cc_name + INTERFACE_SUFFIX
198    cc_name_dep = INTERFACE_PACKAGE_NAME_2 + "@" + INTERFACE_VERSION_1_0
199    interface_name_dep = cc_name_dep + INTERFACE_SUFFIX
200
201    hidl_library(
202        name = interface_name_dep,
203        root = ROOT_2,
204        fq_name = cc_name_dep,
205        srcs = [
206            SRC_TYPE_NAME_2,
207            SRC_INTERFACE_NAME_2,
208        ],
209        tags = ["manual"],
210    )
211
212    cc_hidl_library(
213        name = cc_name_dep,
214        interface = interface_name_dep,
215        tags = ["manual"],
216    )
217
218    hidl_library(
219        name = interface_name,
220        deps = [interface_name_dep],
221        root = ROOT_1,
222        fq_name = cc_name,
223        srcs = [
224            SRC_TYPE_NAME_1,
225            SRC_INTERFACE_NAME_1,
226        ],
227        tags = ["manual"],
228    )
229
230    cc_hidl_library(
231        name = cc_name,
232        interface = interface_name,
233        dynamic_deps = [cc_name_dep],
234        tags = ["manual"],
235    )
236
237    cc_code_gen_test(
238        name = test_name,
239        target_under_test = cc_name + CC_HEADER_SUFFIX,
240    )
241
242    return test_name
243
244def _cc_interface_dep_test_impl(ctx):
245    env = analysistest.begin(ctx)
246    target_under_test = analysistest.target_under_test(env)
247    dynamic_deps = target_under_test[CcSharedLibraryInfo].dynamic_deps
248
249    dep_name = INTERFACE_PACKAGE_NAME_CORE + "@" + INTERFACE_VERSION_1_1
250    package_root = paths.dirname(ctx.build_file_path)
251
252    asserts.false(
253        env,
254        _find_dep(package_root, dep_name, dynamic_deps),
255        "Core package in the dependencies: %s %s" % (dep_name, dynamic_deps),
256    )
257
258    dep_name = INTERFACE_PACKAGE_NAME_2 + "@" + INTERFACE_VERSION_1_1
259    asserts.true(
260        env,
261        _find_dep(package_root, dep_name, dynamic_deps),
262        "Missing valid dependency: %s %s" % (dep_name, dynamic_deps),
263    )
264
265    return analysistest.end(env)
266
267def _find_dep(package_root, name, deps):
268    full_name = "@//" + package_root + ":" + name
269    for lists in deps.to_list():
270        for dep in lists.exports:
271            if dep.startswith(full_name):
272                return True
273
274    return False
275
276cc_interface_dep_test = analysistest.make(
277    _cc_interface_dep_test_impl,
278)
279
280def _test_cc_interface_dep():
281    test_name = "cc_interface_dep_test"
282    cc_name = INTERFACE_PACKAGE_NAME_1 + "@" + INTERFACE_VERSION_1_1
283    interface_name = cc_name + INTERFACE_SUFFIX
284    cc_name_dep = INTERFACE_PACKAGE_NAME_2 + "@" + INTERFACE_VERSION_1_1
285    interface_name_dep = cc_name_dep + INTERFACE_SUFFIX
286    cc_name_core = INTERFACE_PACKAGE_NAME_CORE + "@" + INTERFACE_VERSION_1_1
287    interface_name_core = cc_name_core + INTERFACE_SUFFIX
288
289    hidl_library(
290        name = interface_name_dep,
291        root = ROOT_2,
292        fq_name = cc_name_dep,
293        srcs = [
294            SRC_TYPE_NAME_2,
295            SRC_INTERFACE_NAME_2,
296        ],
297        tags = ["manual"],
298    )
299
300    cc_hidl_library(
301        name = cc_name_dep,
302        interface = interface_name_dep,
303        tags = ["manual"],
304    )
305
306    hidl_library(
307        name = interface_name_core,
308        root = ROOT_2,
309        fq_name = cc_name_core,
310        srcs = [
311            SRC_TYPE_NAME_2,
312            SRC_INTERFACE_NAME_2,
313        ],
314        tags = ["manual"],
315    )
316
317    cc_hidl_library(
318        name = cc_name_core,
319        interface = interface_name_core,
320        tags = ["manual"],
321    )
322
323    hidl_library(
324        name = interface_name,
325        deps = [interface_name_dep, interface_name_core],
326        root = ROOT_1,
327        fq_name = cc_name,
328        srcs = [
329            SRC_TYPE_NAME_1,
330            SRC_INTERFACE_NAME_1,
331        ],
332        tags = ["manual"],
333    )
334
335    cc_hidl_library(
336        name = cc_name,
337        interface = interface_name,
338        dynamic_deps = [cc_name_dep, cc_name_core],
339        tags = ["manual"],
340    )
341
342    cc_interface_dep_test(
343        name = test_name,
344        target_under_test = cc_name,
345    )
346
347    return test_name
348
349def cc_hidl_library_test_suite(name):
350    _setup_roots()
351    native.test_suite(
352        name = name,
353        tests = [
354            _test_cc_code_gen(),
355            _test_cc_interface_dep(),
356        ],
357    )
358