Merge "Add data property to sh_test."
diff --git a/android/sh_binary.go b/android/sh_binary.go
index cf415c5..fb7446d 100644
--- a/android/sh_binary.go
+++ b/android/sh_binary.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"io"
 	"strings"
 )
 
@@ -58,6 +57,10 @@
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
 	Test_config *string `android:"arch_variant"`
+
+	// list of files or filegroup modules that provide data that should be installed alongside
+	// the test.
+	Data []string `android:"path,arch_variant"`
 }
 
 type ShBinary struct {
@@ -73,6 +76,8 @@
 	ShBinary
 
 	testProperties TestProperties
+
+	data Paths
 }
 
 func (s *ShBinary) DepsMutator(ctx BottomUpMutatorContext) {
@@ -122,30 +127,50 @@
 	})
 }
 
-func (s *ShBinary) AndroidMk() AndroidMkData {
-	return AndroidMkData{
+func (s *ShBinary) AndroidMkEntries() AndroidMkEntries {
+	return AndroidMkEntries{
 		Class:      "EXECUTABLES",
 		OutputFile: OptionalPathForPath(s.outputFilePath),
 		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
-		Extra: []AndroidMkExtraFunc{
-			func(w io.Writer, outputFile Path) {
-				fmt.Fprintln(w, "LOCAL_MODULE_RELATIVE_PATH :=", String(s.properties.Sub_dir))
-				fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX :=")
-				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", s.outputFilePath.Rel())
-			},
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			s.customAndroidMkEntries(entries)
 		},
 	}
 }
 
-func (s *ShTest) AndroidMk() AndroidMkData {
-	data := s.ShBinary.AndroidMk()
-	data.Class = "NATIVE_TESTS"
-	data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
-		fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-			strings.Join(s.testProperties.Test_suites, " "))
-		fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=", String(s.testProperties.Test_config))
-	})
-	return data
+func (s *ShBinary) customAndroidMkEntries(entries *AndroidMkEntries) {
+	entries.SetString("LOCAL_MODULE_RELATIVE_PATH", String(s.properties.Sub_dir))
+	entries.SetString("LOCAL_MODULE_SUFFIX", "")
+	entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
+}
+
+func (s *ShTest) GenerateAndroidBuildActions(ctx ModuleContext) {
+	s.ShBinary.GenerateAndroidBuildActions(ctx)
+
+	s.data = PathsForModuleSrc(ctx, s.testProperties.Data)
+}
+
+func (s *ShTest) AndroidMkEntries() AndroidMkEntries {
+	return AndroidMkEntries{
+		Class:      "NATIVE_TESTS",
+		OutputFile: OptionalPathForPath(s.outputFilePath),
+		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			s.customAndroidMkEntries(entries)
+
+			entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
+			entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
+			for _, d := range s.data {
+				rel := d.Rel()
+				path := d.String()
+				if !strings.HasSuffix(path, rel) {
+					panic(fmt.Errorf("path %q does not end with %q", path, rel))
+				}
+				path = strings.TrimSuffix(path, rel)
+				entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
+			}
+		},
+	}
 }
 
 func InitShBinaryModule(s *ShBinary) {
diff --git a/android/sh_binary_test.go b/android/sh_binary_test.go
new file mode 100644
index 0000000..becb35a
--- /dev/null
+++ b/android/sh_binary_test.go
@@ -0,0 +1,58 @@
+package android
+
+import (
+	"io/ioutil"
+	"os"
+	"reflect"
+	"testing"
+)
+
+func testShBinary(t *testing.T, bp string) (*TestContext, Config) {
+	buildDir, err := ioutil.TempDir("", "soong_sh_binary_test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(buildDir)
+
+	config := TestArchConfig(buildDir, nil)
+
+	ctx := NewTestArchContext()
+	ctx.RegisterModuleType("sh_test", ModuleFactoryAdaptor(ShTestFactory))
+	ctx.Register()
+	mockFiles := map[string][]byte{
+		"Android.bp":         []byte(bp),
+		"test.sh":            nil,
+		"testdata/data1":     nil,
+		"testdata/sub/data2": nil,
+	}
+	ctx.MockFileSystem(mockFiles)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	return ctx, config
+}
+
+func TestShTestTestData(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test {
+			name: "foo",
+			src: "test.sh",
+			filename: "test.sh",
+			data: [
+				"testdata/data1",
+				"testdata/sub/data2",
+			],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+
+	entries := AndroidMkEntriesForTest(t, config, "", mod)
+	expected := []string{":testdata/data1", ":testdata/sub/data2"}
+	actual := entries.EntryMap["LOCAL_TEST_DATA"]
+	if !reflect.DeepEqual(expected, actual) {
+		t.Errorf("Unexpected test data expected: %q, actual: %q", expected, actual)
+	}
+}