tools: Add src/cts/result

Holds types that describe CTS test results

100% test coverage.

Bug: dawn:1342
Change-Id: I453e87549eb992b2dcb41da4e0b6e3907ab2ed06
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85804
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-04-11 11:03:10 +00:00 committed by Dawn LUCI CQ
parent 4127abfd41
commit 9173392671
4 changed files with 1133 additions and 0 deletions

View File

@ -0,0 +1,211 @@
// Copyright 2022 The Dawn Authors
//
// 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 result holds types that describe CTS test results.
package result
import (
"fmt"
"sort"
"strings"
"dawn.googlesource.com/dawn/tools/src/container"
"dawn.googlesource.com/dawn/tools/src/cts/query"
)
// Result holds the result of a CTS test
type Result struct {
Query query.Query
Tags Tags
Status Status
}
// Format writes the Result to the fmt.State
// The Result is printed as a single line, in the form:
// <query> <tags> <status>
// This matches the order in which results are sorted.
func (r Result) Format(f fmt.State, verb rune) {
if len(r.Tags) > 0 {
fmt.Fprintf(f, "%v %v %v", r.Query, TagsToString(r.Tags), r.Status)
} else {
fmt.Fprintf(f, "%v %v", r.Query, r.Status)
}
}
// String returns the result as a string
func (r Result) String() string {
sb := strings.Builder{}
fmt.Fprint(&sb, r)
return sb.String()
}
// Parse parses the result from a string of the form:
// <query> <tags> <status>
// <tags> may be omitted if there were no tags.
func Parse(in string) (Result, error) {
line := in
token := func() string {
for i, c := range line {
if c != ' ' {
line = line[i:]
break
}
}
for i, c := range line {
if c == ' ' {
tok := line[:i]
line = line[i:]
return tok
}
}
tok := line
line = ""
return tok
}
a := token()
b := token()
c := token()
if a == "" || b == "" || token() != "" {
return Result{}, fmt.Errorf("unable to parse result '%v'", in)
}
q := query.Parse(a)
if c == "" {
status := Status(b)
return Result{q, nil, status}, nil
}
tags := StringToTags(b)
status := Status(c)
return Result{q, tags, status}, nil
}
// List is a list of results
type List []Result
// Returns the list of unique tags across all results.
func (l List) UniqueTags() []Tags {
tags := container.NewMap[string, Tags]()
for _, r := range l {
tags.Add(TagsToString(r.Tags), r.Tags)
}
return tags.Values()
}
// TransformTags returns the list of results with the tags transformed using f.
// TransformTags assumes that f will return the same output for the same input.
func (l List) TransformTags(f func(Tags) Tags) List {
cache := map[string]Tags{}
out := List{}
for _, r := range l {
key := TagsToString(r.Tags)
tags, cached := cache[key]
if !cached {
tags = f(r.Tags.Clone())
cache[key] = tags
}
out = append(out, Result{
Query: r.Query,
Tags: tags,
Status: r.Status,
})
}
return out
}
// ReplaceDuplicates returns a new list with duplicate test results replaced.
// When a duplicate is found, the function f is called with the duplicate
// results. The returned status will be used as the replaced result.
func (l List) ReplaceDuplicates(f func(List) Status) List {
type key struct {
query query.Query
tags string
}
m := map[key]List{}
for _, r := range l {
k := key{r.Query, TagsToString(r.Tags)}
m[k] = append(m[k], r)
}
for key, results := range m {
if len(results) > 1 {
result := results[0]
result.Status = f(results)
m[key] = List{result}
}
}
out := make(List, 0, len(m))
for _, r := range l {
k := key{r.Query, TagsToString(r.Tags)}
if unique, ok := m[k]; ok {
out = append(out, unique[0])
delete(m, k)
}
}
return out
}
// Sort sorts the list
func (l List) Sort() {
sort.Slice(l, func(i, j int) bool {
a, b := l[i], l[j]
switch a.Query.Compare(b.Query) {
case -1:
return true
case 1:
return false
}
ta := strings.Join(a.Tags.List(), TagDelimiter)
tb := strings.Join(b.Tags.List(), TagDelimiter)
switch {
case ta < tb:
return true
case ta > tb:
return false
}
return a.Status < b.Status
})
}
// Filter returns the results that match the given predicate
func (l List) Filter(f func(Result) bool) List {
out := make(List, 0, len(l))
for _, r := range l {
if f(r) {
out = append(out, r)
}
}
return out
}
// FilterByStatus returns the results that the given status
func (l List) FilterByStatus(status Status) List {
return l.Filter(func(r Result) bool {
return r.Status == status
})
}
// FilterByTags returns the results that have all the given tags
func (l List) FilterByTags(tags Tags) List {
return l.Filter(func(r Result) bool {
return r.Tags.ContainsAll(tags)
})
}
// Statuses returns a set of all the statuses in the list
func (l List) Statuses() container.Set[Status] {
set := container.NewSet[Status]()
for _, r := range l {
set.Add(r.Status)
}
return set
}

