xref: /aosp_15_r20/build/soong/sh/sh_binary_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1package sh
2
3import (
4	"os"
5	"path/filepath"
6	"strconv"
7	"strings"
8	"testing"
9
10	"android/soong/android"
11	"android/soong/cc"
12	"android/soong/java"
13)
14
15func TestMain(m *testing.M) {
16	os.Exit(m.Run())
17}
18
19var prepareForShTest = android.GroupFixturePreparers(
20	cc.PrepareForTestWithCcBuildComponents,
21	java.PrepareForTestWithJavaDefaultModules,
22	PrepareForTestWithShBuildComponents,
23	android.FixtureMergeMockFs(android.MockFS{
24		"test.sh":            nil,
25		"testdata/data1":     nil,
26		"testdata/sub/data2": nil,
27	}),
28)
29
30// testShBinary runs tests using the prepareForShTest
31//
32// Do not add any new usages of this, instead use the prepareForShTest directly as it makes it much
33// easier to customize the test behavior.
34//
35// If it is necessary to customize the behavior of an existing test that uses this then please first
36// convert the test to using prepareForShTest first and then in a following change add the
37// appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify
38// that it did not change the test behavior unexpectedly.
39//
40// deprecated
41func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) {
42	bp = bp + cc.GatherRequiredDepsForTest(android.Android)
43
44	result := prepareForShTest.RunTestWithBp(t, bp)
45
46	return result.TestContext, result.Config
47}
48
49func TestShTestSubDir(t *testing.T) {
50	result := android.GroupFixturePreparers(
51		prepareForShTest,
52		android.FixtureModifyConfig(android.SetKatiEnabledForTests),
53	).RunTestWithBp(t, `
54		sh_test {
55			name: "foo",
56			src: "test.sh",
57			sub_dir: "foo_test"
58		}
59	`)
60
61	mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
62
63	entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0]
64
65	expectedPath := "out/target/product/test_device/data/nativetest64/foo_test"
66	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
67	android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", result.Config, expectedPath, actualPath)
68}
69
70func TestShTest(t *testing.T) {
71	result := android.GroupFixturePreparers(
72		prepareForShTest,
73		android.FixtureModifyConfig(android.SetKatiEnabledForTests),
74	).RunTestWithBp(t, `
75		sh_test {
76			name: "foo",
77			src: "test.sh",
78			filename: "test.sh",
79			data: [
80				"testdata/data1",
81				"testdata/sub/data2",
82			],
83		}
84	`)
85
86	mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
87
88	entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0]
89
90	expectedPath := "out/target/product/test_device/data/nativetest64/foo"
91	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
92	android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", result.Config, expectedPath, actualPath)
93
94	expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
95	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
96	android.AssertDeepEquals(t, "LOCAL_TEST_DATA", expectedData, actualData)
97}
98
99func TestShTest_dataModules(t *testing.T) {
100	ctx, config := testShBinary(t, `
101		sh_test {
102			name: "foo",
103			src: "test.sh",
104			host_supported: true,
105			data_bins: ["bar"],
106			data_libs: ["libbar"],
107		}
108
109		cc_binary {
110			name: "bar",
111			host_supported: true,
112			shared_libs: ["libbar"],
113			no_libcrt: true,
114			nocrt: true,
115			system_shared_libs: [],
116			stl: "none",
117		}
118
119		cc_library {
120			name: "libbar",
121			host_supported: true,
122			no_libcrt: true,
123			nocrt: true,
124			system_shared_libs: [],
125			stl: "none",
126		}
127	`)
128
129	buildOS := config.BuildOS.String()
130	arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"}
131	for _, arch := range arches {
132		variant := ctx.ModuleForTests("foo", arch)
133
134		libExt := ".so"
135		if arch == "darwin_x86_64" {
136			libExt = ".dylib"
137		}
138		relocated := variant.Output(filepath.Join("out/soong/.intermediates/foo", arch, "relocated/lib64/libbar"+libExt))
139		expectedInput := "out/soong/.intermediates/libbar/" + arch + "_shared/libbar" + libExt
140		android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
141
142		mod := variant.Module().(*ShTest)
143		entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
144		expectedData := []string{
145			filepath.Join("out/soong/.intermediates/bar", arch, ":bar"),
146			filepath.Join("out/soong/.intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
147		}
148		actualData := entries.EntryMap["LOCAL_TEST_DATA"]
149		android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
150	}
151}
152
153func TestShTestHost(t *testing.T) {
154	ctx, _ := testShBinary(t, `
155		sh_test_host {
156			name: "foo",
157			src: "test.sh",
158			filename: "test.sh",
159			data: [
160				"testdata/data1",
161				"testdata/sub/data2",
162			],
163			test_options: {
164				unit_test: true,
165			},
166		}
167	`)
168
169	buildOS := ctx.Config().BuildOS.String()
170	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
171	if !mod.Host() {
172		t.Errorf("host bit is not set for a sh_test_host module.")
173	}
174	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
175	actualData, _ := strconv.ParseBool(entries.EntryMap["LOCAL_IS_UNIT_TEST"][0])
176	android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData)
177}
178
179func TestShTestExtraTestConfig(t *testing.T) {
180	result, _ := testShBinary(t, `
181		sh_test {
182			name: "foo",
183			src: "test.sh",
184			filename: "test.sh",
185                        extra_test_configs: ["config1.xml", "config2.xml"],
186		}
187	`)
188
189	mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
190	entries := android.AndroidMkEntriesForTest(t, result, mod)[0]
191	actualData := entries.EntryMap["LOCAL_EXTRA_FULL_TEST_CONFIGS"]
192	android.AssertStringPathsRelativeToTopEquals(t, "extra_configs", result.Config(), []string{"config1.xml", "config2.xml"}, actualData)
193}
194
195func TestShTestHost_dataDeviceModules(t *testing.T) {
196	ctx, config := testShBinary(t, `
197		sh_test_host {
198			name: "foo",
199			src: "test.sh",
200			data_device_bins: ["bar"],
201			data_device_libs: ["libbar"],
202		}
203
204		cc_binary {
205			name: "bar",
206			shared_libs: ["libbar"],
207			no_libcrt: true,
208			nocrt: true,
209			system_shared_libs: [],
210			stl: "none",
211		}
212
213		cc_library {
214			name: "libbar",
215			no_libcrt: true,
216			nocrt: true,
217			system_shared_libs: [],
218			stl: "none",
219		}
220	`)
221
222	buildOS := config.BuildOS.String()
223	variant := buildOS + "_x86_64"
224	foo := ctx.ModuleForTests("foo", variant)
225
226	relocated := foo.Output(filepath.Join("out/soong/.intermediates/foo", variant, "relocated/lib64/libbar.so"))
227	expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so"
228	android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
229
230	mod := foo.Module().(*ShTest)
231	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
232	expectedData := []string{
233		"out/soong/.intermediates/bar/android_arm64_armv8-a/:bar",
234		// libbar has been relocated, and so has a variant that matches the host arch.
235		"out/soong/.intermediates/foo/" + variant + "/relocated/:lib64/libbar.so",
236	}
237	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
238	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
239}
240
241func TestShTestHost_dataDeviceModulesAutogenTradefedConfig(t *testing.T) {
242	ctx, config := testShBinary(t, `
243		sh_test_host {
244			name: "foo",
245			src: "test.sh",
246			data_device_bins: ["bar"],
247			data_device_libs: ["libbar"],
248		}
249
250		cc_binary {
251			name: "bar",
252			shared_libs: ["libbar"],
253			no_libcrt: true,
254			nocrt: true,
255			system_shared_libs: [],
256			stl: "none",
257		}
258
259		cc_library {
260			name: "libbar",
261			no_libcrt: true,
262			nocrt: true,
263			system_shared_libs: [],
264			stl: "none",
265		}
266	`)
267
268	buildOS := config.BuildOS.String()
269	fooModule := ctx.ModuleForTests("foo", buildOS+"_x86_64")
270
271	expectedBinAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />`
272	autogen := fooModule.Rule("autogen")
273	if !strings.Contains(autogen.Args["extraConfigs"], expectedBinAutogenConfig) {
274		t.Errorf("foo extraConfings %v does not contain %q", autogen.Args["extraConfigs"], expectedBinAutogenConfig)
275	}
276}
277
278func TestShTestHost_javaData(t *testing.T) {
279	ctx, config := testShBinary(t, `
280		sh_test_host {
281			name: "foo",
282			src: "test.sh",
283			filename: "test.sh",
284			data: [
285				"testdata/data1",
286				"testdata/sub/data2",
287			],
288			java_data: [
289				"javalib",
290			],
291		}
292
293		java_library_host {
294			name: "javalib",
295			srcs: [],
296		}
297	`)
298	buildOS := ctx.Config().BuildOS.String()
299	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
300	if !mod.Host() {
301		t.Errorf("host bit is not set for a sh_test_host module.")
302	}
303	expectedData := []string{
304		":testdata/data1",
305		":testdata/sub/data2",
306		"out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar",
307	}
308
309	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
310	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
311	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
312}
313
314func TestDefaultsForTests(t *testing.T) {
315	ctx, config := testShBinary(t, `
316		sh_defaults {
317			name: "defaults",
318			src: "test.sh",
319			filename: "test.sh",
320			data: [
321				"testdata/data1",
322				"testdata/sub/data2",
323			],
324		}
325		sh_test_host {
326			name: "foo",
327			defaults: ["defaults"],
328			data: [
329				"testdata/more_data",
330			],
331			java_data: [
332				"javalib",
333			],
334		}
335
336		java_library_host {
337			name: "javalib",
338			srcs: [],
339		}
340
341		sh_test {
342			name: "sh-test",
343			defaults: ["defaults"],
344		}
345
346	`)
347	buildOS := ctx.Config().BuildOS.String()
348	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
349	if !mod.Host() {
350		t.Errorf("host bit is not set for a sh_test_host module.")
351	}
352	expectedData := []string{
353		":testdata/data1",
354		":testdata/sub/data2",
355		":testdata/more_data",
356		"out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar",
357	}
358
359	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
360	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
361	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
362
363	// Just the defaults
364	expectedData = []string{
365		":testdata/data1",
366		":testdata/sub/data2",
367	}
368	mod = ctx.ModuleForTests("sh-test", "android_arm64_armv8-a").Module().(*ShTest)
369	entries = android.AndroidMkEntriesForTest(t, ctx, mod)[0]
370	actualData = entries.EntryMap["LOCAL_TEST_DATA"]
371	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
372}
373
374func TestDefaultsForBinaries(t *testing.T) {
375	ctx, _ := testShBinary(t, `
376		sh_defaults {
377			name: "defaults",
378			src: "test.sh",
379			filename: "test.sh",
380		}
381		sh_binary_host {
382			name: "the-host-binary",
383			defaults: ["defaults"],
384		}
385		sh_binary{
386			name: "the-binary",
387			defaults: ["defaults"],
388		}
389	`)
390	buildOS := ctx.Config().BuildOS.String()
391	mod := ctx.ModuleForTests("the-host-binary", buildOS+"_x86_64").Module().(*ShBinary)
392	if !mod.Host() {
393		t.Errorf("host bit is not set for a sh_binary_host module.")
394	}
395
396	expectedFilename := "test.sh"
397	android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename)
398
399	mod = ctx.ModuleForTests("the-binary", "android_arm64_armv8-a").Module().(*ShBinary)
400	android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename)
401}
402