1package sh
2
3import (
4	"os"
5	"path/filepath"
6	"testing"
7
8	"android/soong/android"
9	"android/soong/cc"
10)
11
12func TestMain(m *testing.M) {
13	os.Exit(m.Run())
14}
15
16var prepareForShTest = android.GroupFixturePreparers(
17	cc.PrepareForTestWithCcBuildComponents,
18	PrepareForTestWithShBuildComponents,
19	android.FixtureMergeMockFs(android.MockFS{
20		"test.sh":            nil,
21		"testdata/data1":     nil,
22		"testdata/sub/data2": nil,
23	}),
24)
25
26// testShBinary runs tests using the prepareForShTest
27//
28// Do not add any new usages of this, instead use the prepareForShTest directly as it makes it much
29// easier to customize the test behavior.
30//
31// If it is necessary to customize the behavior of an existing test that uses this then please first
32// convert the test to using prepareForShTest first and then in a following change add the
33// appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify
34// that it did not change the test behavior unexpectedly.
35//
36// deprecated
37func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) {
38	result := prepareForShTest.RunTestWithBp(t, bp)
39
40	return result.TestContext, result.Config
41}
42
43func TestShTestSubDir(t *testing.T) {
44	ctx, config := testShBinary(t, `
45		sh_test {
46			name: "foo",
47			src: "test.sh",
48			sub_dir: "foo_test"
49		}
50	`)
51
52	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
53
54	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
55
56	expectedPath := "out/target/product/test_device/data/nativetest64/foo_test"
57	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
58	android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", config, expectedPath, actualPath)
59}
60
61func TestShTest(t *testing.T) {
62	ctx, config := testShBinary(t, `
63		sh_test {
64			name: "foo",
65			src: "test.sh",
66			filename: "test.sh",
67			data: [
68				"testdata/data1",
69				"testdata/sub/data2",
70			],
71		}
72	`)
73
74	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
75
76	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
77
78	expectedPath := "out/target/product/test_device/data/nativetest64/foo"
79	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
80	android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", config, expectedPath, actualPath)
81
82	expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
83	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
84	android.AssertDeepEquals(t, "LOCAL_TEST_DATA", expectedData, actualData)
85}
86
87func TestShTest_dataModules(t *testing.T) {
88	ctx, config := testShBinary(t, `
89		sh_test {
90			name: "foo",
91			src: "test.sh",
92			host_supported: true,
93			data_bins: ["bar"],
94			data_libs: ["libbar"],
95		}
96
97		cc_binary {
98			name: "bar",
99			host_supported: true,
100			shared_libs: ["libbar"],
101			no_libcrt: true,
102			nocrt: true,
103			system_shared_libs: [],
104			stl: "none",
105		}
106
107		cc_library {
108			name: "libbar",
109			host_supported: true,
110			no_libcrt: true,
111			nocrt: true,
112			system_shared_libs: [],
113			stl: "none",
114		}
115	`)
116
117	buildOS := android.BuildOs.String()
118	arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"}
119	for _, arch := range arches {
120		variant := ctx.ModuleForTests("foo", arch)
121
122		libExt := ".so"
123		if arch == "darwin_x86_64" {
124			libExt = ".dylib"
125		}
126		relocated := variant.Output("relocated/lib64/libbar" + libExt)
127		expectedInput := "out/soong/.intermediates/libbar/" + arch + "_shared/libbar" + libExt
128		android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
129
130		mod := variant.Module().(*ShTest)
131		entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
132		expectedData := []string{
133			filepath.Join("out/soong/.intermediates/bar", arch, ":bar"),
134			filepath.Join("out/soong/.intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
135		}
136		actualData := entries.EntryMap["LOCAL_TEST_DATA"]
137		android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
138	}
139}
140
141func TestShTestHost(t *testing.T) {
142	ctx, _ := testShBinary(t, `
143		sh_test_host {
144			name: "foo",
145			src: "test.sh",
146			filename: "test.sh",
147			data: [
148				"testdata/data1",
149				"testdata/sub/data2",
150			],
151		}
152	`)
153
154	buildOS := android.BuildOs.String()
155	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
156	if !mod.Host() {
157		t.Errorf("host bit is not set for a sh_test_host module.")
158	}
159}
160
161func TestShTestHost_dataDeviceModules(t *testing.T) {
162	ctx, config := testShBinary(t, `
163		sh_test_host {
164			name: "foo",
165			src: "test.sh",
166			data_device_bins: ["bar"],
167			data_device_libs: ["libbar"],
168		}
169
170		cc_binary {
171			name: "bar",
172			shared_libs: ["libbar"],
173			no_libcrt: true,
174			nocrt: true,
175			system_shared_libs: [],
176			stl: "none",
177		}
178
179		cc_library {
180			name: "libbar",
181			no_libcrt: true,
182			nocrt: true,
183			system_shared_libs: [],
184			stl: "none",
185		}
186	`)
187
188	buildOS := android.BuildOs.String()
189	variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
190
191	relocated := variant.Output("relocated/lib64/libbar.so")
192	expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so"
193	android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
194
195	mod := variant.Module().(*ShTest)
196	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
197	expectedData := []string{
198		"out/soong/.intermediates/bar/android_arm64_armv8-a/:bar",
199		// libbar has been relocated, and so has a variant that matches the host arch.
200		"out/soong/.intermediates/foo/" + buildOS + "_x86_64/relocated/:lib64/libbar.so",
201	}
202	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
203	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
204}
205