123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- #!/usr/bin/python
- #
- # Licensed to the Apache Software Foundation (ASF) under one or more
- # contributor license agreements. See the NOTICE file distributed with
- # this work for additional information regarding copyright ownership.
- # The ASF licenses this file to You under the Apache License, Version 2.0
- # (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- # $Id$
-
- """A testcase generator for conditional borders and the collapsing border model, in the FO
- tree.
- Computes all the possible combinations of borders (retained/discarded, with/without header
- and footer, etc.) and generates the corresponding tables together with the expected
- resolved borders.
-
- The two functions to call are generateTestCases and generateTestCasesHeaderFooter; each of
- them returns a complete FO file on stdout and a table of resolved borders on stderr, to be
- included in the Java test case. This is all a bit rough be enough to get the testcases
- generated.
-
- Type definitions:
- border specification:
- {'length': <string, e.g. '4pt'>,
- 'cond': <'retain' or 'discard'>
- 'color': <string, e.g. 'black'>
- }
- """
-
- import sys;
- import copy;
-
- fo_table = 0
- fo_column = 1
- fo_body = 2
- fo_row = 3
- fo_cell = 4
-
- def printFOStart():
- print '<?xml version="1.0" standalone="no"?>'
- print '<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">'
- print ' <fo:layout-master-set>'
- print ' <fo:simple-page-master master-name="page" page-height="20cm" page-width="15cm" margin="1cm">'
- print ' <fo:region-body/>'
- print ' </fo:simple-page-master>'
- print ' </fo:layout-master-set>'
- print ' <fo:page-sequence master-reference="page" font-size="14pt">'
- print ' <fo:flow flow-name="xsl-region-body">'
- print
-
- def printFOEnd():
- print ' </fo:flow>'
- print ' </fo:page-sequence>'
- print '</fo:root>'
-
- def printBorder(side, border, indent):
- """Prints out the border specifications.
- Params:
- side: one of 'before', 'after', 'start', 'end'
- border: a border specification
- indent: for pretty-printing, string of whitespaces to put before the border
- """
- print indent + ' border-' + side + '-width.length="' + border['length'] + '"'
- print indent + ' border-' + side + '-width.conditionality="' + border['cond'] + '"'
- print indent + ' border-' + side + '-style="solid"'
- print indent + ' border-' + side + '-color="' + border['color'] + '"'
-
- class TableGenerator:
- """Generates on stdout tables with no header and footer, with the border
- specifications passed to this object; and on stderr the corresponding resolved borders
- in a Java array, for inclusion into the test case. As soon as a pair of border sets is
- recorded, a table is generated.
- """
-
- fobjs = [
- ('<fo:table width="10cm" space-before="12pt" table-layout="fixed"', '>'),
- ('<fo:table-column column-width="proportional-column-width(1)"', '/>'),
- ('<fo:table-body', '>'),
- ('<fo:table-row', '>'),
- ('<fo:table-cell', '>')
- ]
-
- bordersBefore = None
- resBefore = {}
- """The comma between each table; nothing before the first one."""
- separator = ''
-
- def addBorderSet(self, borderSet, resolution):
- """Records a new border set, and prints out a table if its number is even.
- The first set will be used for borders-before, the second one for borders-after.
-
- Params:
- borderSet: a list of 5 border specifications for resp. table, table-column,
- table-body, table-row and table-cell
- resolution: the resolved border for the rest case (for the normal and leading
- cases the resolution is always the same)
- """
- if not self.bordersBefore:
- self.bordersBefore = borderSet
- self.resBefore = resolution
- else:
- # First the table
- for i in range(5):
- fobj = self.fobjs[i]
- indent = ' ' * (6 + 2*i)
- print indent + fobj[0]
- printBorder('before', self.bordersBefore[i], indent)
- printBorder('after', borderSet[i], indent)
- print indent + fobj[1]
- print ' <fo:block>Cell</fo:block>'
- print ' </fo:table-cell>'
- print ' </fo:table-row>'
- print ' </fo:table-body>'
- print ' </fo:table>'
- print
- # Then the resolution
- sys.stderr.write(self.separator + '{')
- comma = ''
- for beforeAfter in [self.resBefore, resolution]:
- sys.stderr.write(comma + '{border' + beforeAfter['length']
- + ', Color.' + beforeAfter['color'] + '}')
- comma = ', '
- sys.stderr.write('}')
- self.separator = ',\n'
- # Reset
- self.bordersBefore = None
- self.resBefore = {}
-
- class TableHFGenerator:
- """Generates on stdout tables with headers and footers, and the border specifications
- passed to this object; and on stderr the corresponding resolved borders in a Java
- array."""
-
- fobjs = [
- ['<fo:table width="10cm" space-before="12pt" table-layout="fixed"', '>'],
- ['<fo:table-column column-width="proportional-column-width(1)"', '/>'],
- ['<fo:table-header', '>'],
- ['<fo:table-row', '>'],
- ['<fo:table-cell', '>']
- ]
-
- borderHeader = [] # border-before for the header.
- borderFooter = [] # border-after for the footer.
- bordersBody = [] # borders for the cells in the body.
-
- def addBorderHeader(self, borders, resolution):
- self.borderHeader.append((borders, resolution))
-
- def addBorderFooter(self, borders, resolution):
- self.borderFooter.append((borders, resolution))
-
- def addBordersBody(self, borders, resolution):
- self.bordersBody.append((borders, resolution))
-
- def finish(self):
- """Prints out the tables and the resolved borders."""
- separator = '' # The comma between each table, none before the first one
- for tableNum in range(len(self.borderHeader)):
- # First the table
- print ' <!-- Table ' + str(tableNum) + ' -->'
- for i in range(2):
- fobj = self.fobjs[i]
- indent = ' ' * (6 + 2*i)
- print indent + fobj[0]
- printBorder('before', self.borderHeader[tableNum][0][i], indent)
- printBorder('after', self.borderFooter[tableNum][0][i], indent)
- print indent + fobj[1]
- self.fobjs[fo_body][0] = '<fo:table-header'
- for i in range(2, 5):
- fobj = self.fobjs[i]
- indent = ' ' * (6 + 2*i)
- print indent + fobj[0]
- printBorder('before', self.borderHeader[tableNum][0][i], indent)
- printBorder('after', self.bordersBody[tableNum][0][i-2], indent)
- print indent + fobj[1]
- print ' <fo:block>Header</fo:block>'
- print ' </fo:table-cell>'
- print ' </fo:table-row>'
- print ' </fo:table-header>'
- self.fobjs[fo_body][0] = '<fo:table-footer'
- for i in range(2, 5):
- fobj = self.fobjs[i]
- indent = ' ' * (6 + 2*i)
- print indent + fobj[0]
- printBorder('before', self.bordersBody[tableNum][0][i+7], indent)
- printBorder('after', self.borderFooter[tableNum][0][i], indent)
- print indent + fobj[1]
- print ' <fo:block>Footer</fo:block>'
- print ' </fo:table-cell>'
- print ' </fo:table-row>'
- print ' </fo:table-footer>'
- self.fobjs[fo_body][0] = '<fo:table-body'
- for i in range(2, 5):
- fobj = self.fobjs[i]
- indent = ' ' * (6 + 2*i)
- print indent + fobj[0]
- printBorder('before', {'length': '4pt', 'cond': 'discard', 'color': 'black'}, indent)
- printBorder('after', self.bordersBody[tableNum][0][i+1], indent)
- print indent + fobj[1]
- print ' <fo:block>Cell1</fo:block>'
- print ' </fo:table-cell>'
- print ' </fo:table-row>'
- print ' </fo:table-body>'
- for i in range(2, 5):
- fobj = self.fobjs[i]
- indent = ' ' * (6 + 2*i)
- print indent + fobj[0]
- printBorder('before', self.bordersBody[tableNum][0][i+4], indent)
- printBorder('after', {'length': '4pt', 'cond': 'discard', 'color': 'blue'}, indent)
- print indent + fobj[1]
- print ' <fo:block>Cell1</fo:block>'
- print ' </fo:table-cell>'
- print ' </fo:table-row>'
- print ' </fo:table-body>'
- print ' </fo:table>'
- print
- # Then the resolutions
- sys.stderr.write(separator + '{')
- comma = ''
- for resHeadFoot in [self.borderHeader[tableNum][1], self.borderFooter[tableNum][1]]:
- for firstRest in ['first', 'rest']:
- sys.stderr.write(comma + '{border'
- + resHeadFoot[firstRest]['length']
- + ', Color.' + resHeadFoot[firstRest]['color']
- + '}')
- comma = ', '
- resBody = self.bordersBody[tableNum][1]
- for i in range(4):
- for normLeadRest in ['normal', 'lead', 'rest']:
- sys.stderr.write(', {border'
- + resBody[i][normLeadRest][0]
- + ', Color.' + resBody[i][normLeadRest][1]
- + '}')
- sys.stderr.write('}')
- separator = ',\n'
-
- def generateTestCases():
- """Generates testcases for table without header and footer."""
- def createAllCombinations():
- def createCombinations(n):
- if n == 0:
- allCombinations[0].append([])
- else:
- createCombinations(n-1)
- i = n
- while i > 0:
- for combinations in allCombinations[i-1]:
- allCombinations[i].append(copy.copy(combinations) + [n-1])
- i = i - 1
- allCombinations = [[] for i in range(6)]
- createCombinations(5)
- return allCombinations
-
- printFOStart()
- tableGenerator = TableGenerator()
-
- defaultBorders = []
- for color in ['black', 'red', 'magenta', 'blue', 'yellow']:
- defaultBorders.append({'length': '4pt', 'cond': 'discard', 'color': color})
- defaultBorders[fo_table]['length'] = '8pt'
-
- resolution = {'length': '0pt', 'color': 'black'}
- tableGenerator.addBorderSet(defaultBorders, resolution)
- for combinations in createAllCombinations()[1:]:
- for combination in combinations:
- retainedBorders = copy.deepcopy(defaultBorders)
- for index in combination:
- retainedBorders[index]['cond'] = 'retain'
- for index in combination:
- finalBorders = copy.deepcopy(retainedBorders)
- if index != fo_table:
- finalBorders[index]['length'] = '6pt'
- if fo_table in combination:
- resolution = {'length': '8pt', 'color': 'black'}
- else:
- resolution = {'length': '6pt', 'color': finalBorders[index]['color']}
- tableGenerator.addBorderSet(finalBorders, resolution)
- printFOEnd()
-
- def generateTestCasesHeaderFooter():
- """Generates testcases for table with headers and footers."""
- def generateBordersHeaderFooter(tableGenerator):
- defaultBorders = [
- {'length': '4pt', 'cond': 'discard', 'color': 'black'}, # table
- {'length': '4pt', 'cond': 'discard', 'color': 'black'}, # table-column
- {'length': '4pt', 'cond': 'discard', 'color': 'blue'}, # table-body
- {'length': '4pt', 'cond': 'discard', 'color': 'blue'}, # table-row
- {'length': '4pt', 'cond': 'discard', 'color': 'blue'} # table-cell
- ]
- defaultResolution = {
- 'first': {'length': '4pt', 'color': 'blue'},
- 'rest': {'length': '4pt', 'color': 'blue'}
- }
- for (winner, other) in [(fo_table, fo_column), (fo_column, fo_table)]:
- borders = copy.deepcopy(defaultBorders)
- borders[winner]['length'] = '8pt'
- resolution = copy.deepcopy(defaultResolution)
- resolution['first'] = {'length': '8pt', 'color': 'black'}
- for border in [
- ((other, '6pt', 'retain'), 'black'),
- ((fo_body, '6pt', 'discard'), 'blue'),
- ((fo_row, '6pt', 'discard'), 'blue'),
- ((fo_cell, '6pt', 'discard'), 'blue')
- ]:
- finalBorders = copy.deepcopy(borders)
- finalBorders[border[0][0]]['length'] = border[0][1]
- finalBorders[border[0][0]]['cond'] = border[0][2]
- finalResolution = copy.deepcopy(resolution)
- finalResolution['rest']['length'] = '6pt'
- finalResolution['rest']['color'] = border[1]
- tableGenerator.addBorderHeader(finalBorders, finalResolution)
- tableGenerator.addBorderFooter(finalBorders, finalResolution)
-
- def generateBordersBody(tableGenerator):
- # Named indices for readability
- header = 0
- rowh = 1
- cellh = 2
- body1 = 3
- row1 = 4
- cell1 = 5
- body2 = 6
- row2 = 7
- cell2 = 8
- footer = 9
- rowf = 10
- cellf = 11
-
- defaultBorders = [
- {'length': '4pt', 'cond': 'discard', 'color': 'red'}, # header
- {'length': '4pt', 'cond': 'discard', 'color': 'red'}, # header > row
- {'length': '4pt', 'cond': 'discard', 'color': 'red'}, # header > row > cell
- {'length': '4pt', 'cond': 'discard', 'color': 'black'}, # body1
- {'length': '4pt', 'cond': 'discard', 'color': 'black'}, # body1 > row
- {'length': '4pt', 'cond': 'discard', 'color': 'black'}, # body1 > row > cell
- {'length': '4pt', 'cond': 'discard', 'color': 'blue'}, # body2
- {'length': '4pt', 'cond': 'discard', 'color': 'blue'}, # body2 > row
- {'length': '4pt', 'cond': 'discard', 'color': 'blue'}, # body2 > row > cell
- {'length': '4pt', 'cond': 'discard', 'color': 'magenta'}, # footer
- {'length': '4pt', 'cond': 'discard', 'color': 'magenta'}, # footer > row
- {'length': '4pt', 'cond': 'discard', 'color': 'magenta'} # footer > row > cell
- ]
- defaultResolution = [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')}, # border-before cell 1
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'magenta')}, # border-after cell 1
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'red')}, # border-before cell 2
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')} # border-after cell 2
- ]
- # The following contains changes to the default borders. Depending on the object
- # targeted (in header, footer, body1 or body2), the affected border is either before
- # or after (the other one keeping its default value):
- # - for header: border-after
- # - for body1: border-after
- # - for body2: border-before
- # - for footer: border-before
- for setting in [
- {'borders': [(body2, '8pt', 'discard'), (body1, '6pt', 'discard')], 'res': [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')},
- {'normal': ('8pt', 'blue'), 'lead': ('6pt', 'black'), 'rest': ('4pt', 'magenta')},
- {'normal': ('8pt', 'blue'), 'lead': ('8pt', 'blue'), 'rest': ('4pt', 'red')},
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')}]},
- {'borders': [(row2, '8pt', 'discard'), (row1, '6pt', 'retain')], 'res': [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')},
- {'normal': ('8pt', 'blue'), 'lead': ('6pt', 'black'), 'rest': ('6pt', 'black')},
- {'normal': ('8pt', 'blue'), 'lead': ('8pt', 'blue'), 'rest': ('4pt', 'red')},
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')}]},
- {'borders': [(cell2, '6pt', 'retain'), (cellh, '8pt', 'discard'), (cell1, '4pt', 'retain')], 'res': [
- {'normal': ('8pt', 'red'), 'lead': ('8pt', 'red'), 'rest': ('8pt', 'red')},
- {'normal': ('6pt', 'blue'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'black')},
- {'normal': ('6pt', 'blue'), 'lead': ('8pt', 'red'), 'rest': ('8pt', 'red')},
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')}]},
- {'borders': [(body2, '6pt', 'retain'), (rowh, '8pt', 'discard'), (row1, '4pt', 'retain')], 'res': [
- {'normal': ('8pt', 'red'), 'lead': ('8pt', 'red'), 'rest': ('8pt', 'red')},
- {'normal': ('6pt', 'blue'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'magenta')},
- {'normal': ('6pt', 'blue'), 'lead': ('8pt', 'red'), 'rest': ('8pt', 'red')},
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')}]},
- # Almost a copy-paste of the above, swapping 1 and 2, header and footer
- {'borders': [(body1, '8pt', 'discard'), (body2, '6pt', 'discard')], 'res': [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')},
- {'normal': ('8pt', 'black'), 'lead': ('8pt', 'black'), 'rest': ('4pt', 'magenta')},
- {'normal': ('8pt', 'black'), 'lead': ('6pt', 'blue'), 'rest': ('4pt', 'red')},
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')}]},
- {'borders': [(cell1, '8pt', 'discard'), (cell2, '6pt', 'retain')], 'res': [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')},
- {'normal': ('8pt', 'black'), 'lead': ('8pt', 'black'), 'rest': ('4pt', 'magenta')},
- {'normal': ('8pt', 'black'), 'lead': ('6pt', 'blue'), 'rest': ('6pt', 'blue')},
- {'normal': ('4pt', 'blue'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'magenta')}]},
- {'borders': [(row1, '6pt', 'retain'), (footer, '8pt', 'discard'), (body2, '4pt', 'retain')], 'res': [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')},
- {'normal': ('6pt', 'black'), 'lead': ('8pt', 'magenta'), 'rest': ('8pt', 'magenta')},
- {'normal': ('6pt', 'black'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'red')},
- {'normal': ('8pt', 'magenta'), 'lead': ('8pt', 'magenta'), 'rest': ('8pt', 'magenta')}]},
- {'borders': [(body1, '8pt', 'retain'), (cellf, '6pt', 'discard'), (row2, '4pt', 'retain')], 'res': [
- {'normal': ('4pt', 'black'), 'lead': ('4pt', 'black'), 'rest': ('4pt', 'red')},
- {'normal': ('8pt', 'black'), 'lead': ('8pt', 'black'), 'rest': ('8pt', 'black')},
- {'normal': ('8pt', 'black'), 'lead': ('4pt', 'blue'), 'rest': ('4pt', 'red')},
- {'normal': ('6pt', 'magenta'), 'lead': ('6pt', 'magenta'), 'rest': ('6pt', 'magenta')}]}]:
- finalBorders = copy.deepcopy(defaultBorders)
- for border in setting['borders']:
- finalBorders[border[0]]['length'] = border[1]
- finalBorders[border[0]]['cond'] = border[2]
- tableGenerator.addBordersBody(finalBorders, setting['res'])
-
- tableGenerator = TableHFGenerator()
- printFOStart()
- generateBordersHeaderFooter(tableGenerator)
- generateBordersBody(tableGenerator)
- tableGenerator.finish()
- printFOEnd()
-
- # Uncomment the appropriate line
- #generateTestCases()
- #generateTestCasesHeaderFooter()
|