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:unittest.bzl", "analysistest", "asserts")
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(":flex.bzl", "genlex")
24
25def _single_l_file_to_c_test_impl(ctx):
26    env = analysistest.begin(ctx)
27
28    actions = analysistest.target_actions(env)
29
30    asserts.equals(env, 1, len(actions))
31
32    actual_list_foo = [input.path for input in actions[0].inputs.to_list()]
33    expected_path_foo = get_package_dir_based_path(env, "foo.l")
34    asserts.true(
35        env,
36        expected_path_foo in actual_list_foo,
37        ("Input file %s not present or incorrect in Bazel action for " +
38         "target foo. Actual list of inputs: %s") % (
39            expected_path_foo,
40            actual_list_foo,
41        ),
42    )
43    expected_output = get_output_and_package_dir_based_path(env, "foo.c")
44    actual_outputs = [output.path for output in actions[0].outputs.to_list()]
45    asserts.true(
46        env,
47        expected_output in actual_outputs,
48        ("Expected output %s not present or incorrect in Bazel action\n" +
49         "Actual list of outputs: %s") % (
50            expected_output,
51            actual_outputs,
52        ),
53    )
54
55    return analysistest.end(env)
56
57single_l_file_to_c_test = analysistest.make(_single_l_file_to_c_test_impl)
58
59def _test_single_l_file_to_c():
60    name = "single_l_file_to_c"
61    test_name = name + "_test"
62    genlex(
63        name = name,
64        srcs = ["foo.l"],
65        tags = ["manual"],
66    )
67    single_l_file_to_c_test(
68        name = test_name,
69        target_under_test = name,
70    )
71    return test_name
72
73def _single_ll_file_to_cc_test_impl(ctx):
74    env = analysistest.begin(ctx)
75
76    actions = analysistest.target_actions(env)
77
78    asserts.equals(env, 1, len(actions))
79
80    actual_list_foo = [input.path for input in actions[0].inputs.to_list()]
81    expected_path_foo = get_package_dir_based_path(env, "foo.ll")
82    asserts.true(
83        env,
84        expected_path_foo in actual_list_foo,
85        ("Input file %s not present or incorrect in Bazel action for " +
86         "target foo. Actual list of inputs: %s") % (
87            expected_path_foo,
88            actual_list_foo,
89        ),
90    )
91    expected_output = get_output_and_package_dir_based_path(env, "foo.cc")
92    actual_outputs = [output.path for output in actions[0].outputs.to_list()]
93    asserts.true(
94        env,
95        expected_output in actual_outputs,
96        ("Expected output %s not present or incorrect in Bazel action\n" +
97         "Actual list of outputs: %s") % (
98            expected_output,
99            actual_outputs,
100        ),
101    )
102
103    return analysistest.end(env)
104
105single_ll_file_to_cc_test = analysistest.make(_single_ll_file_to_cc_test_impl)
106
107def _test_single_ll_file_to_cc():
108    name = "single_ll_file_to_cc"
109    test_name = name + "_test"
110    genlex(
111        name = name,
112        srcs = ["foo.ll"],
113        tags = ["manual"],
114    )
115    single_ll_file_to_cc_test(
116        name = test_name,
117        target_under_test = name,
118    )
119    return test_name
120
121def _multiple_files_correct_type_test_impl(ctx):
122    env = analysistest.begin(ctx)
123
124    actions = analysistest.target_actions(env)
125
126    asserts.equals(env, 2, len(actions))
127
128    actual_list_foo = [input.path for input in actions[0].inputs.to_list()]
129    expected_path_foo = get_package_dir_based_path(env, "foo.l")
130    asserts.true(
131        env,
132        expected_path_foo in actual_list_foo,
133        ("Input file %s not present or incorrect in Bazel action for " +
134         "target foo. Actual list of inputs: %s") % (
135            expected_path_foo,
136            actual_list_foo,
137        ),
138    )
139    actual_list_bar = [input.path for input in actions[1].inputs.to_list()]
140    expected_path_bar = get_package_dir_based_path(env, "bar.l")
141    asserts.true(
142        env,
143        expected_path_bar in actual_list_bar,
144        ("Input file %s not present or incorrect in Bazel action for " +
145         "target bar. Actual list of inputs: %s") % (
146            expected_path_bar,
147            actual_list_bar,
148        ),
149    )
150
151    expected_output = get_output_and_package_dir_based_path(env, "foo.c")
152    actual_outputs = [output.path for output in actions[0].outputs.to_list()]
153    asserts.true(
154        env,
155        expected_output in actual_outputs,
156        ("Expected output %s not present or incorrect in Bazel action" +
157         "for source file foo.l\n" +
158         "Actual list of outputs: %s") % (
159            expected_output,
160            actual_outputs,
161        ),
162    )
163    expected_output = get_output_and_package_dir_based_path(env, "bar.c")
164    actual_outputs = [output.path for output in actions[1].outputs.to_list()]
165    asserts.true(
166        env,
167        expected_output in actual_outputs,
168        ("Expected output %s not present or incorrect in Bazel action " +
169         "for source file bar.l\n" +
170         "Actual list of outputs: %s") % (
171            expected_output,
172            actual_outputs,
173        ),
174    )
175
176    return analysistest.end(env)
177
178multiple_files_correct_type_test = analysistest.make(
179    _multiple_files_correct_type_test_impl,
180)
181
182def _test_multiple_files_correct_type():
183    name = "multiple_files_correct_type"
184    test_name = name + "_test"
185    genlex(
186        name = name,
187        srcs = ["foo.l", "bar.l"],
188        tags = ["manual"],
189    )
190    multiple_files_correct_type_test(
191        name = test_name,
192        target_under_test = name,
193    )
194    return test_name
195
196def _output_arg_test_impl(ctx):
197    env = analysistest.begin(ctx)
198
199    actions = analysistest.target_actions(env)
200    actual_list = actions[0].argv
201    cli_string = " ".join(actions[0].argv)
202    expected_value = get_output_and_package_dir_based_path(env, "foo.c")
203
204    asserts.equals(
205        env,
206        expected_value,
207        get_arg_value(actual_list, "-o"),
208        ("Argument -o not found or had unexpected value.\n" +
209         "Expected value: %s\n" +
210         "Command: %s") % (
211            expected_value,
212            cli_string,
213        ),
214    )
215
216    return analysistest.end(env)
217
218output_arg_test = analysistest.make(_output_arg_test_impl)
219
220def _test_output_arg():
221    name = "output_arg"
222    test_name = name + "_test"
223    genlex(
224        name = name,
225        srcs = ["foo.l"],
226        tags = ["manual"],
227    )
228    output_arg_test(
229        name = test_name,
230        target_under_test = name,
231    )
232    return test_name
233
234def _input_arg_test_impl(ctx):
235    env = analysistest.begin(ctx)
236
237    actions = analysistest.target_actions(env)
238    actual_argv = actions[0].argv
239    expected_value = get_package_dir_based_path(env, "foo.l")
240
241    asserts.true(
242        env,
243        expected_value in actual_argv,
244        "Input file %s not present or incorrect in flex command args" %
245        expected_value,
246    )
247
248    return analysistest.end(env)
249
250input_arg_test = analysistest.make(_input_arg_test_impl)
251
252def _test_input_arg():
253    name = "input_arg"
254    test_name = name + "_test"
255    genlex(
256        name = name,
257        srcs = ["foo.l"],
258        tags = ["manual"],
259    )
260    input_arg_test(
261        name = test_name,
262        target_under_test = name,
263    )
264    return test_name
265
266def _lexopts_test_impl(ctx):
267    env = analysistest.begin(ctx)
268    actions = analysistest.target_actions(env)
269
270    actual_argv = actions[0].argv
271    asserts.true(
272        env,
273        "foo_opt" in actual_argv,
274        ("Did not find expected lexopt foo_opt %s for target foo in test " +
275         "lexopts_test") % actual_argv,
276    )
277    asserts.true(
278        env,
279        "bar_opt" in actual_argv,
280        ("Did not find expected lexopt bar_opt %s for target bars in test " +
281         "lexopts_test") % actual_argv,
282    )
283
284    return analysistest.end(env)
285
286lexopts_test = analysistest.make(_lexopts_test_impl)
287
288def _test_lexopts():
289    name = "lexopts"
290    test_name = name + "_test"
291    genlex(
292        name = name,
293        srcs = ["foo_lexopts.ll"],
294        lexopts = ["foo_opt", "bar_opt"],
295        tags = ["manual"],
296    )
297
298    lexopts_test(
299        name = test_name,
300        target_under_test = name,
301    )
302    return test_name
303
304# TODO(b/190006308): When fixed, l and ll sources can coexist. Remove this test.
305def _l_and_ll_files_fails_test_impl(ctx):
306    env = analysistest.begin(ctx)
307
308    asserts.expect_failure(
309        env,
310        "srcs contains both .l and .ll files. Please use separate targets.",
311    )
312
313    return analysistest.end(env)
314
315l_and_ll_files_fails_test = analysistest.make(
316    _l_and_ll_files_fails_test_impl,
317    expect_failure = True,
318)
319
320def _test_l_and_ll_files_fails():
321    name = "l_and_ll_files_fails"
322    test_name = name + "_test"
323    genlex(
324        name = name,
325        srcs = ["foo_fails.l", "bar_fails.ll"],
326        tags = ["manual"],
327    )
328    l_and_ll_files_fails_test(
329        name = test_name,
330        target_under_test = name,
331    )
332    return test_name
333
334def flex_test_suite(name):
335    native.test_suite(
336        name = name,
337        tests = [
338            _test_single_l_file_to_c(),
339            _test_single_ll_file_to_cc(),
340            _test_multiple_files_correct_type(),
341            _test_output_arg(),
342            _test_input_arg(),
343            _test_lexopts(),
344            _test_l_and_ll_files_fails(),
345        ],
346    )
347