| // Copyright 2025 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package expectations |
| |
| import ( |
| "context" |
| "path/filepath" |
| "testing" |
| |
| "dawn.googlesource.com/dawn/tools/src/cmd/cts/common" |
| "dawn.googlesource.com/dawn/tools/src/fileutils" |
| "dawn.googlesource.com/dawn/tools/src/oswrapper" |
| "github.com/stretchr/testify/require" |
| ) |
| |
| func TestUpdateExpectations(t *testing.T) { |
| tests := []struct { |
| name string |
| resultsFile string |
| resultsContent string |
| testListPath string |
| testListContent string |
| expectationsPath string |
| expectationsContent string |
| expectationsFlag []string |
| wantErr string |
| wantLog string |
| verifyContent func(t *testing.T, fs oswrapper.FilesystemReader, path string) |
| generateExplicitTags bool |
| }{ |
| { |
| name: "Success", |
| resultsFile: "results.txt", |
| resultsContent: "webgpu:test:one linux,nvidia Failure 0s false\ncore", |
| testListPath: "third_party/gn/webgpu-cts/test_list.txt", |
| testListContent: "webgpu:test:one\nwebgpu:test:two", |
| expectationsPath: "expectations.txt", |
| expectationsContent: `# BEGIN TAG HEADER |
| # OS |
| # tags: [ mac win linux android ] |
| # GPU |
| # tags: [ amd intel nvidia qualcomm ] |
| # Device |
| # tags: [ android-pixel-4 android-pixel-6 chromeos-board-amd64-generic fuchsia-board-qemu-x64 ] |
| # END TAG HEADER |
| |
| # existing |
| [ mac ] webgpu:test:two: [ Failure ] |
| `, |
| expectationsFlag: []string{"expectations.txt"}, |
| verifyContent: func(t *testing.T, fs oswrapper.FilesystemReader, path string) { |
| content, err := fs.ReadFile(path) |
| require.NoError(t, err) |
| text := string(content) |
| require.Contains(t, text, "[ linux nvidia ] webgpu:test:one: [ Failure ]") |
| require.Contains(t, text, "[ mac ] webgpu:test:two: [ Failure ]") |
| }, |
| }, |
| { |
| name: "Results Fetch Error", |
| resultsFile: "nonexistent.txt", |
| testListPath: "third_party/gn/webgpu-cts/test_list.txt", |
| testListContent: "webgpu:test:one", |
| expectationsPath: "expectations.txt", |
| expectationsFlag: []string{"expectations.txt"}, |
| wantErr: "does not exist", |
| }, |
| { |
| name: "Test List Load Error", |
| resultsFile: "results.txt", |
| resultsContent: "webgpu:test:one linux Failure 0s false\ncore", |
| testListPath: "nonexistent/test_list.txt", |
| expectationsPath: "expectations.txt", |
| expectationsFlag: []string{"expectations.txt"}, |
| wantErr: "failed to load test list", |
| }, |
| { |
| name: "Expectations Load Error", |
| resultsFile: "results.txt", |
| resultsContent: "webgpu:test:one linux Failure 0s false\ncore", |
| testListPath: "third_party/gn/webgpu-cts/test_list.txt", |
| testListContent: "webgpu:test:one\nwebgpu:test:two", |
| expectationsPath: "expectations.txt", |
| expectationsFlag: []string{"nonexistent.txt"}, |
| wantErr: "does not exist", |
| }, |
| { |
| name: "Expectations Validation Error", |
| resultsFile: "results.txt", |
| resultsContent: "webgpu:test:one linux Failure 0s false\ncore", |
| testListPath: "third_party/gn/webgpu-cts/test_list.txt", |
| testListContent: "webgpu:test:one", |
| expectationsPath: "expectations.txt", |
| expectationsContent: "INVALID SYNTAX", |
| expectationsFlag: []string{"expectations.txt"}, |
| wantErr: "expected status", |
| }, |
| { |
| name: "Compat Mode", |
| resultsFile: "results.txt", |
| resultsContent: "webgpu:test:compat linux,nvidia Failure 0s false\ncompat", |
| testListPath: "third_party/gn/webgpu-cts/test_list.txt", |
| testListContent: "webgpu:test:compat", |
| expectationsPath: "compat_expectations.txt", |
| expectationsContent: `# BEGIN TAG HEADER |
| # OS |
| # tags: [ mac win linux android ] |
| # GPU |
| # tags: [ amd intel nvidia qualcomm ] |
| # Device |
| # tags: [ android-pixel-4 android-pixel-6 chromeos-board-amd64-generic fuchsia-board-qemu-x64 ] |
| # END TAG HEADER |
| `, |
| expectationsFlag: []string{"compat_expectations.txt"}, |
| verifyContent: func(t *testing.T, fs oswrapper.FilesystemReader, path string) { |
| content, err := fs.ReadFile(path) |
| require.NoError(t, err) |
| require.Contains(t, string(content), "[ linux nvidia ] webgpu:test:compat: [ Failure ]") |
| }, |
| }, |
| { |
| name: "Unknown Tests Removal", |
| resultsFile: "results.txt", |
| resultsContent: "webgpu:test:known linux,nvidia Failure 0s false\ncore", |
| testListPath: "third_party/gn/webgpu-cts/test_list.txt", |
| testListContent: "webgpu:test:known", |
| expectationsPath: "expectations.txt", |
| expectationsContent: `# BEGIN TAG HEADER |
| # OS |
| # tags: [ mac win linux android ] |
| # GPU |
| # tags: [ amd intel nvidia qualcomm ] |
| # Device |
| # tags: [ android-pixel-4 android-pixel-6 chromeos-board-amd64-generic fuchsia-board-qemu-x64 ] |
| # END TAG HEADER |
| |
| webgpu:test:unknown: [ Failure ]`, |
| expectationsFlag: []string{"expectations.txt"}, |
| verifyContent: func(t *testing.T, fs oswrapper.FilesystemReader, path string) { |
| content, err := fs.ReadFile(path) |
| require.NoError(t, err) |
| require.NotContains(t, string(content), "webgpu:test:unknown") |
| }, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| wrapper := oswrapper.CreateFSTestOSWrapper() |
| realWrapper := oswrapper.GetRealOSWrapper() |
| rootDir := fileutils.DawnRoot(realWrapper) |
| |
| // Helper to write file relative to root |
| write := func(path, content string) { |
| fullPath := filepath.Join(rootDir, path) |
| require.NoError(t, wrapper.MkdirAll(filepath.Dir(fullPath), 0755)) |
| require.NoError(t, wrapper.WriteFile(fullPath, []byte(content), 0666)) |
| } |
| |
| if tt.resultsContent != "" { |
| write(tt.resultsFile, tt.resultsContent) |
| } |
| if tt.testListContent != "" { |
| write(tt.testListPath, tt.testListContent) |
| } |
| if tt.expectationsContent != "" { |
| write(tt.expectationsPath, tt.expectationsContent) |
| } |
| |
| c := &cmd{} |
| |
| // Resolve paths to absolute for flags |
| absExpectations := make([]string, len(tt.expectationsFlag)) |
| for i, p := range tt.expectationsFlag { |
| absExpectations[i] = filepath.Join(rootDir, p) |
| } |
| c.flags.expectations = absExpectations |
| |
| if tt.resultsFile != "" { |
| c.flags.results.File = filepath.Join(rootDir, tt.resultsFile) |
| } |
| |
| c.flags.verbose = true |
| c.flags.generateExplicitTags = tt.generateExplicitTags |
| |
| ctx := context.Background() |
| cfg := common.Config{OsWrapper: wrapper} |
| |
| write("DEPS", "") // Ensure DawnRoot detection works |
| |
| err := c.Run(ctx, cfg) |
| if tt.wantErr != "" { |
| require.Error(t, err) |
| require.ErrorContains(t, err, tt.wantErr) |
| } else { |
| require.NoError(t, err) |
| } |
| |
| if tt.verifyContent != nil { |
| // Check content of the first expectations file |
| path := filepath.Join(rootDir, tt.expectationsPath) |
| tt.verifyContent(t, wrapper, path) |
| } |
| }) |
| } |
| } |