Add tests for request_type ParseResult functions.

Test: go test request_type_test
Test: bp2build generate & sync; mixed build libc
Change-Id: Id0b813e9de4d02d8625e42549999659ccb005c6d
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 31c31fb..2697007 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -67,7 +67,7 @@
 
 	// TODO(cparsons): Other cquery-related methods should be added here.
 	// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
-	GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool)
+	GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
 
 	// ** End cquery methods
 
@@ -132,9 +132,9 @@
 	return result, ok
 }
 
-func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool) {
+func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
 	result, ok := m.LabelToCcInfo[label]
-	return result, ok
+	return result, ok, nil
 }
 
 func (m MockBazelContext) InvokeBazel() error {
@@ -163,21 +163,22 @@
 	return ret, ok
 }
 
-func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool) {
+func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
 	result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, archType)
 	if !ok {
-		return cquery.CcInfo{}, ok
+		return cquery.CcInfo{}, ok, nil
 	}
 
 	bazelOutput := strings.TrimSpace(result)
-	return cquery.GetCcInfo.ParseResult(bazelOutput), ok
+	ret, err := cquery.GetCcInfo.ParseResult(bazelOutput)
+	return ret, ok, err
 }
 
 func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
 	panic("unimplemented")
 }
 
-func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool) {
+func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
 	panic("unimplemented")
 }
 
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 7bd12a8..8049108 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -1,6 +1,7 @@
 package cquery
 
 import (
+	"fmt"
 	"strings"
 )
 
@@ -39,7 +40,7 @@
 // The given rawString must correspond to the string output which was created by evaluating the
 // Starlark given in StarlarkFunctionBody.
 func (g getOutputFilesRequestType) ParseResult(rawString string) []string {
-	return strings.Split(rawString, ", ")
+	return splitOrEmpty(rawString, ", ")
 }
 
 type getCcInfoType struct{}
@@ -85,11 +86,14 @@
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
 // The given rawString must correspond to the string output which was created by evaluating the
 // Starlark given in StarlarkFunctionBody.
-func (g getCcInfoType) ParseResult(rawString string) CcInfo {
+func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
 	var outputFiles []string
 	var ccObjects []string
 
 	splitString := strings.Split(rawString, "|")
+	if expectedLen := 3; len(splitString) != expectedLen {
+		return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
+	}
 	outputFilesString := splitString[0]
 	ccStaticLibrariesString := splitString[1]
 	ccObjectsString := splitString[2]
@@ -100,7 +104,7 @@
 		OutputFiles:          outputFiles,
 		CcObjectFiles:        ccObjects,
 		CcStaticLibraryFiles: ccStaticLibraries,
-	}
+	}, nil
 }
 
 // splitOrEmpty is a modification of strings.Split() that returns an empty list
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
new file mode 100644
index 0000000..56e03e2
--- /dev/null
+++ b/bazel/cquery/request_type_test.go
@@ -0,0 +1,89 @@
+package cquery
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+func TestGetOutputFilesParseResults(t *testing.T) {
+	testCases := []struct {
+		description    string
+		input          string
+		expectedOutput []string
+	}{
+		{
+			description:    "no result",
+			input:          "",
+			expectedOutput: []string{},
+		},
+		{
+			description:    "one result",
+			input:          "test",
+			expectedOutput: []string{"test"},
+		},
+		{
+			description:    "splits on comma with space",
+			input:          "foo, bar",
+			expectedOutput: []string{"foo", "bar"},
+		},
+	}
+	for _, tc := range testCases {
+		actualOutput := GetOutputFiles.ParseResult(tc.input)
+		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+		}
+	}
+}
+
+func TestGetCcInfoParseResults(t *testing.T) {
+	testCases := []struct {
+		description          string
+		input                string
+		expectedOutput       CcInfo
+		expectedErrorMessage string
+	}{
+		{
+			description: "no result",
+			input:       "||",
+			expectedOutput: CcInfo{
+				OutputFiles:          []string{},
+				CcObjectFiles:        []string{},
+				CcStaticLibraryFiles: []string{},
+			},
+		},
+		{
+			description: "only output",
+			input:       "test||",
+			expectedOutput: CcInfo{
+				OutputFiles:          []string{"test"},
+				CcObjectFiles:        []string{},
+				CcStaticLibraryFiles: []string{},
+			},
+		},
+		{
+			description: "all items set",
+			input:       "out1, out2|static_lib1, static_lib2|object1, object2",
+			expectedOutput: CcInfo{
+				OutputFiles:          []string{"out1", "out2"},
+				CcObjectFiles:        []string{"object1", "object2"},
+				CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+			},
+		},
+		{
+			description:          "too few result splits",
+			input:                "|",
+			expectedOutput:       CcInfo{},
+			expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", ""}),
+		},
+	}
+	for _, tc := range testCases {
+		actualOutput, err := GetCcInfo.ParseResult(tc.input)
+		if (err == nil && tc.expectedErrorMessage != "") ||
+			(err != nil && err.Error() != tc.expectedErrorMessage) {
+			t.Errorf("%q: expected Error %s, got %s", tc.description, tc.expectedErrorMessage, err)
+		} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+		}
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index cb0aebf..53be3a5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -483,12 +483,16 @@
 
 func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
-	ccInfo, ok := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
-	outputPaths := ccInfo.OutputFiles
-	objPaths := ccInfo.CcObjectFiles
+	ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+	if err != nil {
+		ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+		return false
+	}
 	if !ok {
 		return ok
 	}
+	outputPaths := ccInfo.OutputFiles
+	objPaths := ccInfo.CcObjectFiles
 	if len(outputPaths) > 1 {
 		// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
 		// We should support this.
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 7857432..c19b1ff 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -329,11 +329,14 @@
 
 func (h *prebuiltStaticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
-	ccInfo, ok := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
-	staticLibs := ccInfo.CcStaticLibraryFiles
+	ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+	if err != nil {
+		ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+	}
 	if !ok {
 		return false
 	}
+	staticLibs := ccInfo.CcStaticLibraryFiles
 	if len(staticLibs) > 1 {
 		ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
 		return false