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