#!/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': , 'cond': <'retain' or 'discard'> 'color': } """ import sys; import copy; fo_table = 0 fo_column = 1 fo_body = 2 fo_row = 3 fo_cell = 4 def printFOStart(): print '' print '' print ' ' print ' ' print ' ' print ' ' print ' ' print ' ' print ' ' print def printFOEnd(): print ' ' print ' ' print '' 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 = [ (''), (''), (''), (''), ('') ] 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 ' Cell' print ' ' print ' ' print ' ' print ' ' 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 = [ [''], [''], [''], [''], [''] ] 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 ' ' 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] = 'Header' print ' ' print ' ' print ' ' self.fobjs[fo_body][0] = 'Footer' print ' ' print ' ' print ' ' self.fobjs[fo_body][0] = 'Cell1' print ' ' print ' ' print ' ' 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 ' Cell1' print ' ' print ' ' print ' ' print ' ' 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()