blob: f61bff6ed11ccc71be094fdff76ea15bd24ce8ae [file] [log] [blame]
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00001#!/bin/bash
2# Part of the Crubit project, under the Apache License v2.0 with LLVM
3# Exceptions. See /LICENSE for license information.
4# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5
6
7source gbash.sh || exit
8source module gbash_unit.sh
9
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000010readonly RS_BINDINGS_FROM_CC="${RUNFILES}/rs_bindings_from_cc/rs_bindings_from_cc"
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -080011readonly DEFAULT_CLANG_FORMAT_EXE_PATH="${RUNFILES}/google3/third_party/crosstool/google3_users/clang-format"
Googler83b6d7f2023-02-14 05:18:49 -080012readonly DEFAULT_RUSTFMT_EXE_PATH="nowhere/llvm/rust/rustfmt_for_crubit_aspects"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000013
Marcel Hlopko7aa38a72021-11-11 07:39:51 +000014function quote_escape() {
15 sed 's/"/\\"/g'
16}
17
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +000018function test::cmd_line_api() {
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000019 EXPECT_FAIL "${RS_BINDINGS_FROM_CC}" "generator should return non-zero with no arguments"
20 EXPECT_SUCCEED \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080021 "${RS_BINDINGS_FROM_CC} 2>&1 | grep 'please specify --target' > /dev/null" \
22 "generator should show help message for --target"
23 EXPECT_SUCCEED \
24 "${RS_BINDINGS_FROM_CC} --target=//:target 2>&1 | grep 'please specify --rs_out' > /dev/null" \
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000025 "generator should show help message for --rs_out"
26 EXPECT_SUCCEED \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080027 "${RS_BINDINGS_FROM_CC} --target=//:target --rs_out=/foo 2>&1 | \
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000028 grep 'please specify --cc_out' > /dev/null" \
29 "generator should show help message for --cc_out"
30
31 local rs_out="${TEST_TMPDIR}/rs_api.rs"
32 local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
Marcel Hlopko45b60ef2021-08-13 13:37:43 +000033
34 EXPECT_SUCCEED \
35 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080036 --target=//:target \
Marcel Hlopko45b60ef2021-08-13 13:37:43 +000037 --rs_out=\"${rs_out}\" \
38 --cc_out=\"${cc_out}\" 2>&1 | \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -070039 grep 'please specify --crubit_support_path' > /dev/null" \
40 "generator should show help message for --crubit_support_path"
41
42 EXPECT_SUCCEED \
43 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080044 --target=//:target \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -070045 --rs_out=\"${rs_out}\" \
46 --cc_out=\"${cc_out}\" 2>&1 \
47 --crubit_support_path=test/crubit/support/path | \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -080048 grep 'please specify --clang_format_exe_path' > /dev/null" \
49 "generator should show help message for --clang_format_exe_path"
50
51 EXPECT_SUCCEED \
52 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080053 --target=//:target \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -080054 --rs_out=\"${rs_out}\" \
55 --cc_out=\"${cc_out}\" 2>&1 \
56 --crubit_support_path=test/crubit/support/path \
57 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" | \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -070058 grep 'please specify --rustfmt_exe_path' > /dev/null" \
59 "generator should show help message for --rustfmt_exe_path"
60
61 EXPECT_SUCCEED \
62 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080063 --target=//:target \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -070064 --rs_out=\"${rs_out}\" \
65 --cc_out=\"${cc_out}\" 2>&1 \
66 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -080067 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -070068 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" | \
Lukasz Anforowicz016eb362022-03-02 18:37:03 +000069 grep 'please specify --public_headers' > /dev/null" \
Marcel Hlopko45b60ef2021-08-13 13:37:43 +000070 "generator should show help message for --public_headers"
71
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000072 local hdr="${TEST_TMPDIR}/hello_world.h"
73 echo "int foo();" > "${hdr}"
Marcel Hlopko7aa38a72021-11-11 07:39:51 +000074
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000075 EXPECT_SUCCEED \
76 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080077 --target=//:target \
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000078 --rs_out=\"${rs_out}\" \
79 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -070080 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -080081 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -070082 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Marcel Hlopko7aa38a72021-11-11 07:39:51 +000083 --public_headers=\"${hdr}\" 2>&1 | \
84 grep 'please specify --targets_and_headers' > /dev/null" \
85 "generator should show help message for --targets_and_headers"
86
87 local json
88 json="$(cat <<-EOT
89 [{"t": "//foo/bar:baz", "h": ["${hdr}"]}]
90EOT
91)"
92
93 EXPECT_SUCCEED \
94 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -080095 --target=//:target \
Marcel Hlopko7aa38a72021-11-11 07:39:51 +000096 --rs_out=\"${rs_out}\" \
97 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -070098 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -080099 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700100 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000101 --public_headers=\"${hdr}\" \
102 --targets_and_headers=\"$(echo "${json}" | quote_escape)\""
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +0000103
104 EXPECT_FILE_NOT_EMPTY "${rs_out}"
105 EXPECT_FILE_NOT_EMPTY "${cc_out}"
106}
107
Marcel Hlopko42d9e262021-11-26 16:09:20 +0000108function test::do_nothing() {
109 local rs_out="${TEST_TMPDIR}/rs_api.rs"
110 local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
Lukasz Anforowicz016eb362022-03-02 18:37:03 +0000111 local hdr="no_such_file.h"
112 local json
113 json="$(cat <<-EOT
114 [{"t": "//foo/bar:baz", "h": ["${hdr}"]}]
115EOT
116)"
Marcel Hlopko42d9e262021-11-26 16:09:20 +0000117
118 EXPECT_SUCCEED \
119 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -0800120 --target=//:target \
Marcel Hlopko42d9e262021-11-26 16:09:20 +0000121 --rs_out=\"${rs_out}\" \
122 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700123 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -0800124 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700125 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Lukasz Anforowicz016eb362022-03-02 18:37:03 +0000126 --public_headers=\"${hdr}\" \
127 --targets_and_headers=\"$(echo "${json}" | quote_escape)\" \
Marcel Hlopko42d9e262021-11-26 16:09:20 +0000128 --do_nothing"
129
130 EXPECT_FILE_NOT_EMPTY "${rs_out}"
131 EXPECT_FILE_NOT_EMPTY "${cc_out}"
132
133 EXPECT_SUCCEED "cat \"${rs_out}\" | grep '// intentionally left empty because --do_nothing was passed.'"
134 EXPECT_SUCCEED "cat \"${cc_out}\" | grep '// intentionally left empty because --do_nothing was passed.'"
135}
136
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +0000137function test::tool_returns_nonzero_on_invalid_input() {
138 local rs_out="${TEST_TMPDIR}/rs_api.rs"
139 local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
Lukasz Anforowicz016eb362022-03-02 18:37:03 +0000140 rm -rf "$rs_out"
141 rm -rf "$cc_out"
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +0000142
143 local hdr="${TEST_TMPDIR}/hello_world.h"
144 echo "int foo(); But this is not C++;" > "${hdr}"
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000145 local json
146 json="$(cat <<-EOT
147 [{"t": "//foo/bar:baz", "h": ["${hdr}"]}]
148EOT
149)"
150
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +0000151 EXPECT_FAIL \
152 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -0800153 --target=//:target \
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +0000154 --rs_out=\"${rs_out}\" \
155 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700156 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -0800157 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700158 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000159 --public_headers=\"${hdr}\" \
160 --targets_and_headers=\"$(echo "${json}" | quote_escape)\" 2>&1"
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +0000161
Lukasz Anforowicz016eb362022-03-02 18:37:03 +0000162 # No output files should be created if the C++ input was invalid.
Marcel Hlopko19f2ebf2021-08-18 09:35:05 +0000163 CHECK_FILE_NOT_EXISTS "${rs_out}"
164 CHECK_FILE_NOT_EXISTS "${cc_out}"
165}
166
Marcel Hlopkoaca042a2021-10-26 15:12:36 +0000167function test::public_headers() {
168 local rs_out="${TEST_TMPDIR}/rs_api.rs"
169 local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
170
171 local header_1="${TEST_TMPDIR}/header_1.h"
172 local header_2="${TEST_TMPDIR}/header_2.h"
173 echo "int function_1();" > "${header_1}"
174 echo "int function_2();" > "${header_2}"
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000175
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000176 local json
177 json="$(cat <<-EOT
178 [{"t": "//foo/bar:baz", "h": ["${header_1}", "${header_2}"]}]
179EOT
180)"
181
Marcel Hlopkoaca042a2021-10-26 15:12:36 +0000182 EXPECT_SUCCEED \
183 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -0800184 --target=//foo/bar:baz \
Marcel Hlopkoaca042a2021-10-26 15:12:36 +0000185 --rs_out=\"${rs_out}\" \
186 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700187 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -0800188 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700189 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Marcel Hlopkoaca042a2021-10-26 15:12:36 +0000190 --public_headers=\"${header_1},${header_2}\" \
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000191 --targets_and_headers=\"$(echo "${json}" | quote_escape)\" 2>&1"
192
Marcel Hlopkoaca042a2021-10-26 15:12:36 +0000193 EXPECT_SUCCEED "grep function_1 \"${rs_out}\"" "function_1 was not imported"
194 EXPECT_SUCCEED "grep function_2 \"${rs_out}\"" "function_2 was not imported"
195}
196
Lukasz Anforowicz54ff3182022-05-06 07:17:58 -0700197function test::rustfmt_config_path() {
198 local rs_out="${TEST_TMPDIR}/rs_api.rs"
199 local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
200
201 local hdr="${TEST_TMPDIR}/hello_world.h"
202 echo "int MyFunction(int arg1, int arg2);" > "${hdr}"
203
204 local json
205 json="$(cat <<-EOT
206 [{"t": "//foo/bar:baz", "h": ["${hdr}"]}]
207EOT
208)"
209
210 #########################################################
211 # Testing the default `rustfmt` config.
212 EXPECT_SUCCEED \
213 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -0800214 --target=//foo/bar:baz \
Lukasz Anforowicz54ff3182022-05-06 07:17:58 -0700215 --rs_out=\"${rs_out}\" \
216 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700217 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -0800218 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700219 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Lukasz Anforowicz54ff3182022-05-06 07:17:58 -0700220 --public_headers=\"${hdr}\" \
221 --targets_and_headers=\"$(echo "${json}" | quote_escape)\""
222
223 EXPECT_FILE_NOT_EMPTY "${rs_out}"
224
225 # Expecting:
226 # pub fn MyFunction(arg1: i32, arg2: i32) -> i32
227 EXPECT_SUCCEED \
228 "grep \"MyFunction.*arg1:.*i32,.*arg2:.*i32.*)\" \"${rs_out}\"" \
229 "Verify function args are on single line when using default rustfmt config (1)"
230 EXPECT_FAIL \
231 "grep \"^[^a-z]*arg1:[^a-z]*i32,[^a-z]*\\\$\" \"${rs_out}\"" \
232 "Verify function args are *not on single line when using default rustfmt config (2)"
233
234 #########################################################
235 # Testing a custom `rustfmt` config.
236 local rustfmt_config_path="${TEST_TMPDIR}/rustfmt.toml"
237 cat >"${rustfmt_config_path}" <<EOF
238 edition = "2021"
239 version = "Two"
240 fn_args_layout="Vertical"
241EOF
242 EXPECT_SUCCEED \
243 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -0800244 --target=//foo/bar:baz\
Lukasz Anforowicz54ff3182022-05-06 07:17:58 -0700245 --rs_out=\"${rs_out}\" \
246 --cc_out=\"${cc_out}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700247 --crubit_support_path=test/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -0800248 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700249 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Lukasz Anforowicz54ff3182022-05-06 07:17:58 -0700250 --rustfmt_config_path=\"${rustfmt_config_path}\" \
251 --public_headers=\"${hdr}\" \
252 --targets_and_headers=\"$(echo "${json}" | quote_escape)\""
253
254 EXPECT_FILE_NOT_EMPTY "${rs_out}"
255
256 # Expecting:
257 # pub fn MyFunction(
258 # arg1: i32,
259 # arg2: i32,
260 # ) -> i32
261 EXPECT_FAIL \
262 "grep \"MyFunction.*arg1:.*i32,.*arg2:.*i32.*)\" \"${rs_out}\"" \
263 "Verify function args are *not* on single line when using default rustfmt config (1)"
264 EXPECT_SUCCEED \
265 "grep \"^[^a-z]*arg1:[^a-z]*i32,[^a-z]*\\\$\" \"${rs_out}\"" \
266 "Verify function args are *not on single line when using default rustfmt config (2)"
267}
268
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700269function test::crubit_support_path() {
270 local rs_out="${TEST_TMPDIR}/rs_api.rs"
271 local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
272
273 local hdr="${TEST_TMPDIR}/hello_world.h"
274 echo "int MyFunction();" > "${hdr}"
275
276 local json
277 json="$(cat <<-EOT
278 [{"t": "//foo/bar:baz", "h": ["${hdr}"]}]
279EOT
280)"
281
282 EXPECT_SUCCEED \
283 "\"${RS_BINDINGS_FROM_CC}\" \
Devin Jeanpierree87ae2a2023-01-20 12:15:36 -0800284 --target=//foo/bar:baz \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700285 --rs_out=\"${rs_out}\" \
286 --cc_out=\"${cc_out}\" \
287 --crubit_support_path=test/specific/crubit/support/path \
Lukasz Anforowicz5bf49432022-12-12 12:17:24 -0800288 --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \
Lukasz Anforowiczd7d68f02022-05-26 07:41:02 -0700289 --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" \
Lukasz Anforowiczdd907702022-05-06 09:24:07 -0700290 --public_headers=\"${hdr}\" \
291 --targets_and_headers=\"$(echo "${json}" | quote_escape)\""
292
293 EXPECT_FILE_NOT_EMPTY "${cc_out}"
294 EXPECT_SUCCEED \
295 "grep \"#include.*test/specific/crubit/support/path/[a-z]\" \"${cc_out}\"" \
296 "Verify #include paths are based on the argument of --crubit_support_path"
297}
298
Lukasz Anforowicz54ff3182022-05-06 07:17:58 -0700299gbash::unit::main "$@"