• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package testlist provides utilities for handling test lists.
16package testlist
17
18import (
19	"bytes"
20	"crypto/sha1"
21	"encoding/gob"
22	"encoding/hex"
23	"encoding/json"
24	"io/ioutil"
25	"path/filepath"
26	"sort"
27	"strings"
28
29	"../cause"
30)
31
32// API is an enumerator of graphics APIs.
33type API string
34
35// Graphics APIs.
36const (
37	EGL    = API("egl")
38	GLES2  = API("gles2")
39	GLES3  = API("gles3")
40	Vulkan = API("vulkan")
41)
42
43// Group is a list of tests to be run for a single API.
44type Group struct {
45	Name  string
46	File  string
47	API   API
48	Tests []string
49}
50
51// Filter returns a new Group that contains only tests that match the predicate.
52func (g Group) Filter(pred func(string) bool) Group {
53	out := Group{
54		Name: g.Name,
55		File: g.File,
56		API:  g.API,
57	}
58	for _, test := range g.Tests {
59		if pred(test) {
60			out.Tests = append(out.Tests, test)
61		}
62	}
63	return out
64}
65
66// Lists is the full list of tests to be run.
67type Lists []Group
68
69// Filter returns a new Lists that contains only tests that match the predicate.
70func (l Lists) Filter(pred func(string) bool) Lists {
71	out := Lists{}
72	for _, group := range l {
73		filtered := group.Filter(pred)
74		if len(filtered.Tests) > 0 {
75			out = append(out, filtered)
76		}
77	}
78	return out
79}
80
81// Hash returns a SHA1 hash of the set of tests.
82func (l Lists) Hash() string {
83	h := sha1.New()
84	if err := gob.NewEncoder(h).Encode(l); err != nil {
85		panic(cause.Wrap(err, "Could not encode testlist to produce hash"))
86	}
87	return hex.EncodeToString(h.Sum(nil))
88}
89
90// Load loads the test list json file and returns the full set of tests.
91func Load(root, jsonPath string) (Lists, error) {
92	root, err := filepath.Abs(root)
93	if err != nil {
94		return nil, cause.Wrap(err, "Couldn't get absolute path of '%s'", root)
95	}
96
97	jsonPath, err = filepath.Abs(jsonPath)
98	if err != nil {
99		return nil, cause.Wrap(err, "Couldn't get absolute path of '%s'", jsonPath)
100	}
101
102	i, err := ioutil.ReadFile(jsonPath)
103	if err != nil {
104		return nil, cause.Wrap(err, "Couldn't read test list from '%s'", jsonPath)
105	}
106
107	var jsonGroups []struct {
108		Name     string
109		API      string
110		TestFile string `json:"tests"`
111	}
112	if err := json.NewDecoder(bytes.NewReader(i)).Decode(&jsonGroups); err != nil {
113		return nil, cause.Wrap(err, "Couldn't parse '%s'", jsonPath)
114	}
115
116	dir := filepath.Dir(jsonPath)
117
118	out := make(Lists, len(jsonGroups))
119	for i, jsonGroup := range jsonGroups {
120		path := filepath.Join(dir, jsonGroup.TestFile)
121		tests, err := ioutil.ReadFile(path)
122		if err != nil {
123			return nil, cause.Wrap(err, "Couldn't read '%s'", tests)
124		}
125		relPath, err := filepath.Rel(root, path)
126		if err != nil {
127			return nil, cause.Wrap(err, "Couldn't get relative path for '%s'", path)
128		}
129		group := Group{
130			Name: jsonGroup.Name,
131			File: relPath,
132			API:  API(jsonGroup.API),
133		}
134		for _, line := range strings.Split(string(tests), "\n") {
135			line = strings.TrimSpace(line)
136			if line != "" && !strings.HasPrefix(line, "#") {
137				group.Tests = append(group.Tests, line)
138			}
139		}
140		sort.Strings(group.Tests)
141		out[i] = group
142	}
143
144	return out, nil
145}
146
147// Status is an enumerator of test results.
148type Status string
149
150const (
151	// Pass is the status of a successful test.
152	Pass = Status("PASS")
153	// Fail is the status of a failed test.
154	Fail = Status("FAIL")
155	// Timeout is the status of a test that failed to complete in the alloted
156	// time.
157	Timeout = Status("TIMEOUT")
158	// Crash is the status of a test that crashed.
159	Crash = Status("CRASH")
160	// Unimplemented is the status of a test that failed with UNIMPLEMENTED().
161	Unimplemented = Status("UNIMPLEMENTED")
162	// Unsupported is the status of a test that failed with UNSUPPORTED().
163	Unsupported = Status("UNSUPPORTED")
164	// Unreachable is the status of a test that failed with UNREACHABLE().
165	Unreachable = Status("UNREACHABLE")
166	// Assert is the status of a test that failed with ASSERT() or ASSERT_MSG().
167	Assert = Status("ASSERT")
168	// Abort is the status of a test that failed with ABORT().
169	Abort = Status("ABORT")
170	// NotSupported is the status of a test feature not supported by the driver.
171	NotSupported = Status("NOT_SUPPORTED")
172	// CompatibilityWarning is the status passing test with a warning.
173	CompatibilityWarning = Status("COMPATIBILITY_WARNING")
174	// QualityWarning is the status passing test with a warning.
175	QualityWarning = Status("QUALITY_WARNING")
176)
177
178// Statuses is the full list of status types
179var Statuses = []Status{
180	Pass,
181	Fail,
182	Timeout,
183	Crash,
184	Unimplemented,
185	Unsupported,
186	Unreachable,
187	Assert,
188	Abort,
189	NotSupported,
190	CompatibilityWarning,
191	QualityWarning,
192}
193
194// Failing returns true if the task status requires fixing.
195func (s Status) Failing() bool {
196	switch s {
197	case Fail, Timeout, Crash, Unimplemented, Unreachable, Assert, Abort:
198		return true
199	case Unsupported:
200		// This may seem surprising that this should be a failure, however these
201		// should not be reached, as dEQP should not be using features that are
202		// not advertised.
203		return true
204	default:
205		return false
206	}
207}
208
209// Passing returns true if the task status is considered a pass.
210func (s Status) Passing() bool {
211	switch s {
212	case Pass, CompatibilityWarning, QualityWarning:
213		return true
214	default:
215		return false
216	}
217}
218
219// FilePathWithStatus returns the path to the test list file with the status
220// appended before the file extension.
221func FilePathWithStatus(listPath string, status Status) string {
222	ext := filepath.Ext(listPath)
223	name := listPath[:len(listPath)-len(ext)]
224	return name + "-" + string(status) + ext
225}
226