blob: 084e66d02f20bfaf193fec759e17b09cc53b2b70 [file] [edit]
#!/usr/bin/python
# CSS Test Source 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>
import re
import os
from os.path import join, exists, splitext, dirname, basename
from Sources import XHTMLSource, HTMLSource, SVGSource, SourceTree
class ExtensionMap:
""" Given a file extension mapping (e.g. {'.xht' : '.htm'}), provides
a translate function for paths.
"""
def __init__(self, extMap):
self.extMap = extMap
def translate(self, path):
for ext in self.extMap:
if path.endswith(ext):
return splitext(path)[0] + self.extMap[ext]
return path
class BasicFormat:
"""Base class. A Format manages all the conversions and location
transformations (e.g. subdirectory for all tests in that format)
associated with a test suite format.
The base class implementation performs no conversions or
format-specific location transformations."""
formatDirName = None
indexExt = '.htm'
convert = True # XXX hack to supress format conversion in support dirs, need to clean up output code to make this cleaner
def __init__(self, destroot, sourceTree, extMap=None, outputDirName=None):
"""Creates format root of the output tree. `destroot` is the root path
of the output tree.
extMap provides a file extension mapping, e.g. {'.xht' : '.htm'}
"""
self.root = join(destroot, outputDirName) if outputDirName else destroot
self.sourceTree = sourceTree
self.formatDirName = outputDirName
if not exists(self.root):
os.makedirs(self.root)
self.extMap = ExtensionMap(extMap or {})
self.subdir = None
def setSubDir(self, name=None):
"""Sets format to write into group subdirectory `name`.
"""
self.subdir = name
def destDir(self):
return join(self.root, self.subdir) if self.subdir else self.root
def dest(self, relpath):
"""Returns final destination of relpath in this format and ensures that the
parent directory exists."""
# Translate path
if (self.convert):
relpath = self.extMap.translate(relpath)
if (self.sourceTree.isReferenceAnywhere(relpath)):
relpath = join('reference', basename(relpath))
# XXX when forcing support files into support path, need to account for support/support
dest = join(self.root, self.subdir, relpath) if self.subdir \
else join(self.root, relpath)
# Ensure parent
parent = dirname(dest)
if not exists(parent):
os.makedirs(parent)
return dest
def write(self, source):
"""Write FileSource to destination, following all necessary
conversion methods."""
source.write(self, source)
testTransform = False
# def testTransform(self, outputString, source) if needed
class XHTMLFormat(BasicFormat):
"""Base class for XHTML test suite format. Builds into 'xhtml1' subfolder
of root.
"""
indexExt = '.xht'
def __init__(self, destroot, sourceTree, extMap=None, outputDirName='xhtml1'):
if not extMap:
extMap = {'.htm' : '.xht', '.html' : '.xht', '.xhtml' : '.xht' }
BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
def write(self, source):
# skip HTMLonly tests
if hasattr(source, 'hasFlag') and source.hasFlag('HTMLonly'):
return
if isinstance(source, HTMLSource) and self.convert:
source.write(self, source.serializeXHTML())
else:
source.write(self)
class HTMLFormat(BasicFormat):
"""Base class for HTML test suite format. Builds into 'html4' subfolder
of root.
"""
def __init__(self, destroot, sourceTree, extMap=None, outputDirName='html4'):
if not extMap:
extMap = {'.xht' : '.htm', '.xhtml' : '.htm', '.html' : '.htm' }
BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
def write(self, source):
# skip nonHTML tests
if hasattr(source, 'hasFlag') and source.hasFlag('nonHTML'):
return
if isinstance(source, XHTMLSource) and self.convert:
source.write(self, source.serializeHTML())
else:
source.write(self)
class HTML5Format(HTMLFormat):
def __init__(self, destroot, sourceTree, extMap=None, outputDirName='html'):
HTMLFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
def write(self, source):
# skip nonHTML tests
if hasattr(source, 'hasFlag') and source.hasFlag('nonHTML'):
return
if isinstance(source, XHTMLSource) and self.convert:
source.write(self, source.serializeHTML())
else:
source.write(self)
class SVGFormat(BasicFormat):
def __init__(self, destroot, sourceTree, extMap=None, outputDirName='svg'):
if not extMap:
extMap = {'.svg' : '.svg' }
BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
def write(self, source):
# skip non SVG tests
if isinstance(source, SVGSource):
source.write(self)
class XHTMLPrintFormat(XHTMLFormat):
"""Base class for XHTML Print test suite format. Builds into 'xhtml1print'
subfolder of root.
"""
def __init__(self, destroot, sourceTree, testSuiteName, extMap=None, outputDirName='xhtml1print'):
if not extMap:
extMap = {'.htm' : '.xht', '.html' : '.xht', '.xhtml' : '.xht' }
BasicFormat.__init__(self, destroot, sourceTree, extMap, outputDirName)
self.testSuiteName = testSuiteName
def write(self, source):
if (isinstance(source, XHTMLSource)):
if not source.hasFlag('HTMLonly'):
source.write(self, self.testTransform(source))
else:
XHTMLFormat.write(self, source)
def testTransform(self, source):
assert isinstance(source, XHTMLSource)
output = source.serializeXHTML('xhtml10')
headermeta = {'suitename' : self.testSuiteName,
'testid' : source.name(),
'margin' : '',
}
if re.search('@page\s*{[^}]*@', output):
# Don't use headers and footers when page tests margin boxes
output = re.sub('(<body[^>]*>)',
'\1\n' + self.__htmlstart % headermeta,
output);
output = re.sub('(</body[^>]*>)',
'\1\n' + self.__htmlend % headermeta,
output);
else:
# add margin rule only when @page statement does not exist
if not re.search('@page', output):
headermeta['margin'] = self.__margin
output = re.sub('</title>',
'</title>\n <style type="text/css">%s</style>' % \
(self.__css % headermeta),
output);
return output;
# template bits
__margin = 'margin: 7%;';
__font = 'font: italic 8pt sans-serif; color: gray;'
__css = """
@page { %s
%%(margin)s
counter-increment: page;
@top-left { content: "%%(suitename)s"; }
@top-right { content: "Test %%(testid)s"; }
@bottom-right { content: counter(page); }
}
""" % __font
__htmlstart = '<p style="%s">Start of %%(suitename)s %%(testid)s.</p>' % __font
__htmlend = '<p style="%s">End of %%(suitename)s %%(testid)s.</p>' % __font