Initial commit

This commit is contained in:
Bassem Girgis
2018-12-20 17:34:07 -06:00
parent 7a2d899662
commit 81b4b9e273
34743 changed files with 5940233 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
#-------------------------------------------------------------------------
# CxxTest: A lightweight C++ unit testing library.
# Copyright (c) 2008 Sandia Corporation.
# This software is distributed under the LGPL License v3
# For more information, see the COPYING file in the top CxxTest directory.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------
"""cxxtest: A Python package that supports the CxxTest test framework for C/C++.
.. _CxxTest: http://cxxtest.com/
CxxTest is a unit testing framework for C++ that is similar in
spirit to JUnit, CppUnit, and xUnit. CxxTest is easy to use because
it does not require precompiling a CxxTest testing library, it
employs no advanced features of C++ (e.g. RTTI) and it supports a
very flexible form of test discovery.
The cxxtest Python package includes capabilities for parsing C/C++ source files and generating
CxxTest drivers.
"""
from cxxtest.__release__ import __version__, __date__
__date__
__version__
__maintainer__ = "William E. Hart"
__maintainer_email__ = "whart222@gmail.com"
__license__ = "LGPL"
__url__ = "http://cxxtest.com"
from cxxtest.cxxtestgen import *

View File

@@ -0,0 +1,13 @@
#-------------------------------------------------------------------------
# CxxTest: A lightweight C++ unit testing library.
# Copyright (c) 2008 Sandia Corporation.
# This software is distributed under the LGPL License v3
# For more information, see the COPYING file in the top CxxTest directory.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------
""" Release Information for cxxtest """
__version__ = '4.4'
__date__ = "2014-06-03"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
#-------------------------------------------------------------------------
# CxxTest: A lightweight C++ unit testing library.
# Copyright (c) 2008 Sandia Corporation.
# This software is distributed under the LGPL License v3
# For more information, see the COPYING file in the top CxxTest directory.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------
#
# TODO: add line number info
# TODO: add test function names
#
import sys
import re
from .cxxtest_misc import abort
from . import cxx_parser
import re
def cstr( str ):
'''Convert a string to its C representation'''
return '"' + re.sub('\\\\', '\\\\\\\\', str ) + '"'
def scanInputFiles(files, _options):
'''Scan all input files for test suites'''
suites=[]
for file in files:
try:
print("Parsing file "+file, end=' ')
sys.stdout.flush()
parse_info = cxx_parser.parse_cpp(filename=file,optimize=1)
except IOError as err:
print(" error.")
print(str(err))
continue
print("done.")
sys.stdout.flush()
#
# WEH: see if it really makes sense to use parse information to
# initialize this data. I don't think so...
#
_options.haveStandardLibrary=1
if not parse_info.noExceptionLogic:
_options.haveExceptionHandling=1
#
keys = list(parse_info.index.keys())
tpat = re.compile("[Tt][Ee][Ss][Tt]")
for key in keys:
if parse_info.index[key].scope_t == "class" and parse_info.is_baseclass(key,"CxxTest::TestSuite"):
name=parse_info.index[key].name
if key.startswith('::'):
fullname = key[2:]
else:
fullname = key
suite = {
'fullname' : fullname,
'name' : name,
'file' : file,
'cfile' : cstr(file),
'line' : str(parse_info.index[key].lineno),
'generated' : 0,
'object' : 'suite_%s' % fullname.replace('::','_'),
'dobject' : 'suiteDescription_%s' % fullname.replace('::','_'),
'tlist' : 'Tests_%s' % fullname.replace('::','_'),
'tests' : [],
'lines' : [] }
for fn in parse_info.get_functions(key,quiet=True):
tname = fn[0]
lineno = str(fn[1])
if tname.startswith('createSuite'):
# Indicate that we're using a dynamically generated test suite
suite['create'] = str(lineno) # (unknown line)
if tname.startswith('destroySuite'):
# Indicate that we're using a dynamically generated test suite
suite['destroy'] = str(lineno) # (unknown line)
if not tpat.match(tname):
# Skip non-test methods
continue
test = { 'name' : tname,
'suite' : suite,
'class' : 'TestDescription_suite_%s_%s' % (suite['fullname'].replace('::','_'), tname),
'object' : 'testDescription_suite_%s_%s' % (suite['fullname'].replace('::','_'), tname),
'line' : lineno,
}
suite['tests'].append(test)
suites.append(suite)
if not _options.root:
ntests = 0
for suite in suites:
ntests += len(suite['tests'])
if ntests == 0:
abort( 'No tests defined' )
#
return [_options, suites]

View File

