gecko-dev/dom/canvas/test/webgl-conf/generate-wrappers-and-manif...

532 строки
14 KiB
Python
Executable File

#!/usr/bin/env python
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Write a Mochitest manifest for WebGL conformance test files.
import os
import re
# All paths in this file are based where this file is run.
WRAPPER_TEMPLATE_FILE = 'mochi-wrapper.html.template'
MANIFEST_TEMPLATE_FILE = 'mochitest.ini.template'
ERRATA_FILE = 'mochitest-errata.ini'
DEST_MANIFEST_PATHSTR = 'generated-mochitest.ini'
BASE_TEST_LIST_PATHSTR = 'checkout/00_test_list.txt'
GENERATED_PATHSTR = 'generated'
WEBGL2_TEST_MANGLE = '2_'
PATH_SEP_MANGLING = '__'
WEBGL2_SKIP_IF_CONDITION = "(os == 'android' || os == 'linux')"
SUPPORT_DIRS = [
'checkout',
]
EXTRA_SUPPORT_FILES = [
'always-fail.html',
'iframe-passthrough.css',
'mochi-single.html',
]
ACCEPTABLE_ERRATA_KEYS = set([
'fail-if',
'skip-if',
'subsuite',
])
########################################################################
# GetTestList
def GetTestList():
split = BASE_TEST_LIST_PATHSTR.rsplit('/', 1)
basePath = '.'
testListFile = split[-1]
if len(split) == 2:
basePath = split[0]
allowWebGL1 = True
allowWebGL2 = True
alwaysFailEntry = TestEntry('always-fail.html', True, False)
testList = [alwaysFailEntry]
AccumTests(basePath, testListFile, allowWebGL1, allowWebGL2, testList)
for x in testList:
x.path = os.path.relpath(x.path, basePath).replace(os.sep, '/')
continue
return testList
##############################
# Internals
def IsVersionLess(a, b):
aSplit = [int(x) for x in a.split('.')]
bSplit = [int(x) for x in b.split('.')]
while len(aSplit) < len(bSplit):
aSplit.append(0)
while len(aSplit) > len(bSplit):
bSplit.append(0)
for i in range(len(aSplit)):
aVal = aSplit[i]
bVal = bSplit[i]
if aVal == bVal:
continue
return aVal < bVal
return False
class TestEntry:
def __init__(self, path, webgl1, webgl2):
self.path = path
self.webgl1 = webgl1
self.webgl2 = webgl2
return
def AccumTests(pathStr, listFile, allowWebGL1, allowWebGL2, out_testList):
listPathStr = pathStr + '/' + listFile
listPath = listPathStr.replace('/', os.sep)
assert os.path.exists(listPath), 'Bad `listPath`: ' + listPath
with open(listPath, 'rb') as fIn:
lineNum = 0
for line in fIn:
lineNum += 1
line = line.rstrip()
if not line:
continue
curLine = line.lstrip()
if curLine.startswith('//'):
continue
if curLine.startswith('#'):
continue
webgl1 = allowWebGL1
webgl2 = allowWebGL2
while curLine.startswith('--'): # '--min-version 1.0.2 foo.html'
(flag, curLine) = curLine.split(' ', 1)
if flag == '--min-version':
(minVersion, curLine) = curLine.split(' ', 1)
if not IsVersionLess(minVersion, "2.0.0"): # >= 2.0.0
webgl1 = False
break
elif flag == '--max-version':
(maxVersion, curLine) = curLine.split(' ', 1)
if IsVersionLess(maxVersion, "2.0.0"):
webgl2 = False
break
elif flag == '--slow':
continue # TODO
else:
text = 'Unknown flag \'{}\': {}:{}: {}'.format(flag, listPath,
lineNum, line)
assert False, text
continue
assert(webgl1 or webgl2)
split = curLine.rsplit('.', 1)
assert len(split) == 2, 'Bad split for `line`: ' + line
(name, ext) = split
if ext == 'html':
newTestFilePathStr = pathStr + '/' + curLine
entry = TestEntry(newTestFilePathStr, webgl1, webgl2)
out_testList.append(entry)
continue
assert ext == 'txt', 'Bad `ext` on `line`: ' + line
split = curLine.rsplit('/', 1)
nextListFile = split[-1]
nextPathStr = ''
if len(split) != 1:
nextPathStr = split[0]
nextPathStr = pathStr + '/' + nextPathStr
AccumTests(nextPathStr, nextListFile, webgl1, webgl2, out_testList)
continue
return
########################################################################
# Templates
def FillTemplate(inFilePath, templateDict, outFilePath):
templateShell = ImportTemplate(inFilePath)
OutputFilledTemplate(templateShell, templateDict, outFilePath)
return
def ImportTemplate(inFilePath):
with open(inFilePath, 'rb') as f:
return TemplateShell(f)
def OutputFilledTemplate(templateShell, templateDict, outFilePath):
spanStrList = templateShell.Fill(templateDict)
with open(outFilePath, 'wb') as f:
f.writelines(spanStrList)
return
##############################
# Internals
def WrapWithIndent(lines, indentLen):
split = lines.split('\n')
if len(split) == 1:
return lines
ret = [split[0]]
indentSpaces = ' ' * indentLen
for line in split[1:]:
ret.append(indentSpaces + line)
return '\n'.join(ret)
templateRE = re.compile('(%%.*?%%)')
assert templateRE.split(' foo = %%BAR%%;') == [' foo = ', '%%BAR%%', ';']
class TemplateShellSpan:
def __init__(self, span):
self.span = span
self.isLiteralSpan = True
if self.span.startswith('%%') and self.span.endswith('%%'):
self.isLiteralSpan = False
self.span = self.span[2:-2]
return
def Fill(self, templateDict, indentLen):
if self.isLiteralSpan:
return self.span
assert self.span in templateDict, '\'' + self.span + '\' not in dict!'
filling = templateDict[self.span]
return WrapWithIndent(filling, indentLen)
class TemplateShell:
def __init__(self, iterableLines):
spanList = []
curLiteralSpan = []
for line in iterableLines:
split = templateRE.split(line)
for cur in split:
isTemplateSpan = cur.startswith('%%') and cur.endswith('%%')
if not isTemplateSpan:
curLiteralSpan.append(cur)
continue
if curLiteralSpan:
span = ''.join(curLiteralSpan)
span = TemplateShellSpan(span)
spanList.append(span)
curLiteralSpan = []
assert len(cur) >= 4
span = TemplateShellSpan(cur)
spanList.append(span)
continue
continue
if curLiteralSpan:
span = ''.join(curLiteralSpan)
span = TemplateShellSpan(span)
spanList.append(span)
self.spanList = spanList
return
# Returns spanStrList.
def Fill(self, templateDict):
indentLen = 0
ret = []
for span in self.spanList:
span = span.Fill(templateDict, indentLen)
ret.append(span)
# Get next `indentLen`.
try:
lineStartPos = span.rindex('\n') + 1
# let span = 'foo\nbar'
# len(span) is 7
# lineStartPos is 4
indentLen = len(span) - lineStartPos
except ValueError:
indentLen += len(span)
continue
return ret
########################################################################
# Output
def IsWrapperWebGL2(wrapperPath):
return wrapperPath.startswith(GENERATED_PATHSTR + '/test_' + WEBGL2_TEST_MANGLE)
def WriteWrapper(entryPath, webgl2, templateShell, wrapperPathAccum):
mangledPath = entryPath.replace('/', PATH_SEP_MANGLING)
maybeWebGL2Mangle = ''
if webgl2:
maybeWebGL2Mangle = WEBGL2_TEST_MANGLE
# Mochitests must start with 'test_' or similar, or the test
# runner will ignore our tests.
# The error text is "is not a valid test".
wrapperFileName = 'test_' + maybeWebGL2Mangle + mangledPath
wrapperPath = GENERATED_PATHSTR + '/' + wrapperFileName
print('Adding wrapper: ' + wrapperPath)
args = ''
if webgl2:
args = '?webglVersion=2'
templateDict = {
'TEST_PATH': entryPath,
'ARGS': args,
}
OutputFilledTemplate(templateShell, templateDict, wrapperPath)
if webgl2:
assert IsWrapperWebGL2(wrapperPath)
wrapperPathAccum.append(wrapperPath)
return
def WriteWrappers(testEntryList):
templateShell = ImportTemplate(WRAPPER_TEMPLATE_FILE)
generatedDirPath = GENERATED_PATHSTR.replace('/', os.sep)
if not os.path.exists(generatedDirPath):
os.mkdir(generatedDirPath)
assert os.path.isdir(generatedDirPath)
wrapperPathList = []
for entry in testEntryList:
if entry.webgl1:
WriteWrapper(entry.path, False, templateShell, wrapperPathList)
if entry.webgl2:
WriteWrapper(entry.path, True, templateShell, wrapperPathList)
continue
print('{} wrappers written.\n'.format(len(wrapperPathList)))
return wrapperPathList
kManifestRelPathStr = os.path.relpath('.', os.path.dirname(DEST_MANIFEST_PATHSTR))
kManifestRelPathStr = kManifestRelPathStr.replace(os.sep, '/')
def ManifestPathStr(pathStr):
pathStr = kManifestRelPathStr + '/' + pathStr
return os.path.normpath(pathStr).replace(os.sep, '/')
def WriteManifest(wrapperPathStrList, supportPathStrList):
destPathStr = DEST_MANIFEST_PATHSTR
print 'Generating manifest: ' + destPathStr
errataMap = LoadErrata()
# DEFAULT_ERRATA
defaultSectionName = 'DEFAULT'
defaultSectionLines = []
if defaultSectionName in errataMap:
defaultSectionLines = errataMap[defaultSectionName]
del errataMap[defaultSectionName]
defaultSectionStr = '\n'.join(defaultSectionLines)
# SUPPORT_FILES
supportPathStrList = [ManifestPathStr(x) for x in supportPathStrList]
supportPathStrList = sorted(supportPathStrList)
supportFilesStr = '\n'.join(supportPathStrList)
# MANIFEST_TESTS
manifestTestLineList = []
wrapperPathStrList = sorted(wrapperPathStrList)
for wrapperPathStr in wrapperPathStrList:
#print 'wrapperPathStr: ' + wrapperPathStr
wrapperManifestPathStr = ManifestPathStr(wrapperPathStr)
sectionName = '[' + wrapperManifestPathStr + ']'
manifestTestLineList.append(sectionName)
errataLines = []
if wrapperPathStr in errataMap:
errataLines = errataMap[wrapperPathStr]
del errataMap[wrapperPathStr]
if IsWrapperWebGL2(wrapperPathStr):
needsSkip = True
for i in range(len(errataLines)):
if errataLines[i].startswith('skip-if'):
errataLines[i] += ' || ' + WEBGL2_SKIP_IF_CONDITION
needsSkip = False
continue
if needsSkip:
errataLines.append('skip-if = ' + WEBGL2_SKIP_IF_CONDITION)
manifestTestLineList += errataLines
continue
if errataMap:
print 'Errata left in map:'
for x in errataMap.keys():
print ' '*4 + x
assert False
manifestTestsStr = '\n'.join(manifestTestLineList)
# Fill the template.
templateDict = {
'DEFAULT_ERRATA': defaultSectionStr,
'SUPPORT_FILES': supportFilesStr,
'MANIFEST_TESTS': manifestTestsStr,
}
destPath = destPathStr.replace('/', os.sep)
FillTemplate(MANIFEST_TEMPLATE_FILE, templateDict, destPath)
return
##############################
# Internals
kManifestHeaderRegex = re.compile(r'[[]([^]]*)[]]')
def LoadINI(path):
curSectionName = None
curSectionMap = {}
lineNum = 0
ret = {}
ret[curSectionName] = (lineNum, curSectionMap)
with open(path, 'rb') as f:
for line in f:
lineNum += 1
line = line.strip()
if not line:
continue
if line[0] in [';', '#']:
continue
if line[0] == '[':
assert line[-1] == ']', '{}:{}'.format(path, lineNum)
curSectionName = line[1:-1]
assert curSectionName not in ret, 'Line {}: Duplicate section: {}'.format(lineNum, line)
curSectionMap = {}
ret[curSectionName] = (lineNum, curSectionMap)
continue
split = line.split('=', 1)
key = split[0].strip()
val = ''
if len(split) == 2:
val = split[1].strip()
curSectionMap[key] = (lineNum, val)
continue
return ret
def LoadErrata():
iniMap = LoadINI(ERRATA_FILE)
ret = {}
for (sectionName, (sectionLineNum, sectionMap)) in iniMap.iteritems():
curLines = []
if sectionName == None:
continue
elif sectionName != 'DEFAULT':
path = sectionName.replace('/', os.sep)
assert os.path.exists(path), 'Errata line {}: Invalid file: {}'.format(sectionLineNum, sectionName)
for (key, (lineNum, val)) in sectionMap.iteritems():
assert key in ACCEPTABLE_ERRATA_KEYS, 'Line {}: {}'.format(lineNum, key)
curLine = '{} = {}'.format(key, val)
curLines.append(curLine)
continue
ret[sectionName] = curLines
continue
return ret
########################################################################
def GetSupportFileList():
ret = EXTRA_SUPPORT_FILES[:]
for pathStr in SUPPORT_DIRS:
ret += GetFilePathListForDir(pathStr)
continue
for pathStr in ret:
path = pathStr.replace('/', os.sep)
assert os.path.exists(path), path + '\n\n\n' + 'pathStr: ' + str(pathStr)
continue
return ret
def GetFilePathListForDir(baseDir):
ret = []
for root, folders, files in os.walk(baseDir):
for f in files:
filePath = os.path.join(root, f)
filePath = filePath.replace(os.sep, '/')
ret.append(filePath)
return ret
if __name__ == '__main__':
fileDir = os.path.dirname(__file__)
assert not fileDir, 'Run this file from its directory, not ' + fileDir
testEntryList = GetTestList()
wrapperPathStrList = WriteWrappers(testEntryList)
supportPathStrList = GetSupportFileList()
WriteManifest(wrapperPathStrList, supportPathStrList)
print('Done!')