1// Copyright 2020 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
15package rust
16
17import (
18	"strings"
19	"testing"
20)
21
22func TestRustBindgen(t *testing.T) {
23	ctx := testRust(t, `
24		rust_bindgen {
25			name: "libbindgen",
26			defaults: ["cc_defaults_flags"],
27			wrapper_src: "src/any.h",
28			crate_name: "bindgen",
29			stem: "libbindgen",
30			source_stem: "bindings",
31			bindgen_flags: ["--bindgen-flag.*"],
32			cflags: ["--clang-flag()"],
33			shared_libs: ["libfoo_shared"],
34			static_libs: ["libfoo_static"],
35			header_libs: ["libfoo_header"],
36		}
37		cc_library_shared {
38			name: "libfoo_shared",
39			export_include_dirs: ["shared_include"],
40		}
41		cc_library_static {
42			name: "libfoo_static",
43			export_include_dirs: ["static_include"],
44		}
45		cc_library_headers {
46			name: "libfoo_header",
47			export_include_dirs: ["header_include"],
48		}
49		cc_defaults {
50			name: "cc_defaults_flags",
51			cflags: ["--default-flag"],
52		}
53	`)
54	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
55	// Ensure that the flags are present and escaped
56	if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") {
57		t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"])
58	}
59	if !strings.Contains(libbindgen.Args["cflags"], "'--clang-flag()'") {
60		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
61	}
62	if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") {
63		t.Errorf("missing shared_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
64	}
65	if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") {
66		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
67	}
68	if !strings.Contains(libbindgen.Args["cflags"], "-Iheader_include") {
69		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
70	}
71	if !strings.Contains(libbindgen.Args["cflags"], "--default-flag") {
72		t.Errorf("rust_bindgen missing cflags defined in cc_defaults: cflags %#v", libbindgen.Args["cflags"])
73	}
74}
75
76func TestRustBindgenCustomBindgen(t *testing.T) {
77	ctx := testRust(t, `
78		rust_bindgen {
79			name: "libbindgen",
80			wrapper_src: "src/any.h",
81			crate_name: "bindgen",
82			stem: "libbindgen",
83			source_stem: "bindings",
84			custom_bindgen: "my_bindgen"
85		}
86		rust_binary_host {
87			name: "my_bindgen",
88			srcs: ["foo.rs"],
89		}
90	`)
91
92	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
93
94	// The rule description should contain the custom binary name rather than bindgen, so checking the description
95	// should be sufficient.
96	if !strings.Contains(libbindgen.Description, "my_bindgen") {
97		t.Errorf("Custom bindgen binary %s not used for libbindgen: rule description %#v", "my_bindgen",
98			libbindgen.Description)
99	}
100}
101
102func TestRustBindgenStdVersions(t *testing.T) {
103	testRustError(t, "c_std and cpp_std cannot both be defined at the same time.", `
104		rust_bindgen {
105			name: "libbindgen",
106			wrapper_src: "src/any.h",
107			crate_name: "bindgen",
108			stem: "libbindgen",
109			source_stem: "bindings",
110			c_std: "somevalue",
111			cpp_std: "somevalue",
112		}
113	`)
114
115	ctx := testRust(t, `
116		rust_bindgen {
117			name: "libbindgen_cstd",
118			wrapper_src: "src/any.h",
119			crate_name: "bindgen",
120			stem: "libbindgen",
121			source_stem: "bindings",
122			c_std: "foo"
123		}
124		rust_bindgen {
125			name: "libbindgen_cppstd",
126			wrapper_src: "src/any.h",
127			crate_name: "bindgen",
128			stem: "libbindgen",
129			source_stem: "bindings",
130			cpp_std: "foo"
131		}
132	`)
133
134	libbindgen_cstd := ctx.ModuleForTests("libbindgen_cstd", "android_arm64_armv8-a_source").Output("bindings.rs")
135	libbindgen_cppstd := ctx.ModuleForTests("libbindgen_cppstd", "android_arm64_armv8-a_source").Output("bindings.rs")
136
137	if !strings.Contains(libbindgen_cstd.Args["cflags"], "-std=foo") {
138		t.Errorf("c_std value not passed in to rust_bindgen as a clang flag")
139	}
140
141	if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-std=foo") {
142		t.Errorf("cpp_std value not passed in to rust_bindgen as a clang flag")
143	}
144}
145
146func TestBindgenDisallowedFlags(t *testing.T) {
147	// Make sure passing '-x c++' to cflags generates an error
148	testRustError(t, "cflags: -x c\\+\\+ should not be specified in cflags.*", `
149		rust_bindgen {
150			name: "libbad_flag",
151			wrapper_src: "src/any.h",
152			crate_name: "bindgen",
153			stem: "libbindgen",
154			source_stem: "bindings",
155			cflags: ["-x c++"]
156		}
157	`)
158
159	// Make sure passing '-std=' to cflags generates an error
160	testRustError(t, "cflags: -std should not be specified in cflags.*", `
161		rust_bindgen {
162			name: "libbad_flag",
163			wrapper_src: "src/any.h",
164			crate_name: "bindgen",
165			stem: "libbindgen",
166			source_stem: "bindings",
167			cflags: ["-std=foo"]
168		}
169	`)
170}
171