• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 
15 package rust
16 
17 import (
18 	"io/ioutil"
19 	"os"
20 	"runtime"
21 	"strings"
22 	"testing"
23 
24 	"android/soong/android"
25 	"android/soong/cc"
26 )
27 
28 var (
29 	buildDir string
30 )
31 
32 func setUp() {
33 	var err error
34 	buildDir, err = ioutil.TempDir("", "soong_rust_test")
35 	if err != nil {
36 		panic(err)
37 	}
38 }
39 
40 func tearDown() {
41 	os.RemoveAll(buildDir)
42 }
43 
44 func TestMain(m *testing.M) {
45 	run := func() int {
46 		setUp()
47 		defer tearDown()
48 
49 		return m.Run()
50 	}
51 
52 	os.Exit(run())
53 }
54 
55 func testConfig(bp string) android.Config {
56 	bp = bp + GatherRequiredDepsForTest()
57 
58 	fs := map[string][]byte{
59 		"foo.rs":     nil,
60 		"src/bar.rs": nil,
61 		"liby.so":    nil,
62 		"libz.so":    nil,
63 	}
64 
65 	cc.GatherRequiredFilesForTest(fs)
66 
67 	return android.TestArchConfig(buildDir, nil, bp, fs)
68 }
69 
70 func testRust(t *testing.T, bp string) *android.TestContext {
71 	// TODO (b/140435149)
72 	if runtime.GOOS != "linux" {
73 		t.Skip("Only the Linux toolchain is supported for Rust")
74 	}
75 
76 	t.Helper()
77 	config := testConfig(bp)
78 
79 	t.Helper()
80 	ctx := CreateTestContext()
81 	ctx.Register(config)
82 
83 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
84 	android.FailIfErrored(t, errs)
85 	_, errs = ctx.PrepareBuildActions(config)
86 	android.FailIfErrored(t, errs)
87 
88 	return ctx
89 }
90 
91 func testRustError(t *testing.T, pattern string, bp string) {
92 	// TODO (b/140435149)
93 	if runtime.GOOS != "linux" {
94 		t.Skip("Only the Linux toolchain is supported for Rust")
95 	}
96 
97 	t.Helper()
98 	config := testConfig(bp)
99 
100 	ctx := CreateTestContext()
101 	ctx.Register(config)
102 
103 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
104 	if len(errs) > 0 {
105 		android.FailIfNoMatchingErrors(t, pattern, errs)
106 		return
107 	}
108 
109 	_, errs = ctx.PrepareBuildActions(config)
110 	if len(errs) > 0 {
111 		android.FailIfNoMatchingErrors(t, pattern, errs)
112 		return
113 	}
114 
115 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
116 }
117 
118 // Test that we can extract the lib name from a lib path.
119 func TestLibNameFromFilePath(t *testing.T) {
120 	libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so")
121 	libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
122 
123 	libBarName := libNameFromFilePath(libBarPath)
124 	libLibName := libNameFromFilePath(libLibPath)
125 
126 	expectedResult := "bar.so"
127 	if libBarName != expectedResult {
128 		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
129 	}
130 
131 	expectedResult = "lib.dylib"
132 	if libLibName != expectedResult {
133 		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath)
134 	}
135 }
136 
137 // Test that we can extract the link path from a lib path.
138 func TestLinkPathFromFilePath(t *testing.T) {
139 	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
140 	libName := linkPathFromFilePath(barPath)
141 	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
142 
143 	if libName != expectedResult {
144 		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
145 	}
146 }
147 
148 // Test to make sure dependencies are being picked up correctly.
149 func TestDepsTracking(t *testing.T) {
150 	ctx := testRust(t, `
151 		rust_library_host_static {
152 			name: "libstatic",
153 			srcs: ["foo.rs"],
154 			crate_name: "static",
155 		}
156 		rust_library_host_shared {
157 			name: "libshared",
158 			srcs: ["foo.rs"],
159 			crate_name: "shared",
160 		}
161 		rust_library_host_dylib {
162 			name: "libdylib",
163 			srcs: ["foo.rs"],
164 			crate_name: "dylib",
165 		}
166 		rust_library_host_rlib {
167 			name: "librlib",
168 			srcs: ["foo.rs"],
169 			crate_name: "rlib",
170 		}
171 		rust_proc_macro {
172 			name: "libpm",
173 			srcs: ["foo.rs"],
174 			crate_name: "pm",
175 		}
176 		rust_binary_host {
177 			name: "fizz-buzz",
178 			dylibs: ["libdylib"],
179 			rlibs: ["librlib"],
180 			proc_macros: ["libpm"],
181 			static_libs: ["libstatic"],
182 			shared_libs: ["libshared"],
183 			srcs: ["foo.rs"],
184 		}
185 	`)
186 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
187 
188 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
189 	if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
190 		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
191 	}
192 
193 	if !android.InList("librlib", module.Properties.AndroidMkRlibs) {
194 		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
195 	}
196 
197 	if !android.InList("libpm", module.Properties.AndroidMkProcMacroLibs) {
198 		t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
199 	}
200 
201 	if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
202 		t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
203 	}
204 
205 	if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) {
206 		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
207 	}
208 }
209 
210 // Test to make sure proc_macros use host variants when building device modules.
211 func TestProcMacroDeviceDeps(t *testing.T) {
212 	ctx := testRust(t, `
213 		rust_library_host_rlib {
214 			name: "libbar",
215 			srcs: ["foo.rs"],
216 			crate_name: "bar",
217 		}
218 		// Make a dummy libstd to let resolution go through
219 		rust_library_dylib {
220 			name: "libstd",
221 			crate_name: "std",
222 			srcs: ["foo.rs"],
223 			no_stdlibs: true,
224 		}
225 		rust_library_dylib {
226 			name: "libterm",
227 			crate_name: "term",
228 			srcs: ["foo.rs"],
229 			no_stdlibs: true,
230 		}
231 		rust_library_dylib {
232 			name: "libtest",
233 			crate_name: "test",
234 			srcs: ["foo.rs"],
235 			no_stdlibs: true,
236 		}
237 		rust_proc_macro {
238 			name: "libpm",
239 			rlibs: ["libbar"],
240 			srcs: ["foo.rs"],
241 			crate_name: "pm",
242 		}
243 		rust_binary {
244 			name: "fizz-buzz",
245 			proc_macros: ["libpm"],
246 			srcs: ["foo.rs"],
247 		}
248 	`)
249 	rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
250 
251 	if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
252 		t.Errorf("Proc_macro is not using host variant of dependent modules.")
253 	}
254 }
255 
256 // Test that no_stdlibs suppresses dependencies on rust standard libraries
257 func TestNoStdlibs(t *testing.T) {
258 	ctx := testRust(t, `
259 		rust_binary {
260 			name: "fizz-buzz",
261 			srcs: ["foo.rs"],
262                         no_stdlibs: true,
263 		}`)
264 	module := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
265 
266 	if android.InList("libstd", module.Properties.AndroidMkDylibs) {
267 		t.Errorf("no_stdlibs did not suppress dependency on libstd")
268 	}
269 }
270