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 TestShTestHost_dataDeviceModules(t *testing.T) {
180	ctx, config := testShBinary(t, `
181		sh_test_host {
182			name: "foo",
183			src: "test.sh",
184			data_device_bins: ["bar"],
185			data_device_libs: ["libbar"],
186		}
187
188		cc_binary {
189			name: "bar",
190			shared_libs: ["libbar"],
191			no_libcrt: true,
192			nocrt: true,
193			system_shared_libs: [],
194			stl: "none",
195		}
196
197		cc_library {
198			name: "libbar",
199			no_libcrt: true,
200			nocrt: true,
201			system_shared_libs: [],
202			stl: "none",
203		}
204	`)
205
206	buildOS := config.BuildOS.String()
207	variant := buildOS + "_x86_64"
208	foo := ctx.ModuleForTests("foo", variant)
209
210	relocated := foo.Output(filepath.Join("out/soong/.intermediates/foo", variant, "relocated/lib64/libbar.so"))
211	expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so"
212	android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
213
214	mod := foo.Module().(*ShTest)
215	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
216	expectedData := []string{
217		"out/soong/.intermediates/bar/android_arm64_armv8-a/:bar",
218		// libbar has been relocated, and so has a variant that matches the host arch.
219		"out/soong/.intermediates/foo/" + variant + "/relocated/:lib64/libbar.so",
220	}
221	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
222	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
223}
224
225func TestShTestHost_dataDeviceModulesAutogenTradefedConfig(t *testing.T) {
226	ctx, config := testShBinary(t, `
227		sh_test_host {
228			name: "foo",
229			src: "test.sh",
230			data_device_bins: ["bar"],
231			data_device_libs: ["libbar"],
232		}
233
234		cc_binary {
235			name: "bar",
236			shared_libs: ["libbar"],
237			no_libcrt: true,
238			nocrt: true,
239			system_shared_libs: [],
240			stl: "none",
241		}
242
243		cc_library {
244			name: "libbar",
245			no_libcrt: true,
246			nocrt: true,
247			system_shared_libs: [],
248			stl: "none",
249		}
250	`)
251
252	buildOS := config.BuildOS.String()
253	fooModule := ctx.ModuleForTests("foo", buildOS+"_x86_64")
254
255	expectedBinAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />`
256	autogen := fooModule.Rule("autogen")
257	if !strings.Contains(autogen.Args["extraConfigs"], expectedBinAutogenConfig) {
258		t.Errorf("foo extraConfings %v does not contain %q", autogen.Args["extraConfigs"], expectedBinAutogenConfig)
259	}
260}
261
262func TestShTestHost_javaData(t *testing.T) {
263	ctx, config := testShBinary(t, `
264		sh_test_host {
265			name: "foo",
266			src: "test.sh",
267			filename: "test.sh",
268			data: [
269				"testdata/data1",
270				"testdata/sub/data2",
271			],
272			java_data: [
273				"javalib",
274			],
275		}
276
277		java_library_host {
278			name: "javalib",
279			srcs: [],
280		}
281	`)
282	buildOS := ctx.Config().BuildOS.String()
283	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
284	if !mod.Host() {
285		t.Errorf("host bit is not set for a sh_test_host module.")
286	}
287	expectedData := []string{
288		":testdata/data1",
289		":testdata/sub/data2",
290		"out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar",
291	}
292
293	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
294	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
295	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
296}
297