| // 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 expectations provides types and helpers for parsing, updating and |
| // writing WebGPU expectations files. |
| // |
| // See <dawn>/webgpu-cts/expectations.txt for more information. |
| package expectations |
| |
| import ( |
| "fmt" |
| |
| "dawn.googlesource.com/dawn/tools/src/container" |
| "dawn.googlesource.com/dawn/tools/src/cts/query" |
| "github.com/google/go-cmp/cmp" |
| ) |
| |
| func (c Content) tagsCollide(a, b container.Set[string]) bool { |
| for _, set := range c.Tags.Sets { |
| aSet := a.Intersection(set.Tags) |
| bSet := b.Intersection(set.Tags) |
| if len(aSet) != 0 && len(bSet) != 0 && len(aSet.Intersection(bSet)) == 0 { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // Validate checks that the expectations do not contain errors |
| func (c Content) Validate() Diagnostics { |
| tree, _ := query.NewTree[Expectations]() |
| for _, chunk := range c.Chunks { |
| for _, ex := range chunk.Expectations { |
| node := tree.GetOrCreate(query.Parse(ex.Query), func() Expectations { |
| return Expectations{} |
| }) |
| *node = append(*node, ex) |
| } |
| } |
| var out Diagnostics |
| for _, chunk := range c.Chunks { |
| for _, ex := range chunk.Expectations { |
| for _, status := range ex.Status { |
| if status == "Slow" { |
| out = append(out, Diagnostic{ |
| Severity: Error, |
| Line: ex.Line, |
| Message: fmt.Sprintf("\"Slow\" expectation is not valid here. Use slow_tests.txt instead."), |
| }) |
| } |
| } |
| glob, err := tree.Glob(query.Parse(ex.Query)) |
| if err != nil { |
| out = append(out, Diagnostic{ |
| Severity: Error, |
| Line: ex.Line, |
| Message: err.Error(), |
| }) |
| continue |
| } |
| for _, qd := range glob { |
| expectations := qd.Data |
| for _, other := range expectations { |
| if other.Line != ex.Line && c.tagsCollide(ex.Tags, other.Tags) { |
| out = append(out, Diagnostic{ |
| Severity: Error, |
| Line: ex.Line, |
| Message: fmt.Sprintf("expectation collides with expectation on line %v", other.Line), |
| }) |
| } |
| } |
| } |
| } |
| } |
| return out |
| } |
| |
| // ValidateSlowTests checks that the expectations are only [ Slow ] |
| func (c Content) ValidateSlowTests() Diagnostics { |
| var out Diagnostics |
| for _, chunk := range c.Chunks { |
| for _, ex := range chunk.Expectations { |
| if !cmp.Equal(ex.Status, []string{"Slow"}) { |
| out = append(out, Diagnostic{ |
| Severity: Error, |
| Line: ex.Line, |
| Message: fmt.Sprintf("slow test expectation for %v must be %v but was %v", ex.Query, []string{"Slow"}, ex.Status), |
| }) |
| } |
| } |
| } |
| return out |
| } |