@@ -0,0 +1,78 @@
#-------------------------------------------------------------------------
# CxxTest: A lightweight C++ unit testing library.
# Copyright (c) 2008 Sandia Corporation.
# This software is distributed under the LGPL License v3
# For more information, see the COPYING file in the top CxxTest directory.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------
import sys
import os
def abort( problem ):
'''Print error message and exit'''
sys.stderr.write( '\n' )
sys.stderr.write( problem )
sys.stderr.write( '\n\n' )
sys.exit(2)
if sys.version_info < (2,6): #pragma: no cover
def resolve_symlinks(orig_path):
drive,tmp = os.path.splitdrive(os.path.normpath(orig_path))
if not drive:
drive = os.path.sep
parts = tmp.split(os.path.sep)
actual_path = [drive]
while parts:
actual_path.append(parts.pop(0))
if not os.path.islink(os.path.join(*actual_path)):
continue
actual_path[-1] = os.readlink(os.path.join(*actual_path))
tmp_drive, tmp_path = os.path.splitdrive(
dereference_path(os.path.join(*actual_path)) )
if tmp_drive:
drive = tmp_drive
actual_path = [drive] + tmp_path.split(os.path.sep)
return os.path.join(*actual_path)
def relpath(path, start=None):
"""Return a relative version of a path.
(provides compatibility with Python < 2.6)"""
# Some notes on implementation:
# - We rely on resolve_symlinks to correctly resolve any symbolic
# links that may be present in the paths
# - The explicit handling od the drive name is critical for proper
# function on Windows (because os.path.join('c:','foo') yields
# "c:foo"!).
if not start:
start = os.getcwd()
ref_drive, ref_path = os.path.splitdrive(
resolve_symlinks(os.path.abspath(start)) )
if not ref_drive:
ref_drive = os.path.sep
start = [ref_drive] + ref_path.split(os.path.sep)
while '' in start:
start.remove('')
pth_drive, pth_path = os.path.splitdrive(
resolve_symlinks(os.path.abspath(path)) )
if not pth_drive:
pth_drive = os.path.sep
path = [pth_drive] + pth_path.split(os.path.sep)
while '' in path:
path.remove('')
i = 0
max = min(len(path), len(start))
while i < max and path[i] == start[i]:
i += 1
if i < 2:
return os.path.join(*path)
else:
rel = ['..']*(len(start)-i) + path[i:]
if rel:
return os.path.join(*rel)
else:
return '.'

View File

