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	"android/soong/android"
22	"android/soong/cc"
23)
24
25// Test that cc modules can link against vendor_available rust_ffi_rlib/rust_ffi_static libraries.
26func TestVendorLinkage(t *testing.T) {
27	ctx := testRust(t, `
28			cc_binary {
29				name: "fizz_vendor_available",
30				static_libs: ["libfoo_vendor_static"],
31				static_rlibs: ["libfoo_vendor"],
32				vendor_available: true,
33			}
34			cc_binary {
35				name: "fizz_soc_specific",
36				static_rlibs: ["libfoo_vendor"],
37				soc_specific: true,
38			}
39			rust_ffi_rlib {
40				name: "libfoo_vendor",
41				crate_name: "foo",
42				srcs: ["foo.rs"],
43				vendor_available: true,
44			}
45			rust_ffi_static {
46				name: "libfoo_vendor_static",
47				crate_name: "foo",
48				srcs: ["foo.rs"],
49				vendor_available: true,
50			}
51		`)
52
53	vendorBinary := ctx.ModuleForTests("fizz_vendor_available", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
54
55	if !android.InList("libfoo_vendor_static.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
56		t.Errorf("vendorBinary should have a dependency on libfoo_vendor_static.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
57	}
58}
59
60// Test that variants which use the vndk emit the appropriate cfg flag.
61func TestImageCfgFlag(t *testing.T) {
62	ctx := testRust(t, `
63			rust_ffi_shared {
64				name: "libfoo",
65				crate_name: "foo",
66				srcs: ["foo.rs"],
67				vendor_available: true,
68				product_available: true,
69			}
70		`)
71
72	vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Rule("rustc")
73
74	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
75		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
76	}
77	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vendor'") {
78		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
79	}
80	if strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_product'") {
81		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
82	}
83
84	product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_shared").Rule("rustc")
85	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
86		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
87	}
88	if strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vendor'") {
89		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
90	}
91	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_product'") {
92		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
93	}
94
95	system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("rustc")
96	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
97		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
98	}
99	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vendor'") {
100		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
101	}
102	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_product'") {
103		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.Args["rustcFlags"])
104	}
105
106}
107
108// Test that cc modules can link against vendor_ramdisk_available rust_ffi_rlib and rust_ffi_static libraries.
109func TestVendorRamdiskLinkage(t *testing.T) {
110	ctx := testRust(t, `
111			cc_library_shared {
112				name: "libcc_vendor_ramdisk",
113				static_rlibs: ["libfoo_vendor_ramdisk"],
114				static_libs: ["libfoo_static_vendor_ramdisk"],
115				system_shared_libs: [],
116				vendor_ramdisk_available: true,
117			}
118			rust_ffi_rlib {
119				name: "libfoo_vendor_ramdisk",
120				crate_name: "foo",
121				srcs: ["foo.rs"],
122				vendor_ramdisk_available: true,
123			}
124			rust_ffi_static {
125				name: "libfoo_static_vendor_ramdisk",
126				crate_name: "foo",
127				srcs: ["foo.rs"],
128				vendor_ramdisk_available: true,
129			}
130		`)
131
132	vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_shared").Module().(*cc.Module)
133
134	if !android.InList("libfoo_static_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
135		t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_static_vendor_ramdisk")
136	}
137}
138
139// Test that prebuilt libraries cannot be made vendor available.
140func TestForbiddenVendorLinkage(t *testing.T) {
141	testRustError(t, "Rust prebuilt modules not supported for non-system images.", `
142		rust_prebuilt_library {
143			name: "librust_prebuilt",
144			crate_name: "rust_prebuilt",
145			rlib: {
146				srcs: ["libtest.rlib"],
147			},
148			dylib: {
149				srcs: ["libtest.so"],
150			},
151			vendor: true,
152		}
153       `)
154}
155
156func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant, expected string) {
157	mod := ctx.ModuleForTests(name, variant).Module().(*Module)
158	partitionDefined := false
159	checkPartition := func(specific bool, partition string) {
160		if specific {
161			if expected != partition && !partitionDefined {
162				// The variant is installed to the 'partition'
163				t.Errorf("%s variant of %q must not be installed to %s partition", variant, name, partition)
164			}
165			partitionDefined = true
166		} else {
167			// The variant is not installed to the 'partition'
168			if expected == partition {
169				t.Errorf("%s variant of %q must be installed to %s partition", variant, name, partition)
170			}
171		}
172	}
173	socSpecific := func(m *Module) bool {
174		return m.SocSpecific()
175	}
176	deviceSpecific := func(m *Module) bool {
177		return m.DeviceSpecific()
178	}
179	productSpecific := func(m *Module) bool {
180		return m.ProductSpecific() || m.productSpecificModuleContext()
181	}
182	systemExtSpecific := func(m *Module) bool {
183		return m.SystemExtSpecific()
184	}
185	checkPartition(socSpecific(mod), "vendor")
186	checkPartition(deviceSpecific(mod), "odm")
187	checkPartition(productSpecific(mod), "product")
188	checkPartition(systemExtSpecific(mod), "system_ext")
189	if !partitionDefined && expected != "system" {
190		t.Errorf("%s variant of %q is expected to be installed to %s partition,"+
191			" but installed to system partition", variant, name, expected)
192	}
193}
194
195func TestInstallPartition(t *testing.T) {
196	t.Parallel()
197	t.Helper()
198	ctx := testRust(t, `
199		rust_binary {
200			name: "sample_system",
201			crate_name: "sample",
202			srcs: ["foo.rs"],
203		}
204		rust_binary {
205			name: "sample_system_ext",
206			crate_name: "sample",
207			srcs: ["foo.rs"],
208			system_ext_specific: true,
209		}
210		rust_binary {
211			name: "sample_product",
212			crate_name: "sample",
213			srcs: ["foo.rs"],
214			product_specific: true,
215		}
216		rust_binary {
217			name: "sample_vendor",
218			crate_name: "sample",
219			srcs: ["foo.rs"],
220			vendor: true,
221		}
222		rust_binary {
223			name: "sample_odm",
224			crate_name: "sample",
225			srcs: ["foo.rs"],
226			device_specific: true,
227		}
228		rust_binary {
229			name: "sample_all_available",
230			crate_name: "sample",
231			srcs: ["foo.rs"],
232			vendor_available: true,
233			product_available: true,
234		}
235	`)
236
237	checkInstallPartition(t, ctx, "sample_system", binaryCoreVariant, "system")
238	checkInstallPartition(t, ctx, "sample_system_ext", binaryCoreVariant, "system_ext")
239	checkInstallPartition(t, ctx, "sample_product", binaryProductVariant, "product")
240	checkInstallPartition(t, ctx, "sample_vendor", binaryVendorVariant, "vendor")
241	checkInstallPartition(t, ctx, "sample_odm", binaryVendorVariant, "odm")
242
243	checkInstallPartition(t, ctx, "sample_all_available", binaryCoreVariant, "system")
244}
245