Add jacoco filter tests

Add tests for converting jacoco filters to command line arguments
to soong_zip.

Bug: 64836607
Test: jacoco_test.go
Change-Id: I969fa877e4be19bb92dcab5a796a4e4ec3fc166a
diff --git a/java/jacoco.go b/java/jacoco.go
index b26b046..c4b3e6e 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -17,6 +17,7 @@
 // Rules for instrumenting classes using jacoco
 
 import (
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -59,41 +60,51 @@
 	})
 }
 
-func (j *Module) jacocoStripSpecs(ctx android.ModuleContext) string {
-	includes := jacocoFiltersToSpecs(ctx,
-		j.properties.Jacoco.Include_filter, "jacoco.include_filter")
-	excludes := jacocoFiltersToSpecs(ctx,
-		j.properties.Jacoco.Exclude_filter, "jacoco.exclude_filter")
+func (j *Module) jacocoModuleToZipCommand(ctx android.ModuleContext) string {
+	includes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Include_filter)
+	if err != nil {
+		ctx.PropertyErrorf("jacoco.include_filter", "%s", err.Error())
+	}
+	excludes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Exclude_filter)
+	if err != nil {
+		ctx.PropertyErrorf("jacoco.exclude_filter", "%s", err.Error())
+	}
 
+	return jacocoFiltersToZipCommand(includes, excludes)
+}
+
+func jacocoFiltersToZipCommand(includes, excludes []string) string {
 	specs := ""
 	if len(excludes) > 0 {
 		specs += android.JoinWithPrefix(excludes, "-x") + " "
 	}
-
 	if len(includes) > 0 {
 		specs += strings.Join(includes, " ")
 	} else {
 		specs += "**/*.class"
 	}
-
 	return specs
 }
 
-func jacocoFiltersToSpecs(ctx android.ModuleContext, filters []string, property string) []string {
+func jacocoFiltersToSpecs(filters []string) ([]string, error) {
 	specs := make([]string, len(filters))
+	var err error
 	for i, f := range filters {
-		specs[i] = jacocoFilterToSpec(ctx, f, property)
+		specs[i], err = jacocoFilterToSpec(f)
+		if err != nil {
+			return nil, err
+		}
 	}
-	return specs
+	return specs, nil
 }
 
-func jacocoFilterToSpec(ctx android.ModuleContext, filter string, property string) string {
+func jacocoFilterToSpec(filter string) (string, error) {
 	wildcard := strings.HasSuffix(filter, "*")
 	filter = strings.TrimSuffix(filter, "*")
 	recursiveWildcard := wildcard && (strings.HasSuffix(filter, ".") || filter == "")
 
 	if strings.ContainsRune(filter, '*') {
-		ctx.PropertyErrorf(property, "'*' is only supported as the last character in a filter")
+		return "", fmt.Errorf("'*' is only supported as the last character in a filter")
 	}
 
 	spec := strings.Replace(filter, ".", "/", -1)
@@ -104,5 +115,5 @@
 		spec += "*.class"
 	}
 
-	return spec
+	return spec, nil
 }
diff --git a/java/jacoco_test.go b/java/jacoco_test.go
new file mode 100644
index 0000000..8321017
--- /dev/null
+++ b/java/jacoco_test.go
@@ -0,0 +1,84 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import "testing"
+
+func TestJacocoFilterToSpecs(t *testing.T) {
+	testCases := []struct {
+		name, in, out string
+	}{
+		{
+			name: "class wildcard",
+			in:   "package.Class*",
+			out:  "package/Class*.class",
+		},
+		{
+			name: "package wildcard",
+			in:   "package.*",
+			out:  "package/**/*.class",
+		},
+		{
+			name: "all wildcard",
+			in:   "*",
+			out:  "**/*.class",
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got, err := jacocoFilterToSpec(testCase.in)
+			if err != nil {
+				t.Error(err)
+			}
+			if got != testCase.out {
+				t.Errorf("expected %q got %q", testCase.out, got)
+			}
+		})
+	}
+}
+
+func TestJacocoFiltersToZipCommand(t *testing.T) {
+	testCases := []struct {
+		name               string
+		includes, excludes []string
+		out                string
+	}{
+		{
+			name:     "implicit wildcard",
+			includes: []string{},
+			out:      "**/*.class",
+		},
+		{
+			name:     "only include",
+			includes: []string{"package/Class.class"},
+			out:      "package/Class.class",
+		},
+		{
+			name:     "multiple includes",
+			includes: []string{"package/Class.class", "package2/Class.class"},
+			out:      "package/Class.class package2/Class.class",
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got := jacocoFiltersToZipCommand(testCase.includes, testCase.excludes)
+			if got != testCase.out {
+				t.Errorf("expected %q got %q", testCase.out, got)
+			}
+		})
+	}
+}
diff --git a/java/java.go b/java/java.go
index 05d38f2..e6ed931 100644
--- a/java/java.go
+++ b/java/java.go
@@ -894,7 +894,7 @@
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
 	classesJar android.Path, jarName string) android.Path {
 
-	specs := j.jacocoStripSpecs(ctx)
+	specs := j.jacocoModuleToZipCommand(ctx)
 
 	jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco", "jacoco-report-classes.jar")
 	instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)