@@ -0,0 +1,254 @@
#-------------------------------------------------------------------------
# CxxTest: A lightweight C++ unit testing library.
# Copyright (c) 2008 Sandia Corporation.
# This software is distributed under the LGPL License v3
# For more information, see the COPYING file in the top CxxTest directory.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------
import codecs
import re
import sys
from cxxtest.cxxtest_misc import abort
# Global variables
suites = []
suite = None
inBlock = 0
options=None
def scanInputFiles(files, _options):
'''Scan all input files for test suites'''
#
# Reset global data
#
global options
options=_options
global suites
suites = []
global suite
suite = None
global inBlock
inBlock = 0
#
for file in files:
scanInputFile(file)
if len(suites) is 0 and not options.root:
abort( 'No tests defined' )
return [options,suites]
lineCont_re = re.compile('(.*)\\\s*$')
def scanInputFile(fileName):
'''Scan single input file for test suites'''
# mode 'rb' is problematic in python3 - byte arrays don't behave the same as
# strings.
# As far as the choice of the default encoding: utf-8 chews through
# everything that the previous ascii codec could, plus most of new code.
# TODO: figure out how to do this properly - like autodetect encoding from
# file header.
file = codecs.open(fileName, mode='r', encoding='utf-8')
prev = ""
lineNo = 0
contNo = 0
while 1:
try:
line = file.readline()
except UnicodeDecodeError:
sys.stderr.write("Could not decode unicode character at %s:%s\n" % (fileName, lineNo + 1));
raise
if not line:
break
lineNo += 1
m = lineCont_re.match(line)
if m:
prev += m.group(1) + " "
contNo += 1
else:
scanInputLine( fileName, lineNo - contNo, prev + line )
contNo = 0
prev = ""
if contNo:
scanInputLine( fileName, lineNo - contNo, prev + line )
closeSuite()
file.close()
def scanInputLine( fileName, lineNo, line ):
'''Scan single input line for interesting stuff'''
scanLineForExceptionHandling( line )
scanLineForStandardLibrary( line )
scanLineForSuiteStart( fileName, lineNo, line )
global suite
if suite:
scanLineInsideSuite( suite, lineNo, line )
def scanLineInsideSuite( suite, lineNo, line ):
'''Analyze line which is part of a suite'''
global inBlock
if lineBelongsToSuite( suite, lineNo, line ):
scanLineForTest( suite, lineNo, line )
scanLineForCreate( suite, lineNo, line )
scanLineForDestroy( suite, lineNo, line )
def lineBelongsToSuite( suite, lineNo, line ):
'''Returns whether current line is part of the current suite.
This can be false when we are in a generated suite outside of CXXTEST_CODE() blocks
If the suite is generated, adds the line to the list of lines'''
if not suite['generated']:
return 1
global inBlock
if not inBlock:
inBlock = lineStartsBlock( line )
if inBlock:
inBlock = addLineToBlock( suite, lineNo, line )
return inBlock
std_re = re.compile( r"\b(std\s*::|CXXTEST_STD|using\s+namespace\s+std\b|^\s*\#\s*include\s+<[a-z0-9]+>)" )
def scanLineForStandardLibrary( line ):
'''Check if current line uses standard library'''
global options
if not options.haveStandardLibrary and std_re.search(line):
if not options.noStandardLibrary:
options.haveStandardLibrary = 1
exception_re = re.compile( r"\b(throw|try|catch|TSM?_ASSERT_THROWS[A-Z_]*)\b" )
def scanLineForExceptionHandling( line ):
'''Check if current line uses exception handling'''
global options
if not options.haveExceptionHandling and exception_re.search(line):
if not options.noExceptionHandling:
options.haveExceptionHandling = 1
classdef = '(?:::\s*)?(?:\w+\s*::\s*)*\w+'
baseclassdef = '(?:public|private|protected)\s+%s' % (classdef,)
general_suite = r"\bclass\s+(%s)\s*:(?:\s*%s\s*,)*\s*public\s+" \
% (classdef, baseclassdef,)
testsuite = '(?:(?:::)?\s*CxxTest\s*::\s*)?TestSuite'
suites_re = { re.compile( general_suite + testsuite ) : None }
generatedSuite_re = re.compile( r'\bCXXTEST_SUITE\s*\(\s*(\w*)\s*\)' )
def scanLineForSuiteStart( fileName, lineNo, line ):
'''Check if current line starts a new test suite'''
for i in list(suites_re.items()):
m = i[0].search( line )
if m:
suite = startSuite( m.group(1), fileName, lineNo, 0 )
if i[1] is not None:
for test in i[1]['tests']:
addTest(suite, test['name'], test['line'])
break
m = generatedSuite_re.search( line )
if m:
sys.stdout.write( "%s:%s: Warning: Inline test suites are deprecated.\n" % (fileName, lineNo) )
startSuite( m.group(1), fileName, lineNo, 1 )
def startSuite( name, file, line, generated ):
'''Start scanning a new suite'''
global suite
closeSuite()
object_name = name.replace(':',"_")
suite = { 'fullname' : name,
'name' : name,
'file' : file,
'cfile' : cstr(file),
'line' : line,
'generated' : generated,
'object' : 'suite_%s' % object_name,
'dobject' : 'suiteDescription_%s' % object_name,
'tlist' : 'Tests_%s' % object_name,
'tests' : [],
'lines' : [] }
suites_re[re.compile( general_suite + name )] = suite
return suite
def lineStartsBlock( line ):
'''Check if current line starts a new CXXTEST_CODE() block'''
return re.search( r'\bCXXTEST_CODE\s*\(', line ) is not None
test_re = re.compile( r'^([^/]|/[^/])*\bvoid\s+([Tt]est\w+)\s*\(\s*(void)?\s*\)' )
def scanLineForTest( suite, lineNo, line ):
'''Check if current line starts a test'''
m = test_re.search( line )
if m:
addTest( suite, m.group(2), lineNo )
def addTest( suite, name, line ):
'''Add a test function to the current suite'''
test = { 'name' : name,
'suite' : suite,
'class' : 'TestDescription_%s_%s' % (suite['object'], name),
'object' : 'testDescription_%s_%s' % (suite['object'], name),
'line' : line,
}
suite['tests'].append( test )
def addLineToBlock( suite, lineNo, line ):
'''Append the line to the current CXXTEST_CODE() block'''
line = fixBlockLine( suite, lineNo, line )
line = re.sub( r'^.*\{\{', '', line )
e = re.search( r'\}\}', line )
if e:
line = line[:e.start()]
suite['lines'].append( line )
return e is None
def fixBlockLine( suite, lineNo, line):
'''Change all [E]TS_ macros used in a line to _[E]TS_ macros with the correct file/line'''
return re.sub( r'\b(E?TSM?_(ASSERT[A-Z_]*|FAIL))\s*\(',
r'_\1(%s,%s,' % (suite['cfile'], lineNo),
line, 0 )
create_re = re.compile( r'\bstatic\s+\w+\s*\*\s*createSuite\s*\(\s*(void)?\s*\)' )
def scanLineForCreate( suite, lineNo, line ):
'''Check if current line defines a createSuite() function'''
if create_re.search( line ):
addSuiteCreateDestroy( suite, 'create', lineNo )
destroy_re = re.compile( r'\bstatic\s+void\s+destroySuite\s*\(\s*\w+\s*\*\s*\w*\s*\)' )
def scanLineForDestroy( suite, lineNo, line ):
'''Check if current line defines a destroySuite() function'''
if destroy_re.search( line ):
addSuiteCreateDestroy( suite, 'destroy', lineNo )
def cstr( s ):
'''Convert a string to its C representation'''
return '"' + s.replace( '\\', '\\\\' ) + '"'
def addSuiteCreateDestroy( suite, which, line ):
'''Add createSuite()/destroySuite() to current suite'''
if which in suite:
abort( '%s:%s: %sSuite() already declared' % ( suite['file'], str(line), which ) )
suite[which] = line
def closeSuite():
'''Close current suite and add it to the list if valid'''
global suite
if suite is not None:
if len(suite['tests']) is not 0:
verifySuite(suite)
rememberSuite(suite)
suite = None
def verifySuite(suite):
'''Verify current suite is legal'''
if 'create' in suite and 'destroy' not in suite:
abort( '%s:%s: Suite %s has createSuite() but no destroySuite()' %
(suite['file'], suite['create'], suite['name']) )
elif 'destroy' in suite and 'create' not in suite:
abort( '%s:%s: Suite %s has destroySuite() but no createSuite()' %
(suite['file'], suite['destroy'], suite['name']) )
def rememberSuite(suite):
'''Add current suite to list'''
global suites
suites.append( suite )