View File

@ -0,0 +1,849 @@
// Copyright 2022 The Dawn Authors
//
// 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 result_test
import (
"fmt"
"testing"
"dawn.googlesource.com/dawn/tools/src/container"
"dawn.googlesource.com/dawn/tools/src/cts/query"
"dawn.googlesource.com/dawn/tools/src/cts/result"
"github.com/google/go-cmp/cmp"
)
var Q = query.Parse
func T(tags ...string) result.Tags {
return result.NewTags(tags...)
}
func TestStringAndParse(t *testing.T) {
type Test struct {
result result.Result
expect string
}
for _, test := range []Test{
{
result.Result{
Query: Q(`a`),
Status: result.Failure,
},
`a Failure`,
}, {
result.Result{
Query: Q(`a:b,c,*`),
Tags: T("x"),
Status: result.Pass,
},
`a:b,c,* x Pass`,
},
{
result.Result{
Query: Q(`a:b,c:d,*`),
Tags: T("zzz", "x", "yy"),
Status: result.Failure,
},
`a:b,c:d,* x,yy,zzz Failure`,
},
} {
if diff := cmp.Diff(test.result.String(), test.expect); diff != "" {
t.Errorf("'%v'.String() was not as expected:\n%v", test.result, diff)
continue
}
parsed, err := result.Parse(test.expect)
if err != nil {
t.Errorf("Parse('%v') returned %v", test.expect, err)
continue
}
if diff := cmp.Diff(parsed, test.result); diff != "" {
t.Errorf("Parse('%v') was not as expected:\n%v", test.expect, diff)
}
}
}
func TestParseError(t *testing.T) {
for _, test := range []string{
``,
`a`,
`a b c d`,
} {
_, err := result.Parse(test)
expect := fmt.Sprintf(`unable to parse result '%v'`, test)
if err == nil || err.Error() != expect {
t.Errorf("Parse('%v') returned '%v'", test, err)
continue
}
}
}
func TestUniqueTags(t *testing.T) {
type Test struct {
results result.List
expect []result.Tags
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags(),
},
},
expect: []result.Tags{
result.NewTags(),
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
},
expect: []result.Tags{
result.NewTags("x"),
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
expect: []result.Tags{
result.NewTags("x", "y"),
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
result.Result{
Query: Q(`b`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
expect: []result.Tags{
result.NewTags("x", "y"),
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
result.Result{
Query: Q(`b`),
Status: result.Pass,
Tags: result.NewTags("y", "z"),
},
},
expect: []result.Tags{
result.NewTags("x", "y"),
result.NewTags("y", "z"),
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
result.Result{
Query: Q(`b`),
Status: result.Pass,
Tags: result.NewTags("y", "z"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("z", "x"),
},
result.Result{
Query: Q(`d`),
Status: result.Pass,
Tags: result.NewTags("y", "z"),
},
},
expect: []result.Tags{
result.NewTags("x", "y"),
result.NewTags("x", "z"),
result.NewTags("y", "z"),
},
},
} {
got := test.results.UniqueTags()
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nUniqueTags() was not as expected:\n%v", test.results, diff)
}
}
}
func TestTransformTags(t *testing.T) {
type Test struct {
results result.List
transform func(result.Tags) result.Tags
expect result.List
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags(),
},
},
transform: func(t result.Tags) result.Tags { return t },
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags(),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
},
transform: func(got result.Tags) result.Tags {
expect := result.NewTags("x")
if diff := cmp.Diff(got, expect); diff != "" {
t.Errorf("transform function's parameter was not as expected:\n%v", diff)
}
return got
},
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
result.Result{
Query: Q(`b`),
Status: result.Pass,
Tags: result.NewTags("y", "z"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("z", "x"),
},
},
transform: func(l result.Tags) result.Tags {
l = l.Clone()
if l.Contains("x") {
l.Remove("x")
l.Add("X")
}
return l
},
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("X", "y"),
},
result.Result{
Query: Q(`b`),
Status: result.Pass,
Tags: result.NewTags("y", "z"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("z", "X"),
},
},
},
} {
got := test.results.TransformTags(test.transform)
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nTransformTags() was not as expected:\n%v", test.results, diff)
}
}
}
func TestReplaceDuplicates(t *testing.T) {
type Test struct {
results result.List
fn func(result.List) result.Status
expect result.List
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
},
fn: func(l result.List) result.Status {
return result.Abort
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`a`), Status: result.Pass},
},
fn: func(l result.List) result.Status {
return result.Abort
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Abort},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Pass},
},
fn: func(l result.List) result.Status {
return result.Abort
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Pass},
result.Result{Query: Q(`a`), Status: result.Skip},
},
fn: func(got result.List) result.Status {
expect := result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`a`), Status: result.Skip},
}
if diff := cmp.Diff(got, expect); diff != "" {
t.Errorf("function's parameter was not as expected:\n%v", diff)
}
return result.Abort
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Abort},
result.Result{Query: Q(`b`), Status: result.Pass},
},
},
} {
got := test.results.ReplaceDuplicates(test.fn)
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nReplaceDuplicates() was not as expected:\n%v", test.results, diff)
}
}
}
func TestSort(t *testing.T) {
type Test struct {
results result.List
expect result.List
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Pass},
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`b`), Status: result.Pass},
result.Result{Query: Q(`a`), Status: result.Pass},
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`a`), Status: result.Skip},
},
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`a`), Status: result.Skip},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Skip,
Tags: result.NewTags(),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags(),
},
},
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags(),
},
result.Result{
Query: Q(`a`),
Status: result.Skip,
Tags: result.NewTags(),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("a"),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("b"),
},
},
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("a"),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("b"),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("b"),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("a"),
},
},
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("a"),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("b"),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`c`),
Status: result.RetryOnFailure,
Tags: result.NewTags("z"),
},
result.Result{
Query: Q(`a`),
Status: result.Crash,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`b`),
Status: result.Slow,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`b`),
Status: result.Skip,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`a`),
Status: result.Crash,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`aa`),
Status: result.Crash,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`c`),
Status: result.Abort,
Tags: result.NewTags("z"),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
},
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Crash,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`a`),
Status: result.Crash,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`aa`),
Status: result.Crash,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`b`),
Status: result.Skip,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`b`),
Status: result.Slow,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`c`),
Status: result.Abort,
Tags: result.NewTags("z"),
},
result.Result{
Query: Q(`c`),
Status: result.RetryOnFailure,
Tags: result.NewTags("z"),
},
},
},
} {
got := make(result.List, len(test.results))
copy(got, test.results)
got.Sort()
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nSort() was not as expected:\n%v", test.results, diff)
}
}
}
func TestFilter(t *testing.T) {
type Test struct {
results result.List
f func(result.Result) bool
expect result.List
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
},
f: func(result.Result) bool { return true },
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Failure},
},
f: func(r result.Result) bool { return r.Query == Q("b") },
expect: result.List{
result.Result{Query: Q(`b`), Status: result.Failure},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Skip},
result.Result{Query: Q(`c`), Status: result.Pass},
},
f: func(r result.Result) bool { return r.Status == result.Pass },
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`c`), Status: result.Pass},
},
},
} {
got := test.results.Filter(test.f)
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nFilter() was not as expected:\n%v", test.results, diff)
}
}
}
func TestFilterByStatus(t *testing.T) {
type Test struct {
results result.List
status result.Status
expect result.List
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Failure},
result.Result{Query: Q(`c`), Status: result.Pass},
},
status: result.Pass,
expect: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`c`), Status: result.Pass},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Failure},
},
status: result.Failure,
expect: result.List{
result.Result{Query: Q(`b`), Status: result.Failure},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{Query: Q(`a`), Status: result.Pass},
result.Result{Query: Q(`b`), Status: result.Failure},
},
status: result.RetryOnFailure,
expect: result.List{},
},
} {
got := test.results.FilterByStatus(test.status)
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nFilterByStatus(%v) was not as expected:\n%v", test.results, test.status, diff)
}
}
}
func TestFilterByTags(t *testing.T) {
type Test struct {
results result.List
tags result.Tags
expect result.List
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`b`),
Status: result.Failure,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
tags: result.NewTags("x", "y"),
expect: result.List{
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`b`),
Status: result.Failure,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
tags: result.NewTags("x"),
expect: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
Tags: result.NewTags("x"),
},
result.Result{
Query: Q(`b`),
Status: result.Failure,
Tags: result.NewTags("y"),
},
result.Result{
Query: Q(`c`),
Status: result.Pass,
Tags: result.NewTags("x", "y"),
},
},
tags: result.NewTags("q"),
expect: result.List{},
},
} {
got := test.results.FilterByTags(test.tags)
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nFilterByTags(%v) was not as expected:\n%v", test.results, test.tags, diff)
}
}
}
func TestStatuses(t *testing.T) {
type Test struct {
results result.List
expect container.Set[result.Status]
}
for _, test := range []Test{
{ //////////////////////////////////////////////////////////////////////
results: result.List{},
expect: container.NewSet[result.Status](),
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
},
},
expect: container.NewSet(result.Pass),
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
},
result.Result{
Query: Q(`b`),
Status: result.Pass,
},
},
expect: container.NewSet(result.Pass),
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
},
result.Result{
Query: Q(`b`),
Status: result.Skip,
},
},
expect: container.NewSet(result.Pass, result.Skip),
},
{ //////////////////////////////////////////////////////////////////////
results: result.List{
result.Result{
Query: Q(`a`),
Status: result.Pass,
},
result.Result{
Query: Q(`b`),
Status: result.Skip,
},
result.Result{
Query: Q(`c`),
Status: result.Failure,
},
},
expect: container.NewSet(result.Pass, result.Skip, result.Failure),
},
} {
got := test.results.Statuses()
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("Results:\n%v\nStatuses() was not as expected:\n%v", test.results, diff)
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright 2022 The Dawn Authors
//
// 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 result
// Status is an enumerator of test results
type Status string
// Enumerator values for Status
const (
Abort = Status("Abort")
Crash = Status("Crash")
Failure = Status("Failure")
Pass = Status("Pass")
RetryOnFailure = Status("RetryOnFailure")
Skip = Status("Skip")
Slow = Status("Slow")
Unknown = Status("Unknown")
)

View File

@ -0,0 +1,43 @@
// Copyright 2022 The Dawn Authors
//
// 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 result
import (
"strings"
"dawn.googlesource.com/dawn/tools/src/container"
)
// Tags is a collection of strings used to annotate test results with the test
// configuration.
type Tags = container.Set[string]
// Returns a new tag set with the given tags
func NewTags(tags ...string) Tags {
return Tags(container.NewSet(tags...))
}
// TagsToString returns the tags sorted and joined using the TagDelimiter
func TagsToString(t Tags) string {
return strings.Join(t.List(), TagDelimiter)
}
// StringToTags returns the tags sorted and joined using the TagDelimiter
func StringToTags(s string) Tags {
return NewTags(strings.Split(s, TagDelimiter)...)
}
// The delimiter used to separate tags when stored as a string
const TagDelimiter = ","