summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py')
-rwxr-xr-xdom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py532
1 files changed, 532 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py b/dom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py
new file mode 100755
index 000000000..1b8888ab1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py
@@ -0,0 +1,532 @@
+#!/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' || " \
+ "(os == 'win' && os_version == '5.1'))"
+
+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!')