View File

@@ -0,0 +1,630 @@
#-------------------------------------------------------------------------
# CxxTest: A lightweight C++ unit testing library.
# Copyright (c) 2008 Sandia Corporation.
# This software is distributed under the LGPL License v3
# For more information, see the COPYING file in the top CxxTest directory.
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#-------------------------------------------------------------------------
# vim: fileencoding=utf-8
# the above import important for forward-compatibility with python3,
# which is already the default in archlinux!
__all__ = ['main', 'create_manpage']
from . import __release__
import os
import sys
import re
import glob
from optparse import OptionParser
from . import cxxtest_parser
from string import Template
try:
from . import cxxtest_fog
imported_fog=True
except ImportError:
imported_fog=False
from .cxxtest_misc import abort
try:
from os.path import relpath
except ImportError:
from .cxxtest_misc import relpath
# Global data is initialized by main()
options = []
suites = []
wrotePreamble = 0
wroteWorld = 0
lastIncluded = ''
def main(args=sys.argv, catch=False):
'''The main program'''
#
# Reset global state
#
global wrotePreamble
wrotePreamble=0
global wroteWorld
wroteWorld=0
global lastIncluded
lastIncluded = ''
global suites
suites = []
global options
options = []
#
try:
files = parseCommandline(args)
if imported_fog and options.fog:
[options,suites] = cxxtest_fog.scanInputFiles( files, options )
else:
[options,suites] = cxxtest_parser.scanInputFiles( files, options )
writeOutput()
except SystemExit:
if not catch:
raise
def create_parser(asciidoc=False):
parser = OptionParser("cxxtestgen [options] [<filename> ...]")
if asciidoc:
parser.description="The cxxtestgen command processes C++ header files to perform test discovery, and then it creates files for the CxxTest test runner."
else:
parser.description="The 'cxxtestgen' command processes C++ header files to perform test discovery, and then it creates files for the 'CxxTest' test runner."
parser.add_option("--version",
action="store_true", dest="version", default=False,
help="Write the CxxTest version.")
parser.add_option("-o", "--output",
dest="outputFileName", default=None, metavar="NAME",
help="Write output to file NAME.")
parser.add_option("-w","--world", dest="world", default="cxxtest",
help="The label of the tests, used to name the XML results.")
parser.add_option("", "--include", action="append",
dest="headers", default=[], metavar="HEADER",
help="Include file HEADER in the test runner before other headers.")
parser.add_option("", "--abort-on-fail",
action="store_true", dest="abortOnFail", default=False,
help="Abort tests on failed asserts (like xUnit).")
parser.add_option("", "--main",
action="store", dest="main", default="main",
help="Specify an alternative name for the main() function.")
parser.add_option("", "--headers",
action="store", dest="header_filename", default=None,
help="Specify a filename that contains a list of header files that are processed to generate a test runner.")
parser.add_option("", "--runner",
dest="runner", default="", metavar="CLASS",
help="Create a test runner that processes test events using the class CxxTest::CLASS.")
parser.add_option("", "--gui",
dest="gui", metavar="CLASS",
help="Create a GUI test runner that processes test events using the class CxxTest::CLASS. (deprecated)")
parser.add_option("", "--error-printer",
action="store_true", dest="error_printer", default=False,
help="Create a test runner using the ErrorPrinter class, and allow the use of the standard library.")
parser.add_option("", "--xunit-printer",
action="store_true", dest="xunit_printer", default=False,
help="Create a test runner using the XUnitPrinter class.")
parser.add_option("", "--xunit-file", dest="xunit_file", default="",
help="The file to which the XML summary is written for test runners using the XUnitPrinter class. The default XML filename is TEST-<world>.xml, where <world> is the value of the --world option. (default: cxxtest)")
parser.add_option("", "--have-std",
action="store_true", dest="haveStandardLibrary", default=False,
help="Use the standard library (even if not found in tests).")
parser.add_option("", "--no-std",
action="store_true", dest="noStandardLibrary", default=False,
help="Do not use standard library (even if found in tests).")
parser.add_option("", "--have-eh",
action="store_true", dest="haveExceptionHandling", default=False,
help="Use exception handling (even if not found in tests).")
parser.add_option("", "--no-eh",
action="store_true", dest="noExceptionHandling", default=False,
help="Do not use exception handling (even if found in tests).")
parser.add_option("", "--longlong",
dest="longlong", default=None, metavar="TYPE",
help="Use TYPE as for long long integers. (default: not supported)")
parser.add_option("", "--no-static-init",
action="store_true", dest="noStaticInit", default=False,
help="Do not rely on static initialization in the test runner.")
parser.add_option("", "--template",
dest="templateFileName", default=None, metavar="TEMPLATE",
help="Generate the test runner using file TEMPLATE to define a template.")
parser.add_option("", "--root",
action="store_true", dest="root", default=False,
help="Write the main() function and global data for a test runner.")
parser.add_option("", "--part",
action="store_true", dest="part", default=False,
help="Write the tester classes for a test runner.")
#parser.add_option("", "--factor",
#action="store_true", dest="factor", default=False,
#help="Declare the _CXXTEST_FACTOR macro. (deprecated)")
if imported_fog:
fog_help = "Use new FOG C++ parser"
else:
fog_help = "Use new FOG C++ parser (disabled)"
parser.add_option("-f", "--fog-parser",
action="store_true",
dest="fog",
default=False,
help=fog_help
)
return parser
def parseCommandline(args):
'''Analyze command line arguments'''
global imported_fog
global options
parser = create_parser()
(options, args) = parser.parse_args(args=args)
if not options.header_filename is None:
if not os.path.exists(options.header_filename):
abort( "ERROR: the file '%s' does not exist!" % options.header_filename )
INPUT = open(options.header_filename)
headers = [line.strip() for line in INPUT]
args.extend( headers )
INPUT.close()
if options.fog and not imported_fog:
abort( "Cannot use the FOG parser. Check that the 'ply' package is installed. The 'ordereddict' package is also required if running Python 2.6")
if options.version:
printVersion()
# the cxxtest builder relies on this behaviour! don't remove
if options.runner == 'none':
options.runner = None
if options.xunit_printer or options.runner == "XUnitPrinter":
options.xunit_printer=True
options.runner="XUnitPrinter"
if len(args) > 1:
if options.xunit_file == "":
if options.world == "":
options.world = "cxxtest"
options.xunit_file="TEST-"+options.world+".xml"
elif options.xunit_file == "":
if options.world == "":
options.world = "cxxtest"
options.xunit_file="TEST-"+options.world+".xml"
if options.error_printer:
options.runner= "ErrorPrinter"
options.haveStandardLibrary = True
if options.noStaticInit and (options.root or options.part):
abort( '--no-static-init cannot be used with --root/--part' )
if options.gui and not options.runner:
options.runner = 'StdioPrinter'
files = setFiles(args[1:])
if len(files) == 0 and not options.root:
sys.stderr.write(parser.error("No input files found"))
return files
def printVersion():
'''Print CxxTest version and exit'''
sys.stdout.write( "This is CxxTest version %s.\n" % __release__.__version__ )
sys.exit(0)
def setFiles(patterns ):
'''Set input files specified on command line'''
files = expandWildcards( patterns )
return files
def expandWildcards( patterns ):
'''Expand all wildcards in an array (glob)'''
fileNames = []
for pathName in patterns:
patternFiles = glob.glob( pathName )
for fileName in patternFiles:
fileNames.append( fixBackslashes( fileName ) )
return fileNames
def fixBackslashes( fileName ):
'''Convert backslashes to slashes in file name'''
return re.sub( r'\\', '/', fileName, 0 )
def writeOutput():
'''Create output file'''
if options.templateFileName:
writeTemplateOutput()
else:
writeSimpleOutput()
def writeSimpleOutput():
'''Create output not based on template'''
output = startOutputFile()
writePreamble( output )
if options.root or not options.part:
writeMain( output )
if len(suites) > 0:
output.write("bool "+suites[0]['object']+"_init = false;\n")
writeWorld( output )
output.close()
include_re = re.compile( r"\s*\#\s*include\s+<cxxtest/" )
preamble_re = re.compile( r"^\s*<CxxTest\s+preamble>\s*$" )
world_re = re.compile( r"^\s*<CxxTest\s+world>\s*$" )
def writeTemplateOutput():
'''Create output based on template file'''
template = open(options.templateFileName)
output = startOutputFile()
while 1:
line = template.readline()
if not line:
break;
if include_re.search( line ):
writePreamble( output )
output.write( line )
elif preamble_re.search( line ):
writePreamble( output )
elif world_re.search( line ):
if len(suites) > 0:
output.write("bool "+suites[0]['object']+"_init = false;\n")
writeWorld( output )
else:
output.write( line )
template.close()
output.close()
def startOutputFile():
'''Create output file and write header'''
if options.outputFileName is not None:
output = open( options.outputFileName, 'w' )
else:
output = sys.stdout
output.write( "/* Generated file, do not edit */\n\n" )
return output
def writePreamble( output ):
'''Write the CxxTest header (#includes and #defines)'''
global wrotePreamble
if wrotePreamble: return
output.write( "#ifndef CXXTEST_RUNNING\n" )
output.write( "#define CXXTEST_RUNNING\n" )
output.write( "#endif\n" )
output.write( "\n" )
if options.xunit_printer:
output.write( "#include <fstream>\n" )
if options.haveStandardLibrary:
output.write( "#define _CXXTEST_HAVE_STD\n" )
if options.haveExceptionHandling:
output.write( "#define _CXXTEST_HAVE_EH\n" )
if options.abortOnFail:
output.write( "#define _CXXTEST_ABORT_TEST_ON_FAIL\n" )
if options.longlong:
output.write( "#define _CXXTEST_LONGLONG %s\n" % options.longlong )
#if options.factor:
#output.write( "#define _CXXTEST_FACTOR\n" )
for header in options.headers:
output.write( "#include \"%s\"\n" % header )
output.write( "#include <cxxtest/TestListener.h>\n" )
output.write( "#include <cxxtest/TestTracker.h>\n" )
output.write( "#include <cxxtest/TestRunner.h>\n" )
output.write( "#include <cxxtest/RealDescriptions.h>\n" )
output.write( "#include <cxxtest/TestMain.h>\n" )
if options.runner:
output.write( "#include <cxxtest/%s.h>\n" % options.runner )
if options.gui:
output.write( "#include <cxxtest/%s.h>\n" % options.gui )
output.write( "\n" )
wrotePreamble = 1
def writeMain( output ):
'''Write the main() function for the test runner'''
if not (options.gui or options.runner):
return
output.write( 'int %s( int argc, char *argv[] ) {\n' % options.main )
output.write( ' int status;\n' )
if options.noStaticInit:
output.write( ' CxxTest::initialize();\n' )
if options.gui:
tester_t = "CxxTest::GuiTuiRunner<CxxTest::%s, CxxTest::%s> " % (options.gui, options.runner)
else:
tester_t = "CxxTest::%s" % (options.runner)
if options.xunit_printer:
output.write( ' std::ofstream ofstr("%s");\n' % options.xunit_file )
output.write( ' %s tmp(ofstr);\n' % tester_t )
else:
output.write( ' %s tmp;\n' % tester_t )
output.write( ' CxxTest::RealWorldDescription::_worldName = "%s";\n' % options.world )
output.write( ' status = CxxTest::Main< %s >( tmp, argc, argv );\n' % tester_t )
output.write( ' return status;\n')
output.write( '}\n' )
def writeWorld( output ):
'''Write the world definitions'''
global wroteWorld
if wroteWorld: return
writePreamble( output )
writeSuites( output )
if options.root or not options.part:
writeRoot( output )
writeWorldDescr( output )
if options.noStaticInit:
writeInitialize( output )
wroteWorld = 1
def writeSuites(output):
'''Write all TestDescriptions and SuiteDescriptions'''
for suite in suites:
writeInclude( output, suite['file'] )
if isGenerated(suite):
generateSuite( output, suite )
if not options.noStaticInit:
if isDynamic(suite):
writeSuitePointer( output, suite )
else:
writeSuiteObject( output, suite )
writeTestList( output, suite )
writeSuiteDescription( output, suite )
writeTestDescriptions( output, suite )
def isGenerated(suite):
'''Checks whether a suite class should be created'''
return suite['generated']
def isDynamic(suite):
'''Checks whether a suite is dynamic'''
return 'create' in suite
def writeInclude(output, file):
'''Add #include "file" statement'''
global lastIncluded
if options.outputFileName:
dirname = os.path.split(options.outputFileName)[0]
tfile = relpath(file, dirname)
if os.path.exists(tfile):
if tfile == lastIncluded: return
output.writelines( [ '#include "', tfile, '"\n\n' ] )
lastIncluded = tfile
return
#
# Use an absolute path if the relative path failed
#
tfile = os.path.abspath(file)
if os.path.exists(tfile):
if tfile == lastIncluded: return
output.writelines( [ '#include "', tfile, '"\n\n' ] )
lastIncluded = tfile
return
def generateSuite( output, suite ):
'''Write a suite declared with CXXTEST_SUITE()'''
output.write( 'class %s : public CxxTest::TestSuite {\n' % suite['fullname'] )
output.write( 'public:\n' )
for line in suite['lines']:
output.write(line)
output.write( '};\n\n' )
def writeSuitePointer( output, suite ):
'''Create static suite pointer object for dynamic suites'''
if options.noStaticInit:
output.write( 'static %s* %s;\n\n' % (suite['fullname'], suite['object']) )
else:
output.write( 'static %s* %s = 0;\n\n' % (suite['fullname'], suite['object']) )
def writeSuiteObject( output, suite ):
'''Create static suite object for non-dynamic suites'''
output.writelines( [ "static ", suite['fullname'], " ", suite['object'], ";\n\n" ] )
def writeTestList( output, suite ):
'''Write the head of the test linked list for a suite'''
if options.noStaticInit:
output.write( 'static CxxTest::List %s;\n' % suite['tlist'] )
else:
output.write( 'static CxxTest::List %s = { 0, 0 };\n' % suite['tlist'] )
def writeWorldDescr( output ):
'''Write the static name of the world name'''
if options.noStaticInit:
output.write( 'const char* CxxTest::RealWorldDescription::_worldName;\n' )
else:
output.write( 'const char* CxxTest::RealWorldDescription::_worldName = "cxxtest";\n' )
def writeTestDescriptions( output, suite ):
'''Write all test descriptions for a suite'''
for test in suite['tests']:
writeTestDescription( output, suite, test )
def writeTestDescription( output, suite, test ):
'''Write test description object'''
if not options.noStaticInit:
output.write( 'static class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
else:
output.write( 'class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
#
output.write( 'public:\n' )
if not options.noStaticInit:
output.write( ' %s() : CxxTest::RealTestDescription( %s, %s, %s, "%s" ) {}\n' %
(test['class'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
else:
if isDynamic(suite):
output.write( ' %s(%s* _%s) : %s(_%s) { }\n' %
(test['class'], suite['fullname'], suite['object'], suite['object'], suite['object']) )
output.write( ' %s* %s;\n' % (suite['fullname'], suite['object']) )
else:
output.write( ' %s(%s& _%s) : %s(_%s) { }\n' %
(test['class'], suite['fullname'], suite['object'], suite['object'], suite['object']) )
output.write( ' %s& %s;\n' % (suite['fullname'], suite['object']) )
output.write( ' void runTest() { %s }\n' % runBody( suite, test ) )
#
if not options.noStaticInit:
output.write( '} %s;\n\n' % test['object'] )
else:
output.write( '};\n\n' )
def runBody( suite, test ):
'''Body of TestDescription::run()'''
if isDynamic(suite): return dynamicRun( suite, test )
else: return staticRun( suite, test )
def dynamicRun( suite, test ):
'''Body of TestDescription::run() for test in a dynamic suite'''
return 'if ( ' + suite['object'] + ' ) ' + suite['object'] + '->' + test['name'] + '();'
def staticRun( suite, test ):
'''Body of TestDescription::run() for test in a non-dynamic suite'''
return suite['object'] + '.' + test['name'] + '();'
def writeSuiteDescription( output, suite ):
'''Write SuiteDescription object'''
if isDynamic( suite ):
writeDynamicDescription( output, suite )
else:
writeStaticDescription( output, suite )
def writeDynamicDescription( output, suite ):
'''Write SuiteDescription for a dynamic suite'''
output.write( 'CxxTest::DynamicSuiteDescription< %s > %s' % (suite['fullname'], suite['dobject']) )
if not options.noStaticInit:
output.write( '( %s, %s, "%s", %s, %s, %s, %s )' %
(suite['cfile'], suite['line'], suite['fullname'], suite['tlist'],
suite['object'], suite['create'], suite['destroy']) )
output.write( ';\n\n' )
def writeStaticDescription( output, suite ):
'''Write SuiteDescription for a static suite'''
output.write( 'CxxTest::StaticSuiteDescription %s' % suite['dobject'] )
if not options.noStaticInit:
output.write( '( %s, %s, "%s", %s, %s )' %
(suite['cfile'], suite['line'], suite['fullname'], suite['object'], suite['tlist']) )
output.write( ';\n\n' )
def writeRoot(output):
'''Write static members of CxxTest classes'''
output.write( '#include <cxxtest/Root.cpp>\n' )
def writeInitialize(output):
'''Write CxxTest::initialize(), which replaces static initialization'''
output.write( 'namespace CxxTest {\n' )
output.write( ' void initialize()\n' )
output.write( ' {\n' )
for suite in suites:
#print "HERE", suite
writeTestList( output, suite )
output.write( ' %s.initialize();\n' % suite['tlist'] )
#writeSuiteObject( output, suite )
if isDynamic(suite):
writeSuitePointer( output, suite )
output.write( ' %s = 0;\n' % suite['object'])
else:
writeSuiteObject( output, suite )
output.write( ' static ')
writeSuiteDescription( output, suite )
if isDynamic(suite):
#output.write( ' %s = %s.suite();\n' % (suite['object'],suite['dobject']) )
output.write( ' %s.initialize( %s, %s, "%s", %s, %s, %s, %s );\n' %
(suite['dobject'], suite['cfile'], suite['line'], suite['fullname'],
suite['tlist'], suite['object'], suite['create'], suite['destroy']) )
output.write( ' %s.setUp();\n' % suite['dobject'])
else:
output.write( ' %s.initialize( %s, %s, "%s", %s, %s );\n' %
(suite['dobject'], suite['cfile'], suite['line'], suite['fullname'],
suite['object'], suite['tlist']) )
for test in suite['tests']:
output.write( ' static %s %s(%s);\n' %
(test['class'], test['object'], suite['object']) )
output.write( ' %s.initialize( %s, %s, %s, "%s" );\n' %
(test['object'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
output.write( ' }\n' )
output.write( '}\n' )
man_template=Template("""CXXTESTGEN(1)
=============
:doctype: manpage
NAME
----
cxxtestgen - performs test discovery to create a CxxTest test runner
SYNOPSIS
--------
${usage}
DESCRIPTION
-----------
${description}
OPTIONS
-------
${options}
EXIT STATUS
-----------
*0*::
Success
*1*::
Failure (syntax or usage error; configuration error; document
processing failure; unexpected error).
BUGS
----
See the CxxTest Home Page for the link to the CxxTest ticket repository.
AUTHOR
------
CxxTest was originally written by Erez Volk. Many people have
contributed to it.
RESOURCES
---------
Home page: <http://cxxtest.com/>
CxxTest User Guide: <http://cxxtest.com/cxxtest/doc/guide.html>
COPYING
-------
Copyright (c) 2008 Sandia Corporation. This software is distributed
under the Lesser GNU General Public License (LGPL) v3
""")
def create_manpage():
"""Write ASCIIDOC manpage file"""
parser = create_parser(asciidoc=True)
#
usage = parser.usage
description = parser.description
options=""
for opt in parser.option_list:
opts = opt._short_opts + opt._long_opts
optstr = '*' + ', '.join(opts) + '*'
if not opt.metavar is None:
optstr += "='%s'" % opt.metavar
optstr += '::\n'
options += optstr
#
options += opt.help
options += '\n\n'
#
OUTPUT = open('cxxtestgen.1.txt','w')
OUTPUT.write( man_template.substitute(usage=usage, description=description, options=options) )
OUTPUT.close()

View File

@@ -0,0 +1,5 @@
#! python
import cxxtest.cxxtestgen
cxxtest.cxxtestgen.main()