|  | package sh | 
|  |  | 
|  | import ( | 
|  | "os" | 
|  | "path/filepath" | 
|  | "strconv" | 
|  | "strings" | 
|  | "testing" | 
|  |  | 
|  | "android/soong/android" | 
|  | "android/soong/cc" | 
|  | "android/soong/java" | 
|  | ) | 
|  |  | 
|  | func TestMain(m *testing.M) { | 
|  | os.Exit(m.Run()) | 
|  | } | 
|  |  | 
|  | var prepareForShTest = android.GroupFixturePreparers( | 
|  | cc.PrepareForTestWithCcBuildComponents, | 
|  | java.PrepareForTestWithJavaDefaultModules, | 
|  | PrepareForTestWithShBuildComponents, | 
|  | android.FixtureMergeMockFs(android.MockFS{ | 
|  | "test.sh":            nil, | 
|  | "testdata/data1":     nil, | 
|  | "testdata/sub/data2": nil, | 
|  | }), | 
|  | ) | 
|  |  | 
|  | // testShBinary runs tests using the prepareForShTest | 
|  | // | 
|  | // Do not add any new usages of this, instead use the prepareForShTest directly as it makes it much | 
|  | // easier to customize the test behavior. | 
|  | // | 
|  | // If it is necessary to customize the behavior of an existing test that uses this then please first | 
|  | // convert the test to using prepareForShTest first and then in a following change add the | 
|  | // appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify | 
|  | // that it did not change the test behavior unexpectedly. | 
|  | // | 
|  | // deprecated | 
|  | func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) { | 
|  | bp = bp + cc.GatherRequiredDepsForTest(android.Android) | 
|  |  | 
|  | result := prepareForShTest.RunTestWithBp(t, bp) | 
|  |  | 
|  | return result.TestContext, result.Config | 
|  | } | 
|  |  | 
|  | func TestShTestSubDir(t *testing.T) { | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForShTest, | 
|  | android.FixtureModifyConfig(android.SetKatiEnabledForTests), | 
|  | ).RunTestWithBp(t, ` | 
|  | sh_test { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | sub_dir: "foo_test" | 
|  | } | 
|  | `) | 
|  |  | 
|  | mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest) | 
|  |  | 
|  | entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] | 
|  |  | 
|  | expectedPath := "out/target/product/test_device/data/nativetest64/foo_test" | 
|  | actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0] | 
|  | android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", result.Config, expectedPath, actualPath) | 
|  | } | 
|  |  | 
|  | func TestShTest(t *testing.T) { | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForShTest, | 
|  | android.FixtureModifyConfig(android.SetKatiEnabledForTests), | 
|  | ).RunTestWithBp(t, ` | 
|  | sh_test { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | filename: "test.sh", | 
|  | data: [ | 
|  | "testdata/data1", | 
|  | "testdata/sub/data2", | 
|  | ], | 
|  | } | 
|  | `) | 
|  |  | 
|  | mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest) | 
|  |  | 
|  | entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] | 
|  |  | 
|  | expectedPath := "out/target/product/test_device/data/nativetest64/foo" | 
|  | actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0] | 
|  | android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", result.Config, expectedPath, actualPath) | 
|  |  | 
|  | expectedData := []string{":testdata/data1", ":testdata/sub/data2"} | 
|  | actualData := entries.EntryMap["LOCAL_TEST_DATA"] | 
|  | android.AssertDeepEquals(t, "LOCAL_TEST_DATA", expectedData, actualData) | 
|  | } | 
|  |  | 
|  | func TestShTest_dataModules(t *testing.T) { | 
|  | ctx, config := testShBinary(t, ` | 
|  | sh_test { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | host_supported: true, | 
|  | data_bins: ["bar"], | 
|  | data_libs: ["libbar"], | 
|  | } | 
|  |  | 
|  | cc_binary { | 
|  | name: "bar", | 
|  | host_supported: true, | 
|  | shared_libs: ["libbar"], | 
|  | no_libcrt: true, | 
|  | nocrt: true, | 
|  | system_shared_libs: [], | 
|  | stl: "none", | 
|  | } | 
|  |  | 
|  | cc_library { | 
|  | name: "libbar", | 
|  | host_supported: true, | 
|  | no_libcrt: true, | 
|  | nocrt: true, | 
|  | system_shared_libs: [], | 
|  | stl: "none", | 
|  | } | 
|  | `) | 
|  |  | 
|  | buildOS := config.BuildOS.String() | 
|  | arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"} | 
|  | for _, arch := range arches { | 
|  | variant := ctx.ModuleForTests("foo", arch) | 
|  |  | 
|  | libExt := ".so" | 
|  | if arch == "darwin_x86_64" { | 
|  | libExt = ".dylib" | 
|  | } | 
|  | relocated := variant.Output(filepath.Join("out/soong/.intermediates/foo", arch, "relocated/lib64/libbar"+libExt)) | 
|  | expectedInput := "out/soong/.intermediates/libbar/" + arch + "_shared/libbar" + libExt | 
|  | android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input) | 
|  |  | 
|  | mod := variant.Module().(*ShTest) | 
|  | entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] | 
|  | expectedData := []string{ | 
|  | filepath.Join("out/soong/.intermediates/bar", arch, ":bar"), | 
|  | filepath.Join("out/soong/.intermediates/foo", arch, "relocated/:lib64/libbar"+libExt), | 
|  | } | 
|  | actualData := entries.EntryMap["LOCAL_TEST_DATA"] | 
|  | android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestShTestHost(t *testing.T) { | 
|  | ctx, _ := testShBinary(t, ` | 
|  | sh_test_host { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | filename: "test.sh", | 
|  | data: [ | 
|  | "testdata/data1", | 
|  | "testdata/sub/data2", | 
|  | ], | 
|  | test_options: { | 
|  | unit_test: true, | 
|  | }, | 
|  | } | 
|  | `) | 
|  |  | 
|  | buildOS := ctx.Config().BuildOS.String() | 
|  | mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) | 
|  | if !mod.Host() { | 
|  | t.Errorf("host bit is not set for a sh_test_host module.") | 
|  | } | 
|  | entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] | 
|  | actualData, _ := strconv.ParseBool(entries.EntryMap["LOCAL_IS_UNIT_TEST"][0]) | 
|  | android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData) | 
|  | } | 
|  |  | 
|  | func TestShTestHost_dataDeviceModules(t *testing.T) { | 
|  | ctx, config := testShBinary(t, ` | 
|  | sh_test_host { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | data_device_bins: ["bar"], | 
|  | data_device_libs: ["libbar"], | 
|  | } | 
|  |  | 
|  | cc_binary { | 
|  | name: "bar", | 
|  | shared_libs: ["libbar"], | 
|  | no_libcrt: true, | 
|  | nocrt: true, | 
|  | system_shared_libs: [], | 
|  | stl: "none", | 
|  | } | 
|  |  | 
|  | cc_library { | 
|  | name: "libbar", | 
|  | no_libcrt: true, | 
|  | nocrt: true, | 
|  | system_shared_libs: [], | 
|  | stl: "none", | 
|  | } | 
|  | `) | 
|  |  | 
|  | buildOS := config.BuildOS.String() | 
|  | variant := buildOS + "_x86_64" | 
|  | foo := ctx.ModuleForTests("foo", variant) | 
|  |  | 
|  | relocated := foo.Output(filepath.Join("out/soong/.intermediates/foo", variant, "relocated/lib64/libbar.so")) | 
|  | expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so" | 
|  | android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input) | 
|  |  | 
|  | mod := foo.Module().(*ShTest) | 
|  | entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] | 
|  | expectedData := []string{ | 
|  | "out/soong/.intermediates/bar/android_arm64_armv8-a/:bar", | 
|  | // libbar has been relocated, and so has a variant that matches the host arch. | 
|  | "out/soong/.intermediates/foo/" + variant + "/relocated/:lib64/libbar.so", | 
|  | } | 
|  | actualData := entries.EntryMap["LOCAL_TEST_DATA"] | 
|  | android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) | 
|  | } | 
|  |  | 
|  | func TestShTestHost_dataDeviceModulesAutogenTradefedConfig(t *testing.T) { | 
|  | ctx, config := testShBinary(t, ` | 
|  | sh_test_host { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | data_device_bins: ["bar"], | 
|  | data_device_libs: ["libbar"], | 
|  | } | 
|  |  | 
|  | cc_binary { | 
|  | name: "bar", | 
|  | shared_libs: ["libbar"], | 
|  | no_libcrt: true, | 
|  | nocrt: true, | 
|  | system_shared_libs: [], | 
|  | stl: "none", | 
|  | } | 
|  |  | 
|  | cc_library { | 
|  | name: "libbar", | 
|  | no_libcrt: true, | 
|  | nocrt: true, | 
|  | system_shared_libs: [], | 
|  | stl: "none", | 
|  | } | 
|  | `) | 
|  |  | 
|  | buildOS := config.BuildOS.String() | 
|  | fooModule := ctx.ModuleForTests("foo", buildOS+"_x86_64") | 
|  |  | 
|  | expectedBinAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />` | 
|  | autogen := fooModule.Rule("autogen") | 
|  | if !strings.Contains(autogen.Args["extraConfigs"], expectedBinAutogenConfig) { | 
|  | t.Errorf("foo extraConfings %v does not contain %q", autogen.Args["extraConfigs"], expectedBinAutogenConfig) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestShTestHost_javaData(t *testing.T) { | 
|  | ctx, config := testShBinary(t, ` | 
|  | sh_test_host { | 
|  | name: "foo", | 
|  | src: "test.sh", | 
|  | filename: "test.sh", | 
|  | data: [ | 
|  | "testdata/data1", | 
|  | "testdata/sub/data2", | 
|  | ], | 
|  | java_data: [ | 
|  | "javalib", | 
|  | ], | 
|  | } | 
|  |  | 
|  | java_library_host { | 
|  | name: "javalib", | 
|  | srcs: [], | 
|  | } | 
|  | `) | 
|  | buildOS := ctx.Config().BuildOS.String() | 
|  | mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) | 
|  | if !mod.Host() { | 
|  | t.Errorf("host bit is not set for a sh_test_host module.") | 
|  | } | 
|  | expectedData := []string{ | 
|  | ":testdata/data1", | 
|  | ":testdata/sub/data2", | 
|  | "out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar", | 
|  | } | 
|  |  | 
|  | entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] | 
|  | actualData := entries.EntryMap["LOCAL_TEST_DATA"] | 
|  | android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) | 
|  | } |