times.go: Add test query filter

Usage: `./tools/run cts time -query QUERY ...`

Change-Id: Ifac16ee2405d1b5d03d246bf1556245e2dafe8c1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93304
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/tools/src/cmd/cts/time/time.go b/tools/src/cmd/cts/time/time.go
index 302071f..f96da47 100644
--- a/tools/src/cmd/cts/time/time.go
+++ b/tools/src/cmd/cts/time/time.go
@@ -38,6 +38,7 @@
 		source    common.ResultSource
 		auth      authcli.Flags
 		tags      string
+		query     string
 		aggregate bool
 		topN      int
 		histogram bool
@@ -57,6 +58,7 @@
 	c.flags.auth.Register(flag.CommandLine, common.DefaultAuthOptions())
 	flag.IntVar(&c.flags.topN, "top", 0, "print the top N slowest tests")
 	flag.BoolVar(&c.flags.histogram, "histogram", false, "print a histogram of test timings")
+	flag.StringVar(&c.flags.query, "query", "", "test query to filter results")
 	flag.StringVar(&c.flags.tags, "tags", "", "comma-separated list of tags to filter results")
 	flag.BoolVar(&c.flags.aggregate, "aggregate", false, "aggregate times by test")
 	return nil, nil
@@ -87,6 +89,13 @@
 		}
 	}
 
+	if c.flags.query != "" {
+		results = results.FilterByQuery(query.Parse(c.flags.query))
+		if len(results) == 0 {
+			return fmt.Errorf("no results after filtering by test query")
+		}
+	}
+
 	if c.flags.aggregate {
 		type Key struct {
 			Query  query.Query
diff --git a/tools/src/cts/result/result.go b/tools/src/cts/result/result.go
index 623a906..b94da2d 100644
--- a/tools/src/cts/result/result.go
+++ b/tools/src/cts/result/result.go
@@ -270,6 +270,13 @@
 	})
 }
 
+/// FilterByQuery returns the results that match the given query
+func (l List) FilterByQuery(q query.Query) List {
+	return l.Filter(func(r Result) bool {
+		return q.Contains(r.Query)
+	})
+}
+
 // Statuses is a set of Status
 type Statuses = container.Set[Status]