Rollforward w/fix of "Use json encoding for cquery ParseResult"
Previous commit: commit fcc53f992b40786b216d38844ab61945fe5c9071.

Test: 1. use `TARGET_BUILD_VARIANT=userdebug TARGET_PRODUCT=aosp_arm64 build/bazel/ci/mixed_droid.sh` to verify no error occurred.
2. revise the test cases under request_type_test. 3. pass the test cases

Bug: 242587802
Change-Id: I7f70e62f7b6f42fa5f211772888040a0d07a710b
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index cf8e9f7..3b06f85 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -158,63 +158,30 @@
   # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
   pass
 
-returns = [
-  outputFiles,
-  ccObjectFiles,
-  sharedLibraries,
-  staticLibraries,
-  includes,
-  system_includes,
-  headers,
-  rootStaticArchives,
-  rootSharedLibraries,
-  [toc_file]
-]
+return json_encode({
+	"OutputFiles": outputFiles,
+	"CcObjectFiles": ccObjectFiles,
+	"CcSharedLibraryFiles": sharedLibraries,
+	"CcStaticLibraryFiles": staticLibraries,
+	"Includes": includes,
+	"SystemIncludes": system_includes,
+	"Headers": headers,
+	"RootStaticArchives": rootStaticArchives,
+	"RootDynamicLibraries": rootSharedLibraries,
+	"TocFile": toc_file
+})`
 
-return "|".join([", ".join(r) for r in returns])`
 }
 
 // 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, error) {
-	const expectedLen = 10
-	splitString := strings.Split(rawString, "|")
-	if len(splitString) != expectedLen {
-		return CcInfo{}, fmt.Errorf("expected %d items, got %q", expectedLen, splitString)
-	}
-	outputFilesString := splitString[0]
-	ccObjectsString := splitString[1]
-	ccSharedLibrariesString := splitString[2]
-	ccStaticLibrariesString := splitString[3]
-	includesString := splitString[4]
-	systemIncludesString := splitString[5]
-	headersString := splitString[6]
-	rootStaticArchivesString := splitString[7]
-	rootDynamicLibrariesString := splitString[8]
-	tocFile := splitString[9] // NOTE: Will be the empty string if there wasn't
-
-	outputFiles := splitOrEmpty(outputFilesString, ", ")
-	ccObjects := splitOrEmpty(ccObjectsString, ", ")
-	ccSharedLibraries := splitOrEmpty(ccSharedLibrariesString, ", ")
-	ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
-	includes := splitOrEmpty(includesString, ", ")
-	systemIncludes := splitOrEmpty(systemIncludesString, ", ")
-	headers := splitOrEmpty(headersString, ", ")
-	rootStaticArchives := splitOrEmpty(rootStaticArchivesString, ", ")
-	rootDynamicLibraries := splitOrEmpty(rootDynamicLibrariesString, ", ")
-	return CcInfo{
-		OutputFiles:          outputFiles,
-		CcObjectFiles:        ccObjects,
-		CcSharedLibraryFiles: ccSharedLibraries,
-		CcStaticLibraryFiles: ccStaticLibraries,
-		Includes:             includes,
-		SystemIncludes:       systemIncludes,
-		Headers:              headers,
-		RootStaticArchives:   rootStaticArchives,
-		RootDynamicLibraries: rootDynamicLibraries,
-		TocFile:              tocFile,
-	}, nil
+	var ccInfo CcInfo
+	decoder := json.NewDecoder(strings.NewReader(rawString))
+	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
+	err := decoder.Decode(&ccInfo)
+	return ccInfo, err
 }
 
 // Query Bazel for the artifacts generated by the apex modules.
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 46eb0b6..afe478b 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -1,9 +1,8 @@
 package cquery
 
 import (
-	"fmt"
+	"encoding/json"
 	"reflect"
-	"strings"
 	"testing"
 )
 
