xref: /aosp_15_r20/external/deqp/scripts/testset.py (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
2*35238bceSAndroid Build Coastguard Worker
3*35238bceSAndroid Build Coastguard Worker#-------------------------------------------------------------------------
4*35238bceSAndroid Build Coastguard Worker# drawElements Quality Program utilities
5*35238bceSAndroid Build Coastguard Worker# --------------------------------------
6*35238bceSAndroid Build Coastguard Worker#
7*35238bceSAndroid Build Coastguard Worker# Copyright 2015 The Android Open Source Project
8*35238bceSAndroid Build Coastguard Worker#
9*35238bceSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
10*35238bceSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
11*35238bceSAndroid Build Coastguard Worker# You may obtain a copy of the License at
12*35238bceSAndroid Build Coastguard Worker#
13*35238bceSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
14*35238bceSAndroid Build Coastguard Worker#
15*35238bceSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
16*35238bceSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
17*35238bceSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18*35238bceSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
19*35238bceSAndroid Build Coastguard Worker# limitations under the License.
20*35238bceSAndroid Build Coastguard Worker#
21*35238bceSAndroid Build Coastguard Worker#-------------------------------------------------------------------------
22*35238bceSAndroid Build Coastguard Worker
23*35238bceSAndroid Build Coastguard Workerimport sys
24*35238bceSAndroid Build Coastguard Workerimport random
25*35238bceSAndroid Build Coastguard Workerimport string
26*35238bceSAndroid Build Coastguard Workerimport subprocess
27*35238bceSAndroid Build Coastguard Workerfrom optparse import OptionParser
28*35238bceSAndroid Build Coastguard Worker
29*35238bceSAndroid Build Coastguard Workerdef all (results, predicate):
30*35238bceSAndroid Build Coastguard Worker    for result in results:
31*35238bceSAndroid Build Coastguard Worker        if not predicate(result):
32*35238bceSAndroid Build Coastguard Worker            return False
33*35238bceSAndroid Build Coastguard Worker    return True
34*35238bceSAndroid Build Coastguard Worker
35*35238bceSAndroid Build Coastguard Workerdef any (results, predicate):
36*35238bceSAndroid Build Coastguard Worker    for result in results:
37*35238bceSAndroid Build Coastguard Worker        if predicate(result):
38*35238bceSAndroid Build Coastguard Worker            return True
39*35238bceSAndroid Build Coastguard Worker    return False
40*35238bceSAndroid Build Coastguard Worker
41*35238bceSAndroid Build Coastguard Workerclass FilterRule:
42*35238bceSAndroid Build Coastguard Worker    def __init__ (self, name, description, filters):
43*35238bceSAndroid Build Coastguard Worker        self.name = name
44*35238bceSAndroid Build Coastguard Worker        self.description = description
45*35238bceSAndroid Build Coastguard Worker        self.filters = filters
46*35238bceSAndroid Build Coastguard Worker
47*35238bceSAndroid Build Coastguard Workerclass TestCaseResult:
48*35238bceSAndroid Build Coastguard Worker    def __init__ (self, name, results):
49*35238bceSAndroid Build Coastguard Worker        self.name = name
50*35238bceSAndroid Build Coastguard Worker        self.results = results
51*35238bceSAndroid Build Coastguard Worker
52*35238bceSAndroid Build Coastguard Workerclass Group:
53*35238bceSAndroid Build Coastguard Worker    def __init__ (self, name):
54*35238bceSAndroid Build Coastguard Worker        self.name = name
55*35238bceSAndroid Build Coastguard Worker        self.cases = []
56*35238bceSAndroid Build Coastguard Worker
57*35238bceSAndroid Build Coastguard Workerdef readCaseList (filename):
58*35238bceSAndroid Build Coastguard Worker    f = open(filename, 'rb')
59*35238bceSAndroid Build Coastguard Worker    cases = []
60*35238bceSAndroid Build Coastguard Worker    for line in f:
61*35238bceSAndroid Build Coastguard Worker        if line[:6] == "TEST: ":
62*35238bceSAndroid Build Coastguard Worker            case = line[6:].strip()
63*35238bceSAndroid Build Coastguard Worker            if len(case) > 0:
64*35238bceSAndroid Build Coastguard Worker                cases.append(case)
65*35238bceSAndroid Build Coastguard Worker    return cases
66*35238bceSAndroid Build Coastguard Worker
67*35238bceSAndroid Build Coastguard Workerdef toResultList (caselist):
68*35238bceSAndroid Build Coastguard Worker    results = []
69*35238bceSAndroid Build Coastguard Worker    for case in caselist:
70*35238bceSAndroid Build Coastguard Worker        results.append(TestCaseResult(case, []))
71*35238bceSAndroid Build Coastguard Worker    return results
72*35238bceSAndroid Build Coastguard Worker
73*35238bceSAndroid Build Coastguard Workerdef addResultsToCaseList (caselist, results):
74*35238bceSAndroid Build Coastguard Worker    resultMap = {}
75*35238bceSAndroid Build Coastguard Worker    caseListRes = toResultList(caselist)
76*35238bceSAndroid Build Coastguard Worker
77*35238bceSAndroid Build Coastguard Worker    for res in caseListRes:
78*35238bceSAndroid Build Coastguard Worker        resultMap[res.name] = res
79*35238bceSAndroid Build Coastguard Worker
80*35238bceSAndroid Build Coastguard Worker    for result in results:
81*35238bceSAndroid Build Coastguard Worker        if result.name in resultMap:
82*35238bceSAndroid Build Coastguard Worker            resultMap[result.name].results += result.results
83*35238bceSAndroid Build Coastguard Worker
84*35238bceSAndroid Build Coastguard Worker    return caseListRes
85*35238bceSAndroid Build Coastguard Worker
86*35238bceSAndroid Build Coastguard Workerdef readTestResults (filename):
87*35238bceSAndroid Build Coastguard Worker    f = open(filename, 'rb')
88*35238bceSAndroid Build Coastguard Worker    csvData = f.read()
89*35238bceSAndroid Build Coastguard Worker    csvLines = csvData.splitlines()
90*35238bceSAndroid Build Coastguard Worker    results = []
91*35238bceSAndroid Build Coastguard Worker
92*35238bceSAndroid Build Coastguard Worker    f.close()
93*35238bceSAndroid Build Coastguard Worker
94*35238bceSAndroid Build Coastguard Worker    for line in csvLines[1:]:
95*35238bceSAndroid Build Coastguard Worker        args = line.split(',')
96*35238bceSAndroid Build Coastguard Worker        if len(args) == 1:
97*35238bceSAndroid Build Coastguard Worker            continue # Ignore
98*35238bceSAndroid Build Coastguard Worker
99*35238bceSAndroid Build Coastguard Worker        results.append(TestCaseResult(args[0], args[1:]))
100*35238bceSAndroid Build Coastguard Worker
101*35238bceSAndroid Build Coastguard Worker    if len(results) == 0:
102*35238bceSAndroid Build Coastguard Worker        raise Exception("Empty result list")
103*35238bceSAndroid Build Coastguard Worker
104*35238bceSAndroid Build Coastguard Worker    # Quick check for results
105*35238bceSAndroid Build Coastguard Worker    numResultItems = len(results[0].results)
106*35238bceSAndroid Build Coastguard Worker    seenResults = set()
107*35238bceSAndroid Build Coastguard Worker    for result in results:
108*35238bceSAndroid Build Coastguard Worker        if result.name in seenResults:
109*35238bceSAndroid Build Coastguard Worker            raise Exception("Duplicate result row for test case '%s'" % result.name)
110*35238bceSAndroid Build Coastguard Worker        if len(result.results) != numResultItems:
111*35238bceSAndroid Build Coastguard Worker            raise Exception("Found %d results for test case '%s', expected %d" % (len(result.results), result.name, numResultItems))
112*35238bceSAndroid Build Coastguard Worker        seenResults.add(result.name)
113*35238bceSAndroid Build Coastguard Worker
114*35238bceSAndroid Build Coastguard Worker    return results
115*35238bceSAndroid Build Coastguard Worker
116*35238bceSAndroid Build Coastguard Workerdef readGroupList (filename):
117*35238bceSAndroid Build Coastguard Worker    f = open(filename, 'rb')
118*35238bceSAndroid Build Coastguard Worker    groups = []
119*35238bceSAndroid Build Coastguard Worker    for line in f:
120*35238bceSAndroid Build Coastguard Worker        group = line.strip()
121*35238bceSAndroid Build Coastguard Worker        if group != "":
122*35238bceSAndroid Build Coastguard Worker            groups.append(group)
123*35238bceSAndroid Build Coastguard Worker    return groups
124*35238bceSAndroid Build Coastguard Worker
125*35238bceSAndroid Build Coastguard Workerdef createGroups (results, groupNames):
126*35238bceSAndroid Build Coastguard Worker    groups = []
127*35238bceSAndroid Build Coastguard Worker    matched = set()
128*35238bceSAndroid Build Coastguard Worker
129*35238bceSAndroid Build Coastguard Worker    for groupName in groupNames:
130*35238bceSAndroid Build Coastguard Worker        group = Group(groupName)
131*35238bceSAndroid Build Coastguard Worker        groups.append(group)
132*35238bceSAndroid Build Coastguard Worker
133*35238bceSAndroid Build Coastguard Worker        prefix = groupName + "."
134*35238bceSAndroid Build Coastguard Worker        prefixLen = len(prefix)
135*35238bceSAndroid Build Coastguard Worker        for case in results:
136*35238bceSAndroid Build Coastguard Worker            if case.name[:prefixLen] == prefix:
137*35238bceSAndroid Build Coastguard Worker                if case in matched:
138*35238bceSAndroid Build Coastguard Worker                    die("Case '%s' matched by multiple groups (when processing '%s')" % (case.name, group.name))
139*35238bceSAndroid Build Coastguard Worker                group.cases.append(case)
140*35238bceSAndroid Build Coastguard Worker                matched.add(case)
141*35238bceSAndroid Build Coastguard Worker
142*35238bceSAndroid Build Coastguard Worker    return groups
143*35238bceSAndroid Build Coastguard Worker
144*35238bceSAndroid Build Coastguard Workerdef createLeafGroups (results):
145*35238bceSAndroid Build Coastguard Worker    groups = []
146*35238bceSAndroid Build Coastguard Worker    groupMap = {}
147*35238bceSAndroid Build Coastguard Worker
148*35238bceSAndroid Build Coastguard Worker    for case in results:
149*35238bceSAndroid Build Coastguard Worker        parts = case.name.split('.')
150*35238bceSAndroid Build Coastguard Worker        groupName = string.join(parts[:-1], ".")
151*35238bceSAndroid Build Coastguard Worker
152*35238bceSAndroid Build Coastguard Worker        if not groupName in groupMap:
153*35238bceSAndroid Build Coastguard Worker            group = Group(groupName)
154*35238bceSAndroid Build Coastguard Worker            groups.append(group)
155*35238bceSAndroid Build Coastguard Worker            groupMap[groupName] = group
156*35238bceSAndroid Build Coastguard Worker        else:
157*35238bceSAndroid Build Coastguard Worker            group = groupMap[groupName]
158*35238bceSAndroid Build Coastguard Worker
159*35238bceSAndroid Build Coastguard Worker        group.cases.append(case)
160*35238bceSAndroid Build Coastguard Worker
161*35238bceSAndroid Build Coastguard Worker    return groups
162*35238bceSAndroid Build Coastguard Worker
163*35238bceSAndroid Build Coastguard Workerdef filterList (results, condition):
164*35238bceSAndroid Build Coastguard Worker    filtered = []
165*35238bceSAndroid Build Coastguard Worker    for case in results:
166*35238bceSAndroid Build Coastguard Worker        if condition(case.results):
167*35238bceSAndroid Build Coastguard Worker            filtered.append(case)
168*35238bceSAndroid Build Coastguard Worker    return filtered
169*35238bceSAndroid Build Coastguard Worker
170*35238bceSAndroid Build Coastguard Workerdef getFilter (list, name):
171*35238bceSAndroid Build Coastguard Worker    for filter in list:
172*35238bceSAndroid Build Coastguard Worker        if filter.name == name:
173*35238bceSAndroid Build Coastguard Worker            return filter
174*35238bceSAndroid Build Coastguard Worker    return None
175*35238bceSAndroid Build Coastguard Worker
176*35238bceSAndroid Build Coastguard Workerdef getNumCasesInGroups (groups):
177*35238bceSAndroid Build Coastguard Worker    numCases = 0
178*35238bceSAndroid Build Coastguard Worker    for group in groups:
179*35238bceSAndroid Build Coastguard Worker        numCases += len(group.cases)
180*35238bceSAndroid Build Coastguard Worker    return numCases
181*35238bceSAndroid Build Coastguard Worker
182*35238bceSAndroid Build Coastguard Workerdef getCasesInSet (results, caseSet):
183*35238bceSAndroid Build Coastguard Worker    filtered = []
184*35238bceSAndroid Build Coastguard Worker    for case in results:
185*35238bceSAndroid Build Coastguard Worker        if case in caseSet:
186*35238bceSAndroid Build Coastguard Worker            filtered.append(case)
187*35238bceSAndroid Build Coastguard Worker    return filtered
188*35238bceSAndroid Build Coastguard Worker
189*35238bceSAndroid Build Coastguard Workerdef selectCasesInGroups (results, groups):
190*35238bceSAndroid Build Coastguard Worker    casesInGroups = set()
191*35238bceSAndroid Build Coastguard Worker    for group in groups:
192*35238bceSAndroid Build Coastguard Worker        for case in group.cases:
193*35238bceSAndroid Build Coastguard Worker            casesInGroups.add(case)
194*35238bceSAndroid Build Coastguard Worker    return getCasesInSet(results, casesInGroups)
195*35238bceSAndroid Build Coastguard Worker
196*35238bceSAndroid Build Coastguard Workerdef selectRandomSubset (results, groups, limit, seed):
197*35238bceSAndroid Build Coastguard Worker    selectedCases = set()
198*35238bceSAndroid Build Coastguard Worker    numSelect = min(limit, getNumCasesInGroups(groups))
199*35238bceSAndroid Build Coastguard Worker
200*35238bceSAndroid Build Coastguard Worker    random.seed(seed)
201*35238bceSAndroid Build Coastguard Worker    random.shuffle(groups)
202*35238bceSAndroid Build Coastguard Worker
203*35238bceSAndroid Build Coastguard Worker    groupNdx = 0
204*35238bceSAndroid Build Coastguard Worker    while len(selectedCases) < numSelect:
205*35238bceSAndroid Build Coastguard Worker        group = groups[groupNdx]
206*35238bceSAndroid Build Coastguard Worker        if len(group.cases) == 0:
207*35238bceSAndroid Build Coastguard Worker            del groups[groupNdx]
208*35238bceSAndroid Build Coastguard Worker            if groupNdx == len(groups):
209*35238bceSAndroid Build Coastguard Worker                groupNdx -= 1
210*35238bceSAndroid Build Coastguard Worker            continue # Try next
211*35238bceSAndroid Build Coastguard Worker
212*35238bceSAndroid Build Coastguard Worker        selected = random.choice(group.cases)
213*35238bceSAndroid Build Coastguard Worker        selectedCases.add(selected)
214*35238bceSAndroid Build Coastguard Worker        group.cases.remove(selected)
215*35238bceSAndroid Build Coastguard Worker
216*35238bceSAndroid Build Coastguard Worker        groupNdx = (groupNdx + 1) % len(groups)
217*35238bceSAndroid Build Coastguard Worker
218*35238bceSAndroid Build Coastguard Worker    return getCasesInSet(results, selectedCases)
219*35238bceSAndroid Build Coastguard Worker
220*35238bceSAndroid Build Coastguard Workerdef die (msg):
221*35238bceSAndroid Build Coastguard Worker    print(msg)
222*35238bceSAndroid Build Coastguard Worker    sys.exit(-1)
223*35238bceSAndroid Build Coastguard Worker
224*35238bceSAndroid Build Coastguard Worker# Named filter lists
225*35238bceSAndroid Build Coastguard WorkerFILTER_RULES = [
226*35238bceSAndroid Build Coastguard Worker    FilterRule("all", "No filtering", []),
227*35238bceSAndroid Build Coastguard Worker    FilterRule("all-pass", "All results must be 'Pass'", [lambda l: all(l, lambda r: r == 'Pass')]),
228*35238bceSAndroid Build Coastguard Worker    FilterRule("any-pass", "Any of results is 'Pass'", [lambda l: any(l, lambda r: r == 'Pass')]),
229*35238bceSAndroid Build Coastguard Worker    FilterRule("any-fail", "Any of results is not 'Pass' or 'NotSupported'", [lambda l: not all(l, lambda r: r == 'Pass' or r == 'NotSupported')]),
230*35238bceSAndroid Build Coastguard Worker    FilterRule("prev-failing", "Any except last result is failure", [lambda l: l[-1] == 'Pass' and not all(l[:-1], lambda r: r == 'Pass')]),
231*35238bceSAndroid Build Coastguard Worker    FilterRule("prev-passing", "Any except last result is 'Pass'", [lambda l: l[-1] != 'Pass' and any(l[:-1], lambda r: r == 'Pass')])
232*35238bceSAndroid Build Coastguard Worker]
233*35238bceSAndroid Build Coastguard Worker
234*35238bceSAndroid Build Coastguard Workerif __name__ == "__main__":
235*35238bceSAndroid Build Coastguard Worker    parser = OptionParser(usage = "usage: %prog [options] [caselist] [result csv file]")
236*35238bceSAndroid Build Coastguard Worker    parser.add_option("-f", "--filter", dest="filter", default="all", help="filter rule name")
237*35238bceSAndroid Build Coastguard Worker    parser.add_option("-l", "--list", action="store_true", dest="list", default=False, help="list available rules")
238*35238bceSAndroid Build Coastguard Worker    parser.add_option("-n", "--num", dest="limit", default=0, help="limit number of cases")
239*35238bceSAndroid Build Coastguard Worker    parser.add_option("-s", "--seed", dest="seed", default=0, help="use selected seed for random selection")
240*35238bceSAndroid Build Coastguard Worker    parser.add_option("-g", "--groups", dest="groups_file", default=None, help="select cases based on group list file")
241*35238bceSAndroid Build Coastguard Worker
242*35238bceSAndroid Build Coastguard Worker    (options, args) = parser.parse_args()
243*35238bceSAndroid Build Coastguard Worker
244*35238bceSAndroid Build Coastguard Worker    if options.list:
245*35238bceSAndroid Build Coastguard Worker        print("Available filter rules:")
246*35238bceSAndroid Build Coastguard Worker        for filter in FILTER_RULES:
247*35238bceSAndroid Build Coastguard Worker            print("  %s: %s" % (filter.name, filter.description))
248*35238bceSAndroid Build Coastguard Worker        sys.exit(0)
249*35238bceSAndroid Build Coastguard Worker
250*35238bceSAndroid Build Coastguard Worker    if len(args) == 0:
251*35238bceSAndroid Build Coastguard Worker        die("No input files specified")
252*35238bceSAndroid Build Coastguard Worker    elif len(args) > 2:
253*35238bceSAndroid Build Coastguard Worker        die("Too many arguments")
254*35238bceSAndroid Build Coastguard Worker
255*35238bceSAndroid Build Coastguard Worker    # Fetch filter
256*35238bceSAndroid Build Coastguard Worker    filter = getFilter(FILTER_RULES, options.filter)
257*35238bceSAndroid Build Coastguard Worker    if filter == None:
258*35238bceSAndroid Build Coastguard Worker        die("Unknown filter '%s'" % options.filter)
259*35238bceSAndroid Build Coastguard Worker
260*35238bceSAndroid Build Coastguard Worker    # Read case list
261*35238bceSAndroid Build Coastguard Worker    caselist = readCaseList(args[0])
262*35238bceSAndroid Build Coastguard Worker    if len(args) > 1:
263*35238bceSAndroid Build Coastguard Worker        results = readTestResults(args[1])
264*35238bceSAndroid Build Coastguard Worker        results = addResultsToCaseList(caselist, results)
265*35238bceSAndroid Build Coastguard Worker    else:
266*35238bceSAndroid Build Coastguard Worker        results = toResultList(caselist)
267*35238bceSAndroid Build Coastguard Worker
268*35238bceSAndroid Build Coastguard Worker    # Execute filters for results
269*35238bceSAndroid Build Coastguard Worker    for rule in filter.filters:
270*35238bceSAndroid Build Coastguard Worker        results = filterList(results, rule)
271*35238bceSAndroid Build Coastguard Worker
272*35238bceSAndroid Build Coastguard Worker    if options.limit != 0:
273*35238bceSAndroid Build Coastguard Worker        if options.groups_file != None:
274*35238bceSAndroid Build Coastguard Worker            groups = createGroups(results, readGroupList(options.groups_file))
275*35238bceSAndroid Build Coastguard Worker        else:
276*35238bceSAndroid Build Coastguard Worker            groups = createLeafGroups(results)
277*35238bceSAndroid Build Coastguard Worker        results = selectRandomSubset(results, groups, int(options.limit), int(options.seed))
278*35238bceSAndroid Build Coastguard Worker    elif options.groups_file != None:
279*35238bceSAndroid Build Coastguard Worker        groups = createGroups(results, readGroupList(options.groups_file))
280*35238bceSAndroid Build Coastguard Worker        results = selectCasesInGroups(results, groups)
281*35238bceSAndroid Build Coastguard Worker
282*35238bceSAndroid Build Coastguard Worker    # Print test set
283*35238bceSAndroid Build Coastguard Worker    for result in results:
284*35238bceSAndroid Build Coastguard Worker        print(result.name)
285