1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
|
#!/usr/bin/python
# CSS Test Suite Manipulation Library
# Initial code by fantasai, joint copyright 2010 W3C and Microsoft
# Licensed under BSD 3-Clause: <http://www.w3.org/Consortium/Legal/2008/03-bsd-license>
# Define contains vmethod for Template Toolkit
from template.stash import list_op
@list_op("contains")
def list_contains(l, x):
return x in l
import sys
import re
import os
import codecs
from os.path import join, exists, abspath
from template import Template
import w3ctestlib
from Utils import listfiles, escapeToNamedASCII
from OutputFormats import ExtensionMap
import shutil
class Section:
def __init__(self, uri, title, numstr):
self.uri = uri
self.title = title
self.numstr = numstr
self.tests = []
def __cmp__(self, other):
return cmp(self.natsortkey(), other.natsortkey())
def chapterNum(self):
return self.numstr.partition('.')[0]
def natsortkey(self):
chunks = self.numstr.partition('.#')[0].split('.')
for index in range(len(chunks)):
if chunks[index].isdigit():
# wrap in tuple with '0' to explicitly specify numbers come first
chunks[index] = (0, int(chunks[index]))
else:
chunks[index] = (1, chunks[index])
return (chunks, self.numstr)
class Indexer:
def __init__(self, suite, sections, suites, flags, splitChapter=False, templatePathList=None,
extraData=None, overviewTmplNames=None, overviewCopyExts=('.css', 'htaccess')):
"""Initialize indexer with TestSuite `suite` toc data file
`tocDataPath` and additional template paths in list `templatePathList`.
The toc data file should be list of tab-separated records, one
per line, of each spec section's uri, number/letter, and title.
`splitChapter` selects a single page index if False, chapter
indicies if True.
`extraData` can be a dictionary whose data gets passed to the templates.
`overviewCopyExts` lists file extensions that should be found
and copied from the template path into the main build directory.
The default value is ['.css', 'htaccess'].
`overviewTemplateNames` lists template names that should be
processed from the template path into the main build directory.
The '.tmpl' extension, if any, is stripped from the output filename.
The default value is ['index.htm.tmpl', 'index.xht.tmpl', 'testinfo.data.tmpl']
"""
self.suite = suite
self.splitChapter = splitChapter
self.extraData = extraData
self.overviewCopyExtPat = re.compile('.*(%s)$' % '|'.join(overviewCopyExts))
self.overviewTmplNames = overviewTmplNames if overviewTmplNames is not None \
else ['index.htm.tmpl', 'index.xht.tmpl', 'testinfo.data.tmpl',
'implementation-report-TEMPLATE.data.tmpl']
# Initialize template engine
self.templatePath = [join(w3ctestlib.__path__[0], 'templates')]
if templatePathList:
self.templatePath.extend(templatePathList)
self.templatePath = [abspath(path) for path in self.templatePath]
self.tt = Template({
'INCLUDE_PATH': self.templatePath,
'ENCODING' : 'utf-8',
'PRE_CHOMP' : 1,
'POST_CHOMP' : 0,
})
# Load toc data
self.sections = {}
for uri, numstr, title in sections:
uri = intern(uri.encode('utf-8'))
uriKey = intern(self._normalizeScheme(uri))
numstr = escapeToNamedASCII(numstr)
title = escapeToNamedASCII(title) if title else None
self.sections[uriKey] = Section(uri, title, numstr)
self.suites = suites
self.flags = flags
# Initialize storage
self.errors = {}
self.contributors = {}
self.alltests = []
def _normalizeScheme(self, uri):
if (uri and uri.startswith('http:')):
return 'https:' + uri[5:]
return uri
def indexGroup(self, group):
for test in group.iterTests():
data = test.getMetadata()
if data: # Shallow copy for template output
data = dict(data)
data['file'] = '/'.join((group.name, test.relpath)) \
if group.name else test.relpath
if (data['scripttest']):
data['flags'].append(intern('script'))
self.alltests.append(data)
for uri in data['links']:
uri = self._normalizeScheme(uri)
uri = uri.replace(self._normalizeScheme(self.suite.draftroot), self._normalizeScheme(self.suite.specroot))
if self.sections.has_key(uri):
testlist = self.sections[uri].tests.append(data)
for credit in data['credits']:
self.contributors[credit[0]] = credit[1]
else:
self.errors[test.sourcepath] = test.errors
def __writeTemplate(self, template, data, outfile):
o = self.tt.process(template, data)
with open(outfile, 'w') as f:
f.write(o.encode('utf-8'))
def writeOverview(self, destDir, errorOut=sys.stderr, addTests=[]):
"""Write format-agnostic pages such as test suite overview pages,
test data files, and error reports.
Indexed errors are reported to errorOut, which must be either
an output handle such as sys.stderr, a tuple of
(template filename string, output filename string)
or None to suppress error output.
`addTests` is a list of additional test paths, relative to the
overview root; it is intended for indexing raw tests
"""
# Set common values
data = self.extraData.copy()
data['suitetitle'] = self.suite.title
data['suite'] = self.suite.name
data['specroot'] = self.suite.specroot
data['draftroot'] = self.suite.draftroot
data['contributors'] = self.contributors
data['tests'] = self.alltests
data['extmap'] = ExtensionMap({'.xht':'', '.html':'', '.htm':'', '.svg':''})
data['formats'] = self.suite.formats
data['addtests'] = addTests
data['suites'] = self.suites
data['flagInfo'] = self.flags
data['formatInfo'] = { 'html4': { 'report': True, 'path': 'html4', 'ext': 'htm', 'filter': 'nonHTML'},
'html5': { 'report': True, 'path': 'html', 'ext': 'htm', 'filter': 'nonHTML' },
'xhtml1': { 'report': True, 'path': 'xhtml1', 'ext': 'xht', 'filter': 'HTMLonly' },
'xhtml1print': { 'report': False, 'path': 'xhtml1print', 'ext': 'xht', 'filter': 'HTMLonly' },
'svg': { 'report': True, 'path': 'svg', 'ext': 'svg', 'filter': 'HTMLonly' }
}
# Copy simple copy files
for tmplDir in reversed(self.templatePath):
files = listfiles(tmplDir)
for file in files:
if self.overviewCopyExtPat.match(file):
shutil.copy(join(tmplDir, file), join(destDir, file))
# Generate indexes
for tmpl in self.overviewTmplNames:
out = tmpl[0:-5] if tmpl.endswith('.tmpl') else tmpl
self.__writeTemplate(tmpl, data, join(destDir, out))
# Report errors
if (self.errors):
if type(errorOut) is type(('tmpl','out')):
data['errors'] = errors
self.__writeTemplate(errorOut[0], data, join(destDir, errorOut[1]))
else:
sys.stdout.flush()
for errorLocation in self.errors:
print >> errorOut, "Error in %s: %s" % \
(errorLocation, ' '.join([str(error) for error in self.errors[errorLocation]]))
def writeIndex(self, format):
"""Write indices into test suite build output through format `format`.
"""
# Set common values
data = self.extraData.copy()
data['suitetitle'] = self.suite.title
data['suite'] = self.suite.name
data['specroot'] = self.suite.specroot
data['draftroot'] = self.suite.draftroot
data['indexext'] = format.indexExt
data['isXML'] = format.indexExt.startswith('.x')
data['formatdir'] = format.formatDirName
data['extmap'] = format.extMap
data['tests'] = self.alltests
data['suites'] = self.suites
data['flagInfo'] = self.flags
# Generate indices:
# Reftest indices
self.__writeTemplate('reftest-toc.tmpl', data,
format.dest('reftest-toc%s' % format.indexExt))
self.__writeTemplate('reftest.tmpl', data,
format.dest('reftest.list'))
# Table of Contents
sectionlist = sorted(self.sections.values())
if self.splitChapter:
# Split sectionlist into chapters
chapters = []
lastChapNum = '$' # some nonmatching initial char
chap = None
for section in sectionlist:
if (section.title and (section.chapterNum() != lastChapNum)):
lastChapNum = section.chapterNum()
chap = section
chap.sections = []
chap.testcount = 0
chap.testnames = set()
chapters.append(chap)
chap.testnames.update([test['name'] for test in section.tests])
chap.testcount = len(chap.testnames)
chap.sections.append(section)
# Generate main toc
data['chapters'] = chapters
self.__writeTemplate('chapter-toc.tmpl', data,
format.dest('toc%s' % format.indexExt))
del data['chapters']
# Generate chapter tocs
for chap in chapters:
data['chaptertitle'] = chap.title
data['testcount'] = chap.testcount
data['sections'] = chap.sections
self.__writeTemplate('test-toc.tmpl', data, format.dest('chapter-%s%s' \
% (chap.numstr, format.indexExt)))
else: # not splitChapter
data['chapters'] = sectionlist
self.__writeTemplate('test-toc.tmpl', data,
format.dest('toc%s' % format.indexExt))
del data['chapters']
|