1# Copyright (C) 2022 The Android Open Source Project
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
15load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
16load("//build/bazel/rules/sysprop:sysprop_library.bzl", "sysprop_library")
17load("//build/bazel/rules/test_common:args.bzl", "get_arg_value")
18load(
19    "//build/bazel/rules/test_common:paths.bzl",
20    "get_output_and_package_dir_based_path",
21    "get_package_dir_based_path",
22)
23load(":cc_sysprop_library.bzl", "cc_gen_sysprop")
24
25def _provides_correct_outputs_test_impl(ctx):
26    env = analysistest.begin(ctx)
27
28    target_under_test = analysistest.target_under_test(env)
29    output_files = target_under_test[DefaultInfo].files.to_list()
30    actual_output_strings = [
31        file.short_path
32        for file in output_files
33    ]
34
35    asserts.equals(
36        env,
37        6,
38        len(output_files),
39        "List of outputs incorrect length",
40    )
41    for name in ["foo", "bar"]:
42        expected_cpp_path = get_package_dir_based_path(
43            env,
44            "sysprop/path/to/%s.sysprop.cpp" % (name),
45        )
46        asserts.true(
47            env,
48            expected_cpp_path in actual_output_strings,
49            ("Generated cpp source file for %s.sysprop not present in " +
50             "output.\n" +
51             "Expected Value: %s\n" +
52             "Actual output: %s") % (
53                name,
54                expected_cpp_path,
55                actual_output_strings,
56            ),
57        )
58        expected_header_path = get_package_dir_based_path(
59            env,
60            "sysprop/include/path/to/%s.sysprop.h" % (name),
61        )
62        asserts.true(
63            env,
64            expected_header_path in actual_output_strings,
65            ("Generated header source file for %s.sysprop not present in " +
66             "output.\n" +
67             "Expected Value: %s\n" +
68             "Actual output: %s") % (
69                name,
70                expected_header_path,
71                actual_output_strings,
72            ),
73        )
74        expected_public_header_path = get_package_dir_based_path(
75            env,
76            "sysprop/public/include/path/to/%s.sysprop.h" % (name),
77        )
78        asserts.true(
79            env,
80            expected_public_header_path in actual_output_strings,
81            ("Generated public header source file for %s.sysprop not present " +
82             "in output.\n" +
83             "Expected Value: %s\n" +
84             "Actual output: %s") % (
85                name,
86                expected_public_header_path,
87                actual_output_strings,
88            ),
89        )
90
91    return analysistest.end(env)
92
93provides_correct_outputs_test = analysistest.make(
94    _provides_correct_outputs_test_impl,
95)
96
97# TODO(b/240466571): This test will be notably different after implementing
98#                    exported include and header selection
99def _provides_correct_ccinfo_test_impl(ctx):
100    env = analysistest.begin(ctx)
101
102    target_under_test = analysistest.target_under_test(env)
103    target_ccinfo = target_under_test[CcInfo]
104    actual_includes = target_ccinfo.compilation_context.includes.to_list()
105    actual_headers = target_ccinfo.compilation_context.headers.to_list()
106    expected_package_relative_include = get_package_dir_based_path(
107        env,
108        "sysprop/include",
109    )
110    asserts.true(
111        env,
112        expected_package_relative_include in actual_includes,
113        ("Package relative include incorrect or not found in CcInfo.\n" +
114         "Expected value: %s\n" +
115         "Actual output: %s") % (
116            expected_package_relative_include,
117            actual_includes,
118        ),
119    )
120    expected_root_relative_include = get_output_and_package_dir_based_path(
121        env,
122        "sysprop/include",
123    )
124    asserts.true(
125        env,
126        expected_root_relative_include in actual_includes,
127        ("Root relative include incorrect or not found in CcInfo.\n" +
128         "Expected value: %s\n" +
129         "Actual output: %s") % (
130            expected_root_relative_include,
131            actual_includes,
132        ),
133    )
134    asserts.true(
135        env,
136        len(actual_includes) == 2,
137        ("CcInfo includes should contain a package relative and a " +
138         "root-relative path and nothing else. Actual output: %s" % (
139             actual_includes,
140         )),
141    )
142    actual_header_strings = [
143        header.path
144        for header in actual_headers
145    ]
146    for name in ["foo", "bar"]:
147        asserts.true(
148            env,
149            get_output_and_package_dir_based_path(
150                env,
151                "sysprop/include/path/to/%s.sysprop.h" % (name),
152            ) in actual_header_strings,
153            ("Generated header file for %s.sysprop not present in CcInfo " +
154             "headers. Actual output: %s") % (name, actual_header_strings),
155        )
156    asserts.true(
157        env,
158        len(actual_headers) == 2,
159        ("List of generated headers in CcInfo was incorrect length. Should " +
160         "be exactly two. Actual output: %s" % actual_headers),
161    )
162
163    return analysistest.end(env)
164
165provides_correct_ccinfo_test = analysistest.make(
166    _provides_correct_ccinfo_test_impl,
167)
168
169def _correct_args_test_impl(ctx):
170    env = analysistest.begin(ctx)
171
172    actions = analysistest.target_actions(env)
173
174    asserts.equals(
175        env,
176        2,
177        len(actions),
178        "Incorrect number of actions",
179    )
180    names = ["foo", "bar"]
181    for i in range(2):
182        name = names[i]
183        actual_args = actions[i].argv
184
185        asserts.equals(
186            env,
187            get_output_and_package_dir_based_path(env, "sysprop/include/path/to"),
188            get_arg_value(actual_args, "--header-dir"),
189            "--header-dir argument incorrect or not found.\n",
190        )
191        asserts.equals(
192            env,
193            get_output_and_package_dir_based_path(env, "sysprop/public/include/path/to"),
194            get_arg_value(actual_args, "--public-header-dir"),
195            "--public-header-dir argument incorrect or not found.\n",
196        )
197        asserts.equals(
198            env,
199            get_output_and_package_dir_based_path(env, "sysprop/path/to"),
200            get_arg_value(actual_args, "--source-dir"),
201            "--source-dir argument incorrect or not found.\n",
202        )
203        asserts.equals(
204            env,
205            "path/to/%s.sysprop.h" % name,
206            get_arg_value(actual_args, "--include-name"),
207            "--include-name argument incorrect or not found.\n",
208        )
209        expected_input = get_package_dir_based_path(
210            env,
211            "path/to/%s.sysprop" % name,
212        )
213        actual_cli_string = " ".join(actual_args)
214        asserts.true(
215            env,
216            expected_input in actual_cli_string,
217            ("Input argument not found.\n" +
218             "Expected Value: %s\n" +
219             "Command: %s") % (expected_input, actual_cli_string),
220        )
221
222    return analysistest.end(env)
223
224correct_args_test = analysistest.make(
225    _correct_args_test_impl,
226)
227
228def _create_test_targets(name, rule_func):
229    wrapper_name = name + "_wrapper"
230    test_name = name + "_test"
231    sysprop_library(
232        name = wrapper_name,
233        srcs = [
234            "path/to/foo.sysprop",
235            "path/to/bar.sysprop",
236        ],
237        tags = ["manual"],
238    )
239    cc_gen_sysprop(
240        name = name,
241        dep = ":" + wrapper_name,
242        tags = ["manual"],
243    )
244    rule_func(
245        name = test_name,
246        target_under_test = name,
247    )
248    return test_name
249
250def cc_gen_sysprop_test_suite(name):
251    native.test_suite(
252        name = name,
253        tests = [
254            _create_test_targets(
255                "provides_correct_outputs",
256                provides_correct_outputs_test,
257            ),
258            _create_test_targets(
259                "provides_correct_ccinfo",
260                provides_correct_ccinfo_test,
261            ),
262            _create_test_targets(
263                "correct_args_test",
264                correct_args_test,
265            ),
266        ],
267    )
268