@@ -63,74 +62,48 @@
 }
 
 func TestGetCcInfoParseResults(t *testing.T) {
-	const expectedSplits = 10
-	noResult := strings.Repeat("|", expectedSplits-1)
 	testCases := []struct {
-		description          string
-		input                string
-		expectedOutput       CcInfo
-		expectedErrorMessage string
+		description    string
+		inputCcInfo    CcInfo
+		expectedOutput CcInfo
 	}{
 		{
-			description: "no result",
-			input:       noResult,
-			expectedOutput: CcInfo{
-				OutputFiles:          []string{},
-				CcObjectFiles:        []string{},
-				CcSharedLibraryFiles: []string{},
-				CcStaticLibraryFiles: []string{},
-				Includes:             []string{},
-				SystemIncludes:       []string{},
-				Headers:              []string{},
-				RootStaticArchives:   []string{},
-				RootDynamicLibraries: []string{},
-				TocFile:              "",
-			},
+			description:    "no result",
+			inputCcInfo:    CcInfo{},
+			expectedOutput: CcInfo{},
 		},
 		{
 			description: "only output",
-			input:       "test" + noResult,
+			inputCcInfo: CcInfo{
+				OutputFiles: []string{"test", "test3"},
+			},
 			expectedOutput: CcInfo{
-				OutputFiles:          []string{"test"},
-				CcObjectFiles:        []string{},
-				CcSharedLibraryFiles: []string{},
-				CcStaticLibraryFiles: []string{},
-				Includes:             []string{},
-				SystemIncludes:       []string{},
-				Headers:              []string{},
-				RootStaticArchives:   []string{},
-				RootDynamicLibraries: []string{},
-				TocFile:              "",
+				OutputFiles: []string{"test", "test3"},
 			},
 		},
 		{
 			description: "only ToC",
-			input:       noResult + "test",
+			inputCcInfo: CcInfo{
+				TocFile: "test",
+			},
 			expectedOutput: CcInfo{
-				OutputFiles:          []string{},
-				CcObjectFiles:        []string{},
-				CcSharedLibraryFiles: []string{},
-				CcStaticLibraryFiles: []string{},
-				Includes:             []string{},
-				SystemIncludes:       []string{},
-				Headers:              []string{},
-				RootStaticArchives:   []string{},
-				RootDynamicLibraries: []string{},
-				TocFile:              "test",
+				TocFile: "test",
 			},
 		},
 		{
 			description: "all items set",
-			input: "out1, out2" +
-				"|object1, object2" +
-				"|shared_lib1, shared_lib2" +
-				"|static_lib1, static_lib2" +
-				"|., dir/subdir" +
-				"|system/dir, system/other/dir" +
-				"|dir/subdir/hdr.h" +
-				"|rootstaticarchive1" +
-				"|rootdynamiclibrary1" +
-				"|lib.so.toc",
+			inputCcInfo: CcInfo{
+				OutputFiles:          []string{"out1", "out2"},
+				CcObjectFiles:        []string{"object1", "object2"},
+				CcSharedLibraryFiles: []string{"shared_lib1", "shared_lib2"},
+				CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+				Includes:             []string{".", "dir/subdir"},
+				SystemIncludes:       []string{"system/dir", "system/other/dir"},
+				Headers:              []string{"dir/subdir/hdr.h"},
+				RootStaticArchives:   []string{"rootstaticarchive1"},
+				RootDynamicLibraries: []string{"rootdynamiclibrary1"},
+				TocFile:              "lib.so.toc",
+			},
 			expectedOutput: CcInfo{
 				OutputFiles:          []string{"out1", "out2"},
 				CcObjectFiles:        []string{"object1", "object2"},
@@ -144,24 +117,12 @@
 				TocFile:              "lib.so.toc",
 			},
 		},
-		{
-			description:          "too few result splits",
-			input:                "|",
-			expectedOutput:       CcInfo{},
-			expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, []string{"", ""}),
-		},
-		{
-			description:          "too many result splits",
-			input:                strings.Repeat("|", expectedSplits+1), // 2 too many
-			expectedOutput:       CcInfo{},
-			expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
-		},
 	}
 	for _, tc := range testCases {
-		actualOutput, err := GetCcInfo.ParseResult(tc.input)
-		if (err == nil && tc.expectedErrorMessage != "") ||
-			(err != nil && err.Error() != tc.expectedErrorMessage) {
-			t.Errorf("%q:\n%12s: %q\n%12s: %q", tc.description, "expect Error", tc.expectedErrorMessage, "but got", err)
+		jsonInput, _ := json.Marshal(tc.inputCcInfo)
+		actualOutput, err := GetCcInfo.ParseResult(string(jsonInput))
+		if err != nil {
+			t.Errorf("%q:\n test case get error: %q", tc.description, err)
 		} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
 			t.Errorf("%q:\n expected %#v\n!= actual %#v", tc.description, tc.expectedOutput, actualOutput)
 		}