tools: Add src/cts/query
Provides a type to represent the CTS query strings. 100% test coverage. Bug: dawn:1342 Change-Id: I3769b094ba64221a7b79dd38f76daf0125ee9e28 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85221 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
9c53d8a02c
commit
75cc17f2d1
|
@ -0,0 +1,362 @@
|
||||||
|
// 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 query provides helpers for parsing and mutating WebGPU CTS queries.
|
||||||
|
//
|
||||||
|
// The full query syntax is described at:
|
||||||
|
// https://github.com/gpuweb/cts/blob/main/docs/terms.md#queries
|
||||||
|
//
|
||||||
|
// Note that this package supports a superset of the official CTS query syntax,
|
||||||
|
// as this package permits parsing and printing of queries that do not end in a
|
||||||
|
// wildcard, whereas the CTS requires that all queries end in wildcards unless
|
||||||
|
// they identify a specific test.
|
||||||
|
// For example, the following queries are considered valid by this package, but
|
||||||
|
// would be rejected by the CTS:
|
||||||
|
// `suite`, `suite:file`, `suite:file,file`, `suite:file,file:test`.
|
||||||
|
//
|
||||||
|
// This relaxation is intentional as the Query type is used for constructing and
|
||||||
|
// reducing query trees, and always requiring a wildcard adds unnecessary
|
||||||
|
// complexity.
|
||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Query represents a WebGPU test query
|
||||||
|
// Example queries:
|
||||||
|
// 'suite'
|
||||||
|
// 'suite:*'
|
||||||
|
// 'suite:file'
|
||||||
|
// 'suite:file,*'
|
||||||
|
// 'suite:file,file'
|
||||||
|
// 'suite:file,file,*'
|
||||||
|
// 'suite:file,file,file:test'
|
||||||
|
// 'suite:file,file,file:test:*'
|
||||||
|
// 'suite:file,file,file:test,test:case;*'
|
||||||
|
type Query struct {
|
||||||
|
Suite string
|
||||||
|
Files string
|
||||||
|
Tests string
|
||||||
|
Cases string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target is the target of a query, either a Suite, File, Test or Case.
|
||||||
|
type Target int
|
||||||
|
|
||||||
|
// Enumerators of Target
|
||||||
|
const (
|
||||||
|
// The query targets a suite
|
||||||
|
Suite Target = iota
|
||||||
|
// The query targets one or more files
|
||||||
|
Files
|
||||||
|
// The query targets one or more tests
|
||||||
|
Tests
|
||||||
|
// The query targets one or more test cases
|
||||||
|
Cases
|
||||||
|
|
||||||
|
TargetCount
|
||||||
|
)
|
||||||
|
|
||||||
|
// Format writes the Target to the fmt.State
|
||||||
|
func (l Target) Format(f fmt.State, verb rune) {
|
||||||
|
switch l {
|
||||||
|
case Suite:
|
||||||
|
fmt.Fprint(f, "suite")
|
||||||
|
case Files:
|
||||||
|
fmt.Fprint(f, "files")
|
||||||
|
case Tests:
|
||||||
|
fmt.Fprint(f, "tests")
|
||||||
|
case Cases:
|
||||||
|
fmt.Fprint(f, "cases")
|
||||||
|
default:
|
||||||
|
fmt.Fprint(f, "<invalid>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delimiter constants used by the query format
|
||||||
|
const (
|
||||||
|
TargetDelimiter = ":"
|
||||||
|
FileDelimiter = ","
|
||||||
|
TestDelimiter = ","
|
||||||
|
CaseDelimiter = ";"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse parses a query string
|
||||||
|
func Parse(s string) (Query, error) {
|
||||||
|
parts := strings.Split(s, TargetDelimiter)
|
||||||
|
q := Query{}
|
||||||
|
switch len(parts) {
|
||||||
|
default:
|
||||||
|
q.Cases = strings.Join(parts[3:], TargetDelimiter)
|
||||||
|
fallthrough
|
||||||
|
case 3:
|
||||||
|
q.Tests = parts[2]
|
||||||
|
fallthrough
|
||||||
|
case 2:
|
||||||
|
q.Files = parts[1]
|
||||||
|
fallthrough
|
||||||
|
case 1:
|
||||||
|
q.Suite = parts[0]
|
||||||
|
}
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendFiles returns a new query with the strings appended to the 'files'
|
||||||
|
func (q Query) AppendFiles(f ...string) Query {
|
||||||
|
if len(f) > 0 {
|
||||||
|
if q.Files == "" {
|
||||||
|
q.Files = strings.Join(f, FileDelimiter)
|
||||||
|
} else {
|
||||||
|
q.Files = q.Files + FileDelimiter + strings.Join(f, FileDelimiter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitFiles returns the separated 'files' part of the query
|
||||||
|
func (q Query) SplitFiles() []string {
|
||||||
|
if q.Files != "" {
|
||||||
|
return strings.Split(q.Files, FileDelimiter)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendTests returns a new query with the strings appended to the 'tests'
|
||||||
|
func (q Query) AppendTests(t ...string) Query {
|
||||||
|
if len(t) > 0 {
|
||||||
|
if q.Tests == "" {
|
||||||
|
q.Tests = strings.Join(t, TestDelimiter)
|
||||||
|
} else {
|
||||||
|
q.Tests = q.Tests + TestDelimiter + strings.Join(t, TestDelimiter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitTests returns the separated 'tests' part of the query
|
||||||
|
func (q Query) SplitTests() []string {
|
||||||
|
if q.Tests != "" {
|
||||||
|
return strings.Split(q.Tests, TestDelimiter)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendCases returns a new query with the strings appended to the 'cases'
|
||||||
|
func (q Query) AppendCases(c ...string) Query {
|
||||||
|
if len(c) > 0 {
|
||||||
|
if q.Cases == "" {
|
||||||
|
q.Cases = strings.Join(c, CaseDelimiter)
|
||||||
|
} else {
|
||||||
|
q.Cases = q.Cases + CaseDelimiter + strings.Join(c, CaseDelimiter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitCases returns the separated 'cases' part of the query
|
||||||
|
func (q Query) SplitCases() []string {
|
||||||
|
if q.Cases != "" {
|
||||||
|
return strings.Split(q.Cases, CaseDelimiter)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case parameters is a map of parameter name to parameter value
|
||||||
|
type CaseParameters map[string]string
|
||||||
|
|
||||||
|
// CaseParameters returns all the case parameters of the query
|
||||||
|
func (q Query) CaseParameters() CaseParameters {
|
||||||
|
if q.Cases != "" {
|
||||||
|
out := CaseParameters{}
|
||||||
|
for _, c := range strings.Split(q.Cases, CaseDelimiter) {
|
||||||
|
idx := strings.IndexRune(c, '=')
|
||||||
|
if idx < 0 {
|
||||||
|
out[c] = ""
|
||||||
|
} else {
|
||||||
|
k, v := c[:idx], c[idx+1:]
|
||||||
|
out[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append returns the query with the additional strings appended to the target
|
||||||
|
func (q Query) Append(t Target, n ...string) Query {
|
||||||
|
switch t {
|
||||||
|
case Files:
|
||||||
|
return q.AppendFiles(n...)
|
||||||
|
case Tests:
|
||||||
|
return q.AppendTests(n...)
|
||||||
|
case Cases:
|
||||||
|
return q.AppendCases(n...)
|
||||||
|
}
|
||||||
|
panic("invalid target")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target returns the target of the query
|
||||||
|
func (q Query) Target() Target {
|
||||||
|
if q.Files != "" {
|
||||||
|
if q.Tests != "" {
|
||||||
|
if q.Cases != "" {
|
||||||
|
return Cases
|
||||||
|
}
|
||||||
|
return Tests
|
||||||
|
}
|
||||||
|
return Files
|
||||||
|
}
|
||||||
|
return Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWildcard returns true if the query ends with a wildcard
|
||||||
|
func (q Query) IsWildcard() bool {
|
||||||
|
switch q.Target() {
|
||||||
|
case Suite:
|
||||||
|
return q.Suite == "*"
|
||||||
|
case Files:
|
||||||
|
return strings.HasSuffix(q.Files, "*")
|
||||||
|
case Tests:
|
||||||
|
return strings.HasSuffix(q.Tests, "*")
|
||||||
|
case Cases:
|
||||||
|
return strings.HasSuffix(q.Cases, "*")
|
||||||
|
}
|
||||||
|
panic("invalid target")
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the query formatted as a string
|
||||||
|
func (q Query) String() string {
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString(q.Suite)
|
||||||
|
if q.Files != "" {
|
||||||
|
sb.WriteString(TargetDelimiter)
|
||||||
|
sb.WriteString(q.Files)
|
||||||
|
if q.Tests != "" {
|
||||||
|
sb.WriteString(TargetDelimiter)
|
||||||
|
sb.WriteString(q.Tests)
|
||||||
|
if q.Cases != "" {
|
||||||
|
sb.WriteString(TargetDelimiter)
|
||||||
|
sb.WriteString(q.Cases)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare compares the relative order of q and o, returning:
|
||||||
|
// -1 if q should come before o
|
||||||
|
// 1 if q should come after o
|
||||||
|
// 0 if q and o are identical
|
||||||
|
func (q Query) Compare(o Query) int {
|
||||||
|
for _, cmp := range []struct{ a, b string }{
|
||||||
|
{q.Suite, o.Suite},
|
||||||
|
{q.Files, o.Files},
|
||||||
|
{q.Tests, o.Tests},
|
||||||
|
{q.Cases, o.Cases},
|
||||||
|
} {
|
||||||
|
if cmp.a < cmp.b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if cmp.a > cmp.b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains returns true if q is a superset of o
|
||||||
|
func (q Query) Contains(o Query) bool {
|
||||||
|
if q.Suite != o.Suite {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
{
|
||||||
|
a, b := q.SplitFiles(), o.SplitFiles()
|
||||||
|
for i, f := range a {
|
||||||
|
if f == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if i >= len(b) || b[i] != f {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(a) < len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
a, b := q.SplitTests(), o.SplitTests()
|
||||||
|
for i, f := range a {
|
||||||
|
if f == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if i >= len(b) || b[i] != f {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(a) < len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
a, b := q.CaseParameters(), o.CaseParameters()
|
||||||
|
for key, av := range a {
|
||||||
|
if bv, found := b[key]; found && av != bv {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback function for Query.Walk()
|
||||||
|
// q is the query for the current segment.
|
||||||
|
// t is the target of the query q.
|
||||||
|
// n is the name of the new segment.
|
||||||
|
type WalkCallback func(q Query, t Target, n string) error
|
||||||
|
|
||||||
|
// Walk calls 'f' for each suite, file, test segment, and calls f once for all
|
||||||
|
// cases. If f returns an error then walking is immediately terminated and the
|
||||||
|
// error is returned.
|
||||||
|
func (q Query) Walk(f WalkCallback) error {
|
||||||
|
p := Query{Suite: q.Suite}
|
||||||
|
|
||||||
|
if err := f(p, Suite, q.Suite); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range q.SplitFiles() {
|
||||||
|
p = p.AppendFiles(file)
|
||||||
|
if err := f(p, Files, file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range q.SplitTests() {
|
||||||
|
p = p.AppendTests(test)
|
||||||
|
if err := f(p, Tests, test); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if q.Cases != "" {
|
||||||
|
if err := f(q, Cases, q.Cases); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,865 @@
|
||||||
|
// 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 query_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"dawn.googlesource.com/dawn/tools/src/cts/query"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Q(name string) query.Query {
|
||||||
|
q, err := query.Parse(name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTargetFormat(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
target query.Target
|
||||||
|
expect string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{query.Suite, "suite"},
|
||||||
|
{query.Files, "files"},
|
||||||
|
{query.Tests, "tests"},
|
||||||
|
{query.Cases, "cases"},
|
||||||
|
{query.Target(-1), "<invalid>"},
|
||||||
|
} {
|
||||||
|
s := strings.Builder{}
|
||||||
|
_, err := fmt.Fprint(&s, test.target)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Fprint() returned %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(s.String(), test.expect); diff != "" {
|
||||||
|
t.Errorf("Fprint('%v')\n%v", test.target, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendFiles(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
base query.Query
|
||||||
|
files []string
|
||||||
|
expect query.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), []string{}, Q("suite")},
|
||||||
|
{Q("suite"), []string{"x"}, Q("suite:x")},
|
||||||
|
{Q("suite"), []string{"x", "y"}, Q("suite:x,y")},
|
||||||
|
{Q("suite:a"), []string{}, Q("suite:a")},
|
||||||
|
{Q("suite:a"), []string{"x"}, Q("suite:a,x")},
|
||||||
|
{Q("suite:a"), []string{"x", "y"}, Q("suite:a,x,y")},
|
||||||
|
{Q("suite:a,b"), []string{}, Q("suite:a,b")},
|
||||||
|
{Q("suite:a,b"), []string{"x"}, Q("suite:a,b,x")},
|
||||||
|
{Q("suite:a,b"), []string{"x", "y"}, Q("suite:a,b,x,y")},
|
||||||
|
{Q("suite:a,b:c"), []string{}, Q("suite:a,b:c")},
|
||||||
|
{Q("suite:a,b:c"), []string{"x"}, Q("suite:a,b,x:c")},
|
||||||
|
{Q("suite:a,b:c"), []string{"x", "y"}, Q("suite:a,b,x,y:c")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{}, Q("suite:a,b:c,d")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"x"}, Q("suite:a,b,x:c,d")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"x", "y"}, Q("suite:a,b,x,y:c,d")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{}, Q("suite:a,b:c,d:e")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"x"}, Q("suite:a,b,x:c,d:e")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"x", "y"}, Q("suite:a,b,x,y:c,d:e")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{}, Q("suite:a,b:c,d:e;f")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"x"}, Q("suite:a,b,x:c,d:e;f")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"x", "y"}, Q("suite:a,b,x,y:c,d:e;f")},
|
||||||
|
} {
|
||||||
|
got := test.base.AppendFiles(test.files...)
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.AppendFiles(%v)\n%v", test.base, test.files, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitFiles(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
expect []string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), nil},
|
||||||
|
{Q("suite:a"), []string{"a"}},
|
||||||
|
{Q("suite:a,b"), []string{"a", "b"}},
|
||||||
|
{Q("suite:a,b:c"), []string{"a", "b"}},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"a", "b"}},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"a", "b"}},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"a", "b"}},
|
||||||
|
} {
|
||||||
|
got := test.query.SplitFiles()
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.SplitFiles()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendTests(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
base query.Query
|
||||||
|
files []string
|
||||||
|
expect query.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), []string{}, Q("suite")},
|
||||||
|
{Q("suite"), []string{"x"}, Q("suite::x")},
|
||||||
|
{Q("suite"), []string{"x", "y"}, Q("suite::x,y")},
|
||||||
|
{Q("suite:a"), []string{}, Q("suite:a")},
|
||||||
|
{Q("suite:a"), []string{"x"}, Q("suite:a:x")},
|
||||||
|
{Q("suite:a"), []string{"x", "y"}, Q("suite:a:x,y")},
|
||||||
|
{Q("suite:a,b"), []string{}, Q("suite:a,b")},
|
||||||
|
{Q("suite:a,b"), []string{"x"}, Q("suite:a,b:x")},
|
||||||
|
{Q("suite:a,b"), []string{"x", "y"}, Q("suite:a,b:x,y")},
|
||||||
|
{Q("suite:a,b:c"), []string{}, Q("suite:a,b:c")},
|
||||||
|
{Q("suite:a,b:c"), []string{"x"}, Q("suite:a,b:c,x")},
|
||||||
|
{Q("suite:a,b:c"), []string{"x", "y"}, Q("suite:a,b:c,x,y")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{}, Q("suite:a,b:c,d")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"x"}, Q("suite:a,b:c,d,x")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"x", "y"}, Q("suite:a,b:c,d,x,y")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{}, Q("suite:a,b:c,d:e")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"x"}, Q("suite:a,b:c,d,x:e")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"x", "y"}, Q("suite:a,b:c,d,x,y:e")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{}, Q("suite:a,b:c,d:e;f")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"x"}, Q("suite:a,b:c,d,x:e;f")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"x", "y"}, Q("suite:a,b:c,d,x,y:e;f")},
|
||||||
|
} {
|
||||||
|
got := test.base.AppendTests(test.files...)
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.AppendTests(%v)\n%v", test.base, test.files, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitTests(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
tests []string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), nil},
|
||||||
|
{Q("suite:a"), nil},
|
||||||
|
{Q("suite:a,b"), nil},
|
||||||
|
{Q("suite:a,b:c"), []string{"c"}},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"c", "d"}},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"c", "d"}},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"c", "d"}},
|
||||||
|
} {
|
||||||
|
got := test.query.SplitTests()
|
||||||
|
if diff := cmp.Diff(got, test.tests); diff != "" {
|
||||||
|
t.Errorf("'%v'.SplitTests()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendCases(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
base query.Query
|
||||||
|
cases []string
|
||||||
|
expect query.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), []string{}, Q("suite")},
|
||||||
|
{Q("suite"), []string{"x"}, Q("suite:::x")},
|
||||||
|
{Q("suite"), []string{"x", "y"}, Q("suite:::x;y")},
|
||||||
|
{Q("suite:a"), []string{}, Q("suite:a")},
|
||||||
|
{Q("suite:a"), []string{"x"}, Q("suite:a::x")},
|
||||||
|
{Q("suite:a"), []string{"x", "y"}, Q("suite:a::x;y")},
|
||||||
|
{Q("suite:a,b"), []string{}, Q("suite:a,b")},
|
||||||
|
{Q("suite:a,b"), []string{"x"}, Q("suite:a,b::x")},
|
||||||
|
{Q("suite:a,b"), []string{"x", "y"}, Q("suite:a,b::x;y")},
|
||||||
|
{Q("suite:a,b:c"), []string{}, Q("suite:a,b:c")},
|
||||||
|
{Q("suite:a,b:c"), []string{"x"}, Q("suite:a,b:c:x")},
|
||||||
|
{Q("suite:a,b:c"), []string{"x", "y"}, Q("suite:a,b:c:x;y")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{}, Q("suite:a,b:c,d")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"x"}, Q("suite:a,b:c,d:x")},
|
||||||
|
{Q("suite:a,b:c,d"), []string{"x", "y"}, Q("suite:a,b:c,d:x;y")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{}, Q("suite:a,b:c,d:e")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"x"}, Q("suite:a,b:c,d:e;x")},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"x", "y"}, Q("suite:a,b:c,d:e;x;y")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{}, Q("suite:a,b:c,d:e;f")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"x"}, Q("suite:a,b:c,d:e;f;x")},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"x", "y"}, Q("suite:a,b:c,d:e;f;x;y")},
|
||||||
|
} {
|
||||||
|
got := test.base.AppendCases(test.cases...)
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.AppendCases(%v)\n%v", test.base, test.cases, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppend(t *testing.T) {
|
||||||
|
type Subtest struct {
|
||||||
|
target query.Target
|
||||||
|
expect query.Query
|
||||||
|
}
|
||||||
|
type Test struct {
|
||||||
|
base query.Query
|
||||||
|
strings []string
|
||||||
|
subtest []Subtest
|
||||||
|
}
|
||||||
|
for _, test := range []Test{
|
||||||
|
{
|
||||||
|
Q("suite"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite")},
|
||||||
|
{query.Tests, Q("suite")},
|
||||||
|
{query.Cases, Q("suite")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:x")},
|
||||||
|
{query.Tests, Q("suite::x")},
|
||||||
|
{query.Cases, Q("suite:::x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:x,y")},
|
||||||
|
{query.Tests, Q("suite::x,y")},
|
||||||
|
{query.Cases, Q("suite:::x;y")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a")},
|
||||||
|
{query.Tests, Q("suite:a")},
|
||||||
|
{query.Cases, Q("suite:a")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,x")},
|
||||||
|
{query.Tests, Q("suite:a:x")},
|
||||||
|
{query.Cases, Q("suite:a::x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,x,y")},
|
||||||
|
{query.Tests, Q("suite:a:x,y")},
|
||||||
|
{query.Cases, Q("suite:a::x;y")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b")},
|
||||||
|
{query.Tests, Q("suite:a,b")},
|
||||||
|
{query.Cases, Q("suite:a,b")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x")},
|
||||||
|
{query.Tests, Q("suite:a,b:x")},
|
||||||
|
{query.Cases, Q("suite:a,b::x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x,y")},
|
||||||
|
{query.Tests, Q("suite:a,b:x,y")},
|
||||||
|
{query.Cases, Q("suite:a,b::x;y")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b:c")},
|
||||||
|
{query.Tests, Q("suite:a,b:c")},
|
||||||
|
{query.Cases, Q("suite:a,b:c")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x:c")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,x")},
|
||||||
|
{query.Cases, Q("suite:a,b:c:x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x,y:c")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,x,y")},
|
||||||
|
{query.Cases, Q("suite:a,b:c:x;y")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b:c,d")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x:c,d")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d,x")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x,y:c,d")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d,x,y")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:x;y")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d:e"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b:c,d:e")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d:e")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:e")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d:e"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x:c,d:e")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d,x:e")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:e;x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d:e"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x,y:c,d:e")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d,x,y:e")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:e;x;y")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d:e;f"), []string{}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b:c,d:e;f")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d:e;f")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:e;f")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d:e;f"), []string{"x"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x:c,d:e;f")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d,x:e;f")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:e;f;x")},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Q("suite:a,b:c,d:e;f"), []string{"x", "y"}, []Subtest{
|
||||||
|
{query.Files, Q("suite:a,b,x,y:c,d:e;f")},
|
||||||
|
{query.Tests, Q("suite:a,b:c,d,x,y:e;f")},
|
||||||
|
{query.Cases, Q("suite:a,b:c,d:e;f;x;y")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
for _, subtest := range test.subtest {
|
||||||
|
got := test.base.Append(subtest.target, test.strings...)
|
||||||
|
if diff := cmp.Diff(got, subtest.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.Append(%v, %v)\n%v", test.base, subtest.target, test.base.Files, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitCases(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
expect []string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), nil},
|
||||||
|
{Q("suite:a"), nil},
|
||||||
|
{Q("suite:a,b"), nil},
|
||||||
|
{Q("suite:a,b:c"), nil},
|
||||||
|
{Q("suite:a,b:c,d"), nil},
|
||||||
|
{Q("suite:a,b:c,d:e"), []string{"e"}},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), []string{"e", "f"}},
|
||||||
|
} {
|
||||||
|
got := test.query.SplitCases()
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.SplitCases()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCaseParameters(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
expect query.CaseParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), nil},
|
||||||
|
{Q("suite:a"), nil},
|
||||||
|
{Q("suite:a,b"), nil},
|
||||||
|
{Q("suite:a,b:c"), nil},
|
||||||
|
{Q("suite:a,b:c,d"), nil},
|
||||||
|
{Q("suite:a,b:c,d:e"), query.CaseParameters{"e": ""}},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), query.CaseParameters{"e": "", "f": ""}},
|
||||||
|
{Q("suite:a,b:c,d:e=f;g=h"), query.CaseParameters{"e": "f", "g": "h"}},
|
||||||
|
} {
|
||||||
|
got := test.query.CaseParameters()
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.CaseParameters()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTarget(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
expect query.Target
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), query.Suite},
|
||||||
|
{Q("suite:*"), query.Files},
|
||||||
|
{Q("suite:a"), query.Files},
|
||||||
|
{Q("suite:a,*"), query.Files},
|
||||||
|
{Q("suite:a,b"), query.Files},
|
||||||
|
{Q("suite:a,b:*"), query.Tests},
|
||||||
|
{Q("suite:a,b:c"), query.Tests},
|
||||||
|
{Q("suite:a,b:c,*"), query.Tests},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests},
|
||||||
|
{Q("suite:a,b:c,d:*"), query.Cases},
|
||||||
|
{Q("suite:a,b:c,d:e"), query.Cases},
|
||||||
|
{Q("suite:a,b:c,d:e;*"), query.Cases},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), query.Cases},
|
||||||
|
{Q("suite:a,b:c,d:e;f;*"), query.Cases},
|
||||||
|
} {
|
||||||
|
got := test.query.Target()
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.Target()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsWildcard(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
expect bool
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("suite"), false},
|
||||||
|
{Q("suite:*"), true},
|
||||||
|
{Q("suite:a"), false},
|
||||||
|
{Q("suite:a,*"), true},
|
||||||
|
{Q("suite:a,b"), false},
|
||||||
|
{Q("suite:a,b:*"), true},
|
||||||
|
{Q("suite:a,b:c"), false},
|
||||||
|
{Q("suite:a,b:c,*"), true},
|
||||||
|
{Q("suite:a,b:c,d"), false},
|
||||||
|
{Q("suite:a,b:c,d:*"), true},
|
||||||
|
{Q("suite:a,b:c,d:e"), false},
|
||||||
|
{Q("suite:a,b:c,d:e;*"), true},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), false},
|
||||||
|
{Q("suite:a,b:c,d:e;f;*"), true},
|
||||||
|
} {
|
||||||
|
got := test.query.IsWildcard()
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.IsWildcard()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParsePrint(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
in string
|
||||||
|
expect query.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b:*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b",
|
||||||
|
Tests: "*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e,*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e,*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e:*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
Cases: "*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e:f=g",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
Cases: "f=g",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e:f=g;*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
Cases: "f=g;*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e:f=g;h=i",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
Cases: "f=g;h=i",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"a:b,c:d,e:f=g;h=i;*",
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
Cases: "f=g;h=i;*",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
`a:b,c:d,e:f={"x": 1, "y": 2}`,
|
||||||
|
query.Query{
|
||||||
|
Suite: "a",
|
||||||
|
Files: "b,c",
|
||||||
|
Tests: "d,e",
|
||||||
|
Cases: `f={"x": 1, "y": 2}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
parsed, err := query.Parse(test.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("query.Parse('%v') returned %v", test.in, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(test.expect, parsed); diff != "" {
|
||||||
|
t.Errorf("query.Parse('%v')\n%v", test.in, diff)
|
||||||
|
}
|
||||||
|
str := test.expect.String()
|
||||||
|
if diff := cmp.Diff(test.in, str); diff != "" {
|
||||||
|
t.Errorf("query.String('%v')\n%v", test.in, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompare(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
a, b query.Query
|
||||||
|
expect int
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("a"), Q("a"), 0},
|
||||||
|
{Q("a:*"), Q("a"), 1},
|
||||||
|
{Q("a:*"), Q("a:*"), 0},
|
||||||
|
{Q("a:*"), Q("b:*"), -1},
|
||||||
|
{Q("a:*"), Q("a:b,*"), -1},
|
||||||
|
{Q("a:b,*"), Q("a:b"), 1},
|
||||||
|
{Q("a:b,*"), Q("a:b,*"), 0},
|
||||||
|
{Q("a:b,*"), Q("a:c,*"), -1},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,*"), 1},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,c,*"), 0},
|
||||||
|
{Q("a:b,c,d,*"), Q("a:b,c,*"), 1},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,c:d,*"), 1},
|
||||||
|
{Q("a:b,c:*"), Q("a:b,c,d,*"), -1},
|
||||||
|
{Q("a:b,c:d,*"), Q("a:b,c:d,*"), 0},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:d,*"), 1},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:d,e,*"), 0},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:e,f,*"), -1},
|
||||||
|
{Q("a:b:c:d;*"), Q("a:b:c:d;*"), 0},
|
||||||
|
{Q("a:b:c:d;e=1;*"), Q("a:b:c:d;*"), 1},
|
||||||
|
{Q("a:b:c:d;e=2;*"), Q("a:b:c:d;e=1;*"), 1},
|
||||||
|
{Q("a:b:c:d;e=1;f=2;*"), Q("a:b:c:d;*"), 1},
|
||||||
|
} {
|
||||||
|
if got, expect := test.a.Compare(test.b), test.expect; got != expect {
|
||||||
|
t.Errorf("('%v').Compare('%v')\nexpect: %+v\ngot: %+v", test.a, test.b, expect, got)
|
||||||
|
}
|
||||||
|
// Check opposite order
|
||||||
|
if got, expect := test.b.Compare(test.a), -test.expect; got != expect {
|
||||||
|
t.Errorf("('%v').Compare('%v')\nexpect: %+v\ngot: %+v", test.b, test.a, expect, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContains(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
a, b query.Query
|
||||||
|
expect bool
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{Q("a"), Q("a"), true},
|
||||||
|
{Q("a"), Q("b"), false},
|
||||||
|
{Q("a:*"), Q("a:*"), true},
|
||||||
|
{Q("a:*"), Q("a:b"), true},
|
||||||
|
{Q("a:*"), Q("b"), false},
|
||||||
|
{Q("a:*"), Q("b:c"), false},
|
||||||
|
{Q("a:*"), Q("b:*"), false},
|
||||||
|
{Q("a:*"), Q("a:b,*"), true},
|
||||||
|
{Q("a:b,*"), Q("a:*"), false},
|
||||||
|
{Q("a:b,*"), Q("a:b"), true},
|
||||||
|
{Q("a:b,*"), Q("a:c"), false},
|
||||||
|
{Q("a:b,*"), Q("a:b,*"), true},
|
||||||
|
{Q("a:b,*"), Q("a:c,*"), false},
|
||||||
|
{Q("a:b,c"), Q("a:b,c,d"), false},
|
||||||
|
{Q("a:b,c"), Q("a:b,c:d"), false},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,*"), false},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,c"), true},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,d"), false},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,c,*"), true},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,c,d,*"), true},
|
||||||
|
{Q("a:b,c,*"), Q("a:b,c:d,*"), true},
|
||||||
|
{Q("a:b,c:*"), Q("a:b,c,d,*"), false},
|
||||||
|
{Q("a:b,c:d"), Q("a:b,c:d,e"), false},
|
||||||
|
{Q("a:b,c:d,*"), Q("a:b,c:d"), true},
|
||||||
|
{Q("a:b,c:d,*"), Q("a:b,c:e"), false},
|
||||||
|
{Q("a:b,c:d,*"), Q("a:b,c:d,*"), true},
|
||||||
|
{Q("a:b,c:d,*"), Q("a:b,c:d,e,*"), true},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:d,e"), true},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:e,e"), false},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:d,f"), false},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:d,e,*"), true},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:e,f,*"), false},
|
||||||
|
{Q("a:b,c:d,e,*"), Q("a:b,c:d,*"), false},
|
||||||
|
{Q("a:b:c:d;*"), Q("a:b:c:d;*"), true},
|
||||||
|
{Q("a:b:c:d;*"), Q("a:b:c:d,e;*"), true},
|
||||||
|
{Q("a:b:c:d;*"), Q("a:b:c:d;e=1;*"), true},
|
||||||
|
{Q("a:b:c:d;*"), Q("a:b:c:d;e=1;*"), true},
|
||||||
|
{Q("a:b:c:d;*"), Q("a:b:c:d;e=1;f=2;*"), true},
|
||||||
|
{Q("a:b:c:d;e=1;*"), Q("a:b:c:d;*"), true},
|
||||||
|
{Q("a:b:c:d;e=1;f=2;*"), Q("a:b:c:d;*"), true},
|
||||||
|
{Q("a:b:c:d;e=1;*"), Q("a:b:c:d;e=2;*"), false},
|
||||||
|
{Q("a:b:c:d;e=2;*"), Q("a:b:c:d;e=1;*"), false},
|
||||||
|
{Q("a:b:c:d;e;*"), Q("a:b:c:d;e=1;*"), false},
|
||||||
|
} {
|
||||||
|
if got := test.a.Contains(test.b); got != test.expect {
|
||||||
|
t.Errorf("('%v').Contains('%v')\nexpect: %+v\ngot: %+v", test.a, test.b, test.expect, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWalk(t *testing.T) {
|
||||||
|
type Segment struct {
|
||||||
|
Query query.Query
|
||||||
|
Target query.Target
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Test struct {
|
||||||
|
query query.Query
|
||||||
|
expect []Segment
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{
|
||||||
|
Q("suite"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:*"), query.Files, "*"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,*"), query.Files, "*"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:*"), query.Tests, "*"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,*"), query.Tests, "*"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,d"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests, "d"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,d:*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests, "d"},
|
||||||
|
{Q("suite:a,b:c,d:*"), query.Cases, "*"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,d:e"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests, "d"},
|
||||||
|
{Q("suite:a,b:c,d:e"), query.Cases, "e"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,d:e;*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests, "d"},
|
||||||
|
{Q("suite:a,b:c,d:e;*"), query.Cases, "e;*"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,d:e;f"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests, "d"},
|
||||||
|
{Q("suite:a,b:c,d:e;f"), query.Cases, "e;f"},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
Q("suite:a,b:c,d:e;f;*"), []Segment{
|
||||||
|
{Q("suite"), query.Suite, "suite"},
|
||||||
|
{Q("suite:a"), query.Files, "a"},
|
||||||
|
{Q("suite:a,b"), query.Files, "b"},
|
||||||
|
{Q("suite:a,b:c"), query.Tests, "c"},
|
||||||
|
{Q("suite:a,b:c,d"), query.Tests, "d"},
|
||||||
|
{Q("suite:a,b:c,d:e;f;*"), query.Cases, "e;f;*"},
|
||||||
|
}},
|
||||||
|
} {
|
||||||
|
got := []Segment{}
|
||||||
|
err := test.query.Walk(func(q query.Query, t query.Target, n string) error {
|
||||||
|
got = append(got, Segment{q, t, n})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("'%v'.Walk() returned %v", test.query, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(got, test.expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.Walk()\n%v", test.query, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestError struct{}
|
||||||
|
|
||||||
|
func (TestError) Error() string { return "test error" }
|
||||||
|
|
||||||
|
func TestWalkErrors(t *testing.T) {
|
||||||
|
for _, fq := range []query.Query{
|
||||||
|
Q("suite"),
|
||||||
|
Q("suite:*"),
|
||||||
|
Q("suite:a"),
|
||||||
|
Q("suite:a,*"),
|
||||||
|
Q("suite:a,b"),
|
||||||
|
Q("suite:a,b:*"),
|
||||||
|
Q("suite:a,b:c"),
|
||||||
|
Q("suite:a,b:c,*"),
|
||||||
|
Q("suite:a,b:c,d"),
|
||||||
|
Q("suite:a,b:c,d:*"),
|
||||||
|
Q("suite:a,b:c,d:e"),
|
||||||
|
Q("suite:a,b:c,d:e;*"),
|
||||||
|
Q("suite:a,b:c,d:e;f"),
|
||||||
|
Q("suite:a,b:c,d:e;f;*"),
|
||||||
|
} {
|
||||||
|
expect := TestError{}
|
||||||
|
got := fq.Walk(func(q query.Query, t query.Target, n string) error {
|
||||||
|
if q == fq {
|
||||||
|
return expect
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if diff := cmp.Diff(got, expect); diff != "" {
|
||||||
|
t.Errorf("'%v'.Walk()\n%v", fq, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue