Compare commits

...

49 commits

Author SHA1 Message Date
Ray Speth
7f5ea6edb3 Fix version displayed by Doxygen docs 2014-02-24 03:51:42 +00:00
Ray Speth
26c6aa856f [Doc] Point to SourceForge for downloads 2014-02-24 03:27:49 +00:00
Ray Speth
c03b67751d Bump version to 2.1.1 2014-02-24 03:27:45 +00:00
Ray Speth
98746058f5 Mention downloads on Sourceforge in README 2014-02-24 03:27:41 +00:00
Ray Speth
5f62e95034 [SCons] Always link to static standard libraries with MinGW 2014-02-24 03:27:36 +00:00
Ray Speth
a3d0176087 [SCons] Ensure that 'compilerOpt' is always defined 2014-02-24 03:27:32 +00:00
Ray Speth
714fe7f35f [SCons] Workaround for SCons bug under Cygwin
See SCons Issue 2911.
http://scons.tigris.org/issues/show_bug.cgi?id=2911

Cherry-pick of trunk r2739.
2014-02-24 03:27:28 +00:00
Ray Speth
214e3c8af7 [SCons] Fix library linking issues under Cygwin
Partial cherry-pick of trunk r2738.
2014-02-24 03:27:25 +00:00
Ray Speth
5441577624 Fix compilation errors with isnan/isinf using Cygwin's GCC
Cherry-pick of trunk r2737.
2014-02-24 03:27:21 +00:00
Ray Speth
f3b877d0a1 [SCons] Correctly identify Cygwin builds
The correct preprocessor macro to use is the one provided by the
compiler, '__CYGWIN__'.

Cherry-pick of trunk r2736.
2014-02-24 03:27:17 +00:00
Ray Speth
2861a8a633 [SCons] Simplify treatment of sydep1.h and signal1.h
We don't actually have system-dependent versions of these headers, so just put
the templates in place directly. This is also a workaround for a SCons bug on
Cygwin.

Cherry-pick of trunk r2735.
2014-02-24 03:27:10 +00:00
Ray Speth
73e20dc1eb [SCons] Fix a missing SCons dependency
Cherry-pick of trunk r2734.
2014-02-24 03:27:06 +00:00
Ray Speth
3b2c7d3ae2 [SCons] Fix simultaneous compilation of Python 2 and Python 3 modules
Use separate SCons Environments so the 'py_include_dirs' variable (which
contains the Numpy include directory) can be distinct for each Python module.

Cherry-pick of trunk r2710.
2014-02-14 17:02:25 +00:00
Ray Speth
261240e8f1 [MixMaster] Fixes to use Cython function names
DataFrame.importCSV and dataFrame.importData were still using function names
from the old Python module.

Cherry-pick of trunk r2729.
2014-02-14 17:02:21 +00:00
Ray Speth
659bceb9cf [MixMaster] Fix usage of numpy.zeros and numpy.ones
Cherry pick of trunk r2728.
2014-02-14 17:02:16 +00:00
Ray Speth
c7efc2d059 [Matlab] Fix detection of errors when importing Kinetics
Cast the unsigned return type of newKineticsFromXML to a signed type so that the
check on the Matlab side (which looks at the sign of the return value) can
detect and report errors.

Cherry-pick of trunk r2724.
2014-02-13 22:39:38 +00:00
Ray Speth
849dc5c82f [Cython] Add saveState/restoreState info to the migration guide
Cherry pick of trunk r2722.
2014-02-13 22:39:34 +00:00
Ray Speth
cc27095599 [ck2cti] Fix support for species names containing '+' and '='
This addesses a parsing error that would occur if a mechanism contained both
'foo' and 'foo+', where reactions written as 'foo+bar' would be parsed as a
reaction with 'foo+' and 'bar'.

See Issue 182.

Cherry pick of trunk commit r2701.
2014-02-03 17:04:48 +00:00
Ray Speth
ee736fb306 Fix potential segmentation fault and invalid read.
Cherry-pick of trunk r2676.
2014-01-23 03:06:29 +00:00
Ray Speth
0590c6c1a3 [ck2cti] Fix for support of unterminated thermo sections
Fixes the case where the next section header contains a modifier, e.g. 'thermo
all' or 'reactions <units>'.

Based on a patch provided by Bryan Weber.

See Issue 199.

Cherry-pick of trunk r2662.
2014-01-23 03:06:23 +00:00
Ray Speth
a23eac62d8 [ck2cti] Improve handling of duplicate species
Warn when a species is given multiple times in the input list. Do not add the
duplicate species to speciesList.

Based on patch provided by Bryan Weber.

Resolves Issue 199.

Cherry-pick of trunk r2660.
2014-01-23 03:06:16 +00:00
Ray Speth
f988382b36 [Matlab] Check for sparse arrays in the Solution 'set' function
Patch provided by Bryan Weber.

Resolves Issue 140.

Cherry-pick of trunk r2659.
2014-01-23 03:06:11 +00:00
Ray Speth
d3dfc3f608 [SCons] Fix Matlab-related paths in post-install message
Cherry-pick of trunk r2641.
2014-01-23 03:06:05 +00:00
Ray Speth
227a792326 [Kinetics] Fix reaction path output when arrow_width > 0
Fixes Issue 197.

Cherry-pick of trunk r2640.
2014-01-23 03:06:01 +00:00
Ray Speth
f8754904dd [Reactor] Make default wall area 1.0 m^2
This makes the default consistent with the documentation in the Python
module. Reported by & patch from Bryan Weber.

Fixes Issue 194.

Cherry-pick of trunk r2614.
2014-01-23 03:05:57 +00:00
Ray Speth
5fbbd30747 [Doc] Cherry-pick of corrections to the documentation
Cherry pick of trunk revisions: r2607, r2608, r2620, r2621, r2622, r2623, r2624,
r2625, r2628, r2630, r2632, r2633, r2635, r2636.
2014-01-23 02:45:23 +00:00
Ray Speth
d190633c47 Fix missing include in csvdiff
"std::exit" is declared in <cstdlib>. Fixes compilation errors on OS X 10.9.

Cherry-pick of trunk r2666.
2014-01-23 02:13:56 +00:00
Ray Speth
c865843d8a [Cython] Fix compilation issue when using Clang
Cherry-pick of trunk r2663.
2014-01-23 02:13:51 +00:00
Ray Speth
2628cb760c [SCons] Add Boost libraries when building the shared library
Cherry-pick of trunk r2670.
2014-01-23 02:13:46 +00:00
Ray Speth
2d7d82d633 [SCons] Install Python 3 module to stage directory
Cherry-pick of trunk r2671.
2014-01-23 02:13:40 +00:00
Ray Speth
5109d0d5a4 [Test] Update gtest to 1.7.0
Cherry-pick of trunk r2680.
2014-01-23 02:12:44 +00:00
Ray Speth
9f156c04fc [Thermo] Make modification of discontinuous NASA polynomials optional
Adding the attribute allow_discontinuities="true" to a phase's
'thermo' node (CTML) or adding 'allow_discontinuous_thermo' to a
phase's 'options' argument (CTI) will disable the automatic adjustment
of the provided polynomials so that enthalpy and entropy are
continuous at the midpoint temperature.

Cherry-pick of trunk r2590.
2014-01-23 02:12:36 +00:00
Ray Speth
5386d6b304 [ctml] Fix constructor for stoichiometric_solid phase
Error introduced in r2579
2013-12-06 23:45:22 +00:00
Ray Speth
81cf00260d [ck2cti] Add support for species names containing '+' and '=' 2013-12-06 23:15:24 +00:00
Ray Speth
44181d5edf [ck2cti/Test] Eliminate confusing messages from expected errors
Suppress error messages from tests of ck2cti that use bad input to
test that input validation is working correctly.
2013-12-06 23:15:21 +00:00
Ray Speth
c9b4d3dbe8 [ck2cti] Add support for truncated section header names
Accept truncated section names such as 'REAC' for 'REACTIONS' and
'ELEM' for 'ELEMENTS'.
2013-12-06 23:15:18 +00:00
Ray Speth
ff842a1a08 [Cython] Direct log output to sys.stdout
This fixes the problem of some output (notably from the 1D solver)
going to std::cout when that is not the primary output location,
e.g. when using IDLE or the IPython QtConsole.
2013-12-06 23:15:14 +00:00
Ray Speth
3f92b77f5a [Thermo] Fix printed labels in phase report when show_thermo=False 2013-12-06 23:15:11 +00:00
Ray Speth
58a4183e55 [Matlab] Remove broken ck2ctml function
There are three problems with this function. It does not work, since
it calls ctmethods with the wrong number of arguments. Even if that
were fixed, it wouldn't do what it claims, as the method it calls
generates a CTI file, not an XML file. Finally, it is redundant, as
the 'ck2cti' function can be used for generating the CTI file, and the
CTI to XML conversion is handled automatically when importing the
phase.

Therefore, this function is being removed.
2013-12-06 23:15:08 +00:00
Ray Speth
7ce65f45d8 [Python/Test] Run tests that were being accidentally ignored 2013-12-05 20:54:11 +00:00
Ray Speth
a8111887bf [CTI] Add optional 'note' field to Phase definitions
The note field is preserved when converting to XML, and can be used to
store extra information used by applications other than Cantera.
2013-12-05 20:54:08 +00:00
Ray Speth
c7d69ac863 [Cython] Expose global 'appdelete' method
Occasionally useful for debugging memory leaks
2013-12-05 20:54:06 +00:00
Ray Speth
b914d59fbd [Docs] Fix typos in a few equations 2013-12-05 20:54:03 +00:00
Ray Speth
bec6e97eb4 [Matlab/Samples] Fix tolerances on flame example 2013-12-05 20:54:01 +00:00
Ray Speth
cd572403df Fix issues with pure fluids near temperature limits
Fixes Issue 186.
2013-11-12 23:44:51 +00:00
Ray Speth
a7bd7c6a7a [Cython] Add 'atomic_weight' method and 'atomic_weights' property
Resolves Issue 185.
2013-11-12 23:44:46 +00:00
Ray Speth
cf429ac374 Fix CXX flags for VS2012
Resolves Issue 184.
2013-11-12 23:44:42 +00:00
Ray Speth
d76ae30e86 [Cython/Doc] Migration guide covers transport model and Soret effect 2013-11-03 21:06:54 +00:00
Ray Speth
3a0c370550 [Matlab] Fix 'thermalConductivity' method 2013-11-03 20:46:38 +00:00
96 changed files with 3231 additions and 1906 deletions

28
README
View file

@ -3,7 +3,7 @@
CANTERA CANTERA
******* *******
Version 2.1.0 (stable) Version 2.1.1 (stable)
License Information License Information
=================== ===================
@ -18,23 +18,25 @@ Web Resources
1. The Cantera Google Code site: 1. The Cantera Google Code site:
http://cantera.googlecode.com/ http://cantera.googlecode.com/
This site contains the Cantera source code, downloads of binary releases, This site contains the Cantera source code, and the issue tracker for bugs
and the issue tracker for bugs and enhancement requests. and enhancement requests.
2. Cantera Documentation: 2. The Cantera SourceForge site:
http://sourceforge.net/projects/cantera
Distribution of Cantera releases and binary installers. It also contains the
project CVS history.
3. Cantera Documentation:
http://cantera.github.com/docs/sphinx/html/index.html http://cantera.github.com/docs/sphinx/html/index.html
This site contains documentation for the current development version of This site contains documentation for the current stable version of Cantera.
Cantera.
3. The Cantera User's Group: http://cantera.github.com/dev-docs/sphinx/html/index.html
This site contains documentation for the development version of Cantera.
4. The Cantera User's Group:
http://groups.google.com/group/cantera-users http://groups.google.com/group/cantera-users
This site has a message board for discussions amongst Cantera users. This site has a message board for discussions amongst Cantera users.
4. The Cantera Developers Group: 5. The Cantera Developers Group:
http://groups.google.com/group/cantera-dev http://groups.google.com/group/cantera-dev
Limited access site where developers can discuss development ideas. Limited access site where developers can discuss development ideas.
5. Old Cantera source code site.
http://sourceforge.net/projects/cantera
Distribution of the Cantera source code previously done using SourceForge.
It still contains the project CVS history.

View file

@ -52,8 +52,6 @@ if 'clean' in COMMAND_LINE_TARGETS:
removeFile('include/cantera/base/config.h') removeFile('include/cantera/base/config.h')
removeFile('interfaces/python/setup.py') removeFile('interfaces/python/setup.py')
removeFile('ext/f2c_libs/arith.h') removeFile('ext/f2c_libs/arith.h')
removeFile('ext/f2c_libs/signal1.h')
removeFile('ext/f2c_libs/sysdep1.h')
for name in os.listdir('.'): for name in os.listdir('.'):
if name.endswith('.msi'): if name.endswith('.msi'):
removeFile(name) removeFile(name)
@ -145,6 +143,8 @@ env = Environment(tools=toolchain+['textfile', 'subst', 'recursiveInstall', 'wix
env['OS'] = platform.system() env['OS'] = platform.system()
env['OS_BITS'] = int(platform.architecture()[0][:2]) env['OS_BITS'] = int(platform.architecture()[0][:2])
if 'cygwin' in env['OS'].lower():
env['OS'] = 'Cygwin' # remove Windows version suffix
# Fixes a linker error in Windows # Fixes a linker error in Windows
if os.name == 'nt' and 'TMP' in os.environ: if os.name == 'nt' and 'TMP' in os.environ:
@ -218,7 +218,7 @@ elif env['CC'] == 'cl': # Visual Studio
'/D_SCL_SECURE_NO_WARNINGS', '/D_CRT_SECURE_NO_WARNINGS'] '/D_SCL_SECURE_NO_WARNINGS', '/D_CRT_SECURE_NO_WARNINGS']
if env['MSVC_VERSION'] == '11.0': if env['MSVC_VERSION'] == '11.0':
# Fix compatibility issue between VS2012 and Google Test # Fix compatibility issue between VS2012 and Google Test
defaults.cxxFlags.append('D_VARIADIC_MAX=10') defaults.cxxFlags.append('/D_VARIADIC_MAX=10')
defaults.debugCcFlags = '/Zi /Fd${TARGET}.pdb' defaults.debugCcFlags = '/Zi /Fd${TARGET}.pdb'
defaults.noOptimizeCcFlags = '/Od /Ob0' defaults.noOptimizeCcFlags = '/Od /Ob0'
defaults.optimizeCcFlags = '/O2 /DNDEBUG' defaults.optimizeCcFlags = '/O2 /DNDEBUG'
@ -622,7 +622,7 @@ config_options = [
name recognized by the 'dot' program. On linux systems, this name recognized by the 'dot' program. On linux systems, this
should be lowercase 'helvetica'.""", should be lowercase 'helvetica'.""",
'Helvetica'), 'Helvetica'),
('cantera_version', '', '2.1.0') ('cantera_version', '', '2.1.1')
] ]
opts.AddVariables(*config_options) opts.AddVariables(*config_options)
@ -808,6 +808,8 @@ if env['coverage']:
print 'Error: coverage testing is only available with GCC' print 'Error: coverage testing is only available with GCC'
exit(0) exit(0)
if env['toolchain'] == 'mingw':
env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])
def config_error(message): def config_error(message):
print 'ERROR:', message print 'ERROR:', message
@ -1076,14 +1078,14 @@ addInstallActions = ('install' in COMMAND_LINE_TARGETS or
# Directories where things will be staged for package creation. These # Directories where things will be staged for package creation. These
# variables should always be used by the Install(...) targets # variables should always be used by the Install(...) targets
if env['stage_dir']: if env['stage_dir']:
pp = env['python_prefix']
instRoot = pjoin(os.getcwd(), env['stage_dir'], instRoot = pjoin(os.getcwd(), env['stage_dir'],
stripDrive(env['prefix']).strip('/\\')) stripDrive(env['prefix']).strip('/\\'))
if pp: for k in ('python_prefix', 'python3_prefix'):
env['python_prefix'] = pjoin(os.getcwd(), env['stage_dir'], if env[k]:
stripDrive(pp).strip('/\\')) env[k] = pjoin(os.getcwd(), env['stage_dir'],
else: stripDrive(env[k]).strip('/\\'))
env['python_prefix'] = pjoin(os.getcwd(), env['stage_dir']) else:
env[k] = pjoin(os.getcwd(), env['stage_dir'])
else: else:
instRoot = env['prefix'] instRoot = env['prefix']
@ -1144,7 +1146,6 @@ cdefine('DEBUG_MODE', 'debug_verbose')
# Need to test all of these to see what platform.system() returns # Need to test all of these to see what platform.system() returns
configh['SOLARIS'] = 1 if env['OS'] == 'Solaris' else None configh['SOLARIS'] = 1 if env['OS'] == 'Solaris' else None
configh['DARWIN'] = 1 if env['OS'] == 'Darwin' else None configh['DARWIN'] = 1 if env['OS'] == 'Darwin' else None
configh['CYGWIN'] = 1 if env['OS'] == 'Cygwin' else None
cdefine('NEEDS_GENERIC_TEMPL_STATIC_DECL', 'OS', 'Solaris') cdefine('NEEDS_GENERIC_TEMPL_STATIC_DECL', 'OS', 'Solaris')
cdefine('HAS_NUMPY', 'python_array', 'numpy') cdefine('HAS_NUMPY', 'python_array', 'numpy')
@ -1459,8 +1460,8 @@ def postInstallMessage(target, source, env):
env['python_example_loc'] = pjoin(env['python_module_loc'], 'cantera', 'examples') env['python_example_loc'] = pjoin(env['python_module_loc'], 'cantera', 'examples')
env['matlab_sample_loc'] = pjoin(env['ct_matlab_dir'], 'matlab') env['matlab_sample_loc'] = pjoin(env['ct_sampledir'], 'matlab')
env['matlab_ctpath_loc'] = pjoin(env['prefix'], 'matlab', 'ctpath.m') env['matlab_ctpath_loc'] = pjoin(env['ct_matlab_dir'], 'ctpath.m')
print """ print """
Cantera has been successfully installed. Cantera has been successfully installed.

View file

@ -34,7 +34,7 @@ PROJECT_NAME = Cantera
# This could be handy for archiving the generated documentation or # This could be handy for archiving the generated documentation or
# if some version control system is used. # if some version control system is used.
PROJECT_NUMBER = 2.0 PROJECT_NUMBER = 2.1.1
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.

View file

@ -116,8 +116,8 @@ Downloading the Cantera source code
Stable Release Stable Release
-------------- --------------
* Option 1: Download the most recent source tarball from the `Cantera Google * Option 1: Download the most recent source tarball from `SourceForge
Code Site <http://code.google.com/p/cantera/downloads/list>`_ and extract the <https://sourceforge.net/projects/cantera/files/cantera/>`_ and extract the
contents. contents.
* Option 2: Check out the code using Subversion:: * Option 2: Check out the code using Subversion::
@ -126,7 +126,7 @@ Stable Release
* Option 3: Check out the code using Git:: * Option 3: Check out the code using Git::
git svn clone --std-layout http://cantera.googlecode.com/svn/cantera cantera git svn clone --stdlayout http://cantera.googlecode.com/svn/cantera cantera
git checkout 2.0 git checkout 2.0
Development Version Development Version
@ -138,7 +138,7 @@ Development Version
* Option 2: Check out the code using Git:: * Option 2: Check out the code using Git::
git svn clone --std-layout http://cantera.googlecode.com/svn/cantera cantera git svn clone --stdlayout http://cantera.googlecode.com/svn/cantera cantera
Determine configuration options Determine configuration options
=============================== ===============================
@ -166,7 +166,7 @@ General
The above paths are typical defaults on Linux, Windows, and OS X, The above paths are typical defaults on Linux, Windows, and OS X,
respectively. respectively.
* SCons saves configuration options specified on the command line in the file * SCons saves configuration options specified on the command line in the file
\b cantera.conf in the root directory of the source tree, so generally it is **cantera.conf** in the root directory of the source tree, so generally it is
not necessary to respecify configuration options when rebuilding Cantera. To not necessary to respecify configuration options when rebuilding Cantera. To
unset a previously set configuration option, either remove the corresponding unset a previously set configuration option, either remove the corresponding
line from cantera.conf or use the syntax:: line from cantera.conf or use the syntax::

View file

@ -75,7 +75,7 @@ copyright = u'2012, Cantera Developers'
# The short X.Y version. # The short X.Y version.
version = '2.1' version = '2.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '2.1.0' release = '2.1.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View file

@ -24,7 +24,7 @@ with Python syntax you already understand many of the details and can probably
skip ahead to :ref:`sec-dimensions`. skip ahead to :ref:`sec-dimensions`.
Entries have fields that can be assigned values. A species entry is shown below Entries have fields that can be assigned values. A species entry is shown below
that has fields name and atoms (plus several others):: that has fields *name* and *atoms* (plus several others)::
species(name='C60', atoms='C:60') species(name='C60', atoms='C:60')
@ -84,11 +84,6 @@ character on a line is ignored::
Strings Strings
------- -------
Strings may be enclosed in single quotes or double quotes, but they must
match. To create a string containing single quotes, enclose it in double quotes,
and vice versa. If you want to create a string to extend over multiple lines,
enclose it in triple double quotes.
Strings may be enclosed in single quotes or double quotes, but they must Strings may be enclosed in single quotes or double quotes, but they must
match. To create a string containing single quotes, enclose it in double quotes, match. To create a string containing single quotes, enclose it in double quotes,
and vice versa. If you want to create a string to extend over multiple lines, and vice versa. If you want to create a string to extend over multiple lines,
@ -361,7 +356,7 @@ use two formats, one designed for writing by humans, the other for reading by
machines, and provide a preprocessor to convert the human-friendly format to the machines, and provide a preprocessor to convert the human-friendly format to the
machine-friendly one. machine-friendly one.
Preprocessor Intenals: the ``ctml_writer`` Module Preprocessor Internals: the ``ctml_writer`` Module
------------------------------------------------- -------------------------------------------------
If you are interested in seeing the internals of how the preprocessing works, If you are interested in seeing the internals of how the preprocessing works,

View file

@ -269,16 +269,21 @@ Option String Meaning
``'skip_undeclared_third_bodies'`` When importing reactions with third body efficiencies, ``'skip_undeclared_third_bodies'`` When importing reactions with third body efficiencies,
ignore any efficiencies for undeclared species, rather ignore any efficiencies for undeclared species, rather
than flagging them as an error. than flagging them as an error.
``'allow_discontinuous_thermo'`` Disable the automatic adjustment of NASA polynomials to
eliminate discontinuities in enthalpy and entropy at the
midpoint temperature.
================================== ================ ================================== ================
Using the ``options`` field, it is possible to extract a sub-mechanism from a large Using the ``options`` field, it is possible to extract a sub-mechanism from a large
reaction mechanism, as follows:: reaction mechanism, as follows::
ideal_gas(name = 'hydrogen_mech', ideal_gas(name = 'hydrogen_mech',
species = 'gri30: all', elements = 'H O',
species = 'gri30:all',
reactions = 'gri30:all', reactions = 'gri30:all',
options = ('skip_undeclared_elements', options = ('skip_undeclared_elements',
'skip_undeclared_species')) 'skip_undeclared_species',
'skip_undeclared_third_bodies'))
If we import this into Matlab, for example, we get a gas mixture containing the If we import this into Matlab, for example, we get a gas mixture containing the
8 species (out of 53 total) that contain only H and O: 8 species (out of 53 total) that contain only H and O:
@ -287,53 +292,64 @@ If we import this into Matlab, for example, we get a gas mixture containing the
>> gas = importPhase('gas.cti', 'hydrogen_mech') >> gas = importPhase('gas.cti', 'hydrogen_mech')
temperature 300 K hydrogen_mech:
pressure 1237.28 Pa
density 0.001 kg/m^3
mean mol. weight 2.01588 amu
X Y temperature 0.001 K
------------ ------------ pressure 0.00412448 Pa
H2 1.000000e+00 1.000000e+00 density 0.001 kg/m^3
H 0.000000e+00 0.000000e+00 mean mol. weight 2.01588 amu
O 0.000000e+00 0.000000e+00
O2 0.000000e+00 0.000000e+00 1 kg 1 kmol
OH 0.000000e+00 0.000000e+00 ----------- ------------
H2O 0.000000e+00 0.000000e+00 enthalpy -3.786e+006 -7.632e+006 J
HO2 0.000000e+00 0.000000e+00 internal energy -3.786e+006 -7.632e+006 J
H2O2 0.000000e+00 0.000000e+00 entropy 6210.88 1.252e+004 J/K
Gibbs function -3.786e+006 -7.632e+006 J
heat capacity c_p 9669.19 1.949e+004 J/K
heat capacity c_v 5544.7 1.118e+004 J/K
X Y Chem. Pot. / RT
------------- ------------ ------------
H2 1 1 -917934
H 0 0
O 0 0
O2 0 0
OH 0 0
H2O 0 0
HO2 0 0
H2O2 0 0
>> eqs = reactionEqn(gas) >> eqs = reactionEqn(gas)
eqs = eqs =
'2 O + M <=> O2 + M' '2 O + M <=> O2 + M'
'O + H + M <=> OH + M' 'O + H + M <=> OH + M'
'O + H2 <=> H + OH' 'O + H2 <=> H + OH'
'O + HO2 <=> OH + O2' 'O + HO2 <=> OH + O2'
'O + H2O2 <=> OH + HO2' 'O + H2O2 <=> OH + HO2'
'H + O2 + M <=> HO2 + M' 'H + O2 + M <=> HO2 + M'
'H + 2 O2 <=> HO2 + O2' 'H + 2 O2 <=> HO2 + O2'
'H + O2 + H2O <=> HO2 + H2O' 'H + O2 + H2O <=> HO2 + H2O'
'H + O2 <=> O + OH' 'H + O2 <=> O + OH'
'2 H + M <=> H2 + M' '2 H + M <=> H2 + M'
'2 H + H2 <=> 2 H2' '2 H + H2 <=> 2 H2'
'2 H + H2O <=> H2 + H2O' '2 H + H2O <=> H2 + H2O'
'H + OH + M <=> H2O + M' 'H + OH + M <=> H2O + M'
'H + HO2 <=> O + H2O' 'H + HO2 <=> O + H2O'
'H + HO2 <=> O2 + H2' 'H + HO2 <=> O2 + H2'
'H + HO2 <=> 2 OH' 'H + HO2 <=> 2 OH'
'H + H2O2 <=> HO2 + H2' 'H + H2O2 <=> HO2 + H2'
'H + H2O2 <=> OH + H2O' 'H + H2O2 <=> OH + H2O'
'OH + H2 <=> H + H2O' 'OH + H2 <=> H + H2O'
'2 OH (+ M) <=> H2O2 (+ M)' '2 OH (+ M) <=> H2O2 (+ M)'
'2 OH <=> O + H2O' '2 OH <=> O + H2O'
'OH + HO2 <=> O2 + H2O' 'OH + HO2 <=> O2 + H2O'
'OH + H2O2 <=> HO2 + H2O' 'OH + H2O2 <=> HO2 + H2O'
'OH + H2O2 <=> HO2 + H2O' 'OH + H2O2 <=> HO2 + H2O'
'2 HO2 <=> O2 + H2O2' '2 HO2 <=> O2 + H2O2'
'2 HO2 <=> O2 + H2O2' '2 HO2 <=> O2 + H2O2'
'OH + HO2 <=> O2 + H2O' 'OH + HO2 <=> O2 + H2O'
Ideal Gas Mixtures Ideal Gas Mixtures
------------------ ------------------
@ -348,13 +364,13 @@ them. It supports all of the options in the widely-used model described by Kee
et al. [#Kee1989]_, plus some additional options for species thermodynamic et al. [#Kee1989]_, plus some additional options for species thermodynamic
properties and reaction rate expressions. properties and reaction rate expressions.
An example of an ideal_gas entry is shown below:: An example of an ``ideal_gas`` entry is shown below::
ideal_gas(name='air8', ideal_gas(name='air8',
elements='N O Ar', elements='N O Ar',
species='gri30: N2 O2 N O NO NO2 N2O AR', species='gri30: N2 O2 N O NO NO2 N2O AR',
reactions='all', reactions='all',
transport='mix', transport='Mix',
initial_state=state(temperature=500.0, initial_state=state(temperature=500.0,
pressure=(1.0, 'atm'), pressure=(1.0, 'atm'),
mole_fractions='N2:0.78, O2:0.21, AR:0.01')) mole_fractions='N2:0.78, O2:0.21, AR:0.01'))
@ -374,17 +390,17 @@ Two transport models are available for use with ideal gas mixtures. The first is
a multicomponent transport model that is based on the model described by a multicomponent transport model that is based on the model described by
Dixon-Lewis [#dl68]_ (see also Kee et al. [#Kee2003]_). The second is a model that uses Dixon-Lewis [#dl68]_ (see also Kee et al. [#Kee2003]_). The second is a model that uses
mixture rules. To select the multicomponent model, set the transport field to mixture rules. To select the multicomponent model, set the transport field to
the string ``'multi'``, and to select the mixture-averaged model, set it to the the string ``'Multi'``, and to select the mixture-averaged model, set it to the
string ``'mix'``:: string ``'Mix'``::
ideal_gas(name="gas1", ideal_gas(name="gas1",
..., ...,
transport="multi", # use multicomponent formulation transport="Multi", # use multicomponent formulation
...) ...)
ideal_gas(name="gas2", ideal_gas(name="gas2",
..., ...,
transport="mix", # use mixture-averaged formulation transport="Mix", # use mixture-averaged formulation
...) ...)
Stoichiometric Solid Stoichiometric Solid

View file

@ -63,8 +63,8 @@ As a shorthand, if the ``rate_coeff`` field is assigned a sequence of three numb
rate_coeff = [1.0e13, 0, (7.3, 'kcal/mol')] # equivalent to above rate_coeff = [1.0e13, 0, (7.3, 'kcal/mol')] # equivalent to above
The units of the pre-exponential factor *A* can be specified explicitly if The units of the pre-exponential factor *A* can be specified explicitly if
desired. If not specified, they will be constructed using the *quantity*, length, desired. If not specified, they will be constructed using the *quantity*, *length*,
and time units specified in the units directive. Since the units of *A* depend on and *time* units specified in the units directive. Since the units of *A* depend on
the reaction order, the units of each reactant concentration (different for bulk the reaction order, the units of each reactant concentration (different for bulk
species in solution, surface species, and pure condensed-phase species), and the species in solution, surface species, and pure condensed-phase species), and the
units of the rate of progress (different for homogeneous and heterogeneous units of the rate of progress (different for homogeneous and heterogeneous
@ -158,15 +158,15 @@ A three-body reaction is a gas-phase reaction of the form:
.. math:: .. math::
{\rm A + B} \rightleftharpoons {\rm AB + M} {\rm A + B + M} \rightleftharpoons {\rm AB + M}
Here M is an unspecified collision partner that carries away excess energy to Here *M* is an unspecified collision partner that carries away excess energy to
stabilize the AB molecule (forward direction) or supplies energy to break the AB stabilize the *AB* molecule (forward direction) or supplies energy to break the *AB*
bond (reverse direction). bond (reverse direction).
Different species may be more or less effective in acting as the collision partner. A species that is much lighter than Different species may be more or less effective in acting as the collision partner. A species that is much lighter than
A and B may not be able to transfer much of its kinetic energy, and so would be inefficient as a collision partner. On *A* and *B* may not be able to transfer much of its kinetic energy, and so would be inefficient as a collision partner. On
the other hand, a species with a transition from its ground state that is nearly resonant with one in the AB* activated the other hand, a species with a transition from its ground state that is nearly resonant with one in the *AB** activated
complex may be much more effective at exchanging energy than would otherwise be expected. complex may be much more effective at exchanging energy than would otherwise be expected.
These effects can be accounted for by defining a collision efficiency These effects can be accounted for by defining a collision efficiency
@ -284,7 +284,7 @@ supports the extended 5-parameter form, given by:
F(T, P_r) = d \bigl[a \exp(-b/T) + \exp(-T/c)\bigr]^{1/(1+\log_{10}^2 P_r )} T^e F(T, P_r) = d \bigl[a \exp(-b/T) + \exp(-T/c)\bigr]^{1/(1+\log_{10}^2 P_r )} T^e
In keeping with the nomenclature of [Kee et al., 1989], we will refer to this as In keeping with the nomenclature of Kee et al.[#Kee1989]_, we will refer to this as
the "SRI" falloff function. It is implemented by the :class:`SRI` directive. the "SRI" falloff function. It is implemented by the :class:`SRI` directive.
.. :: NOTE: "definingphases.pdf" contains documentation for the Wang-Frenklach falloff .. :: NOTE: "definingphases.pdf" contains documentation for the Wang-Frenklach falloff
@ -371,7 +371,7 @@ that pressure.
Chebyshev Reaction Rate Expressions Chebyshev Reaction Rate Expressions
=================================== ===================================
Class :class:`chebyshev` represents a phenomenological rate coefficient Class :class:`chebyshev_reaction` represents a phenomenological rate coefficient
:math:`k(T,P)` in terms of a bivariate Chebyshev polynomial. The rate constant :math:`k(T,P)` in terms of a bivariate Chebyshev polynomial. The rate constant
can be written as: can be written as:

View file

@ -176,7 +176,7 @@ The Shomate parameterization is:
.. math:: .. math::
\hat{c}_p^0(T) = A + Bt + Ct^2 + Dt^3 | \frac{E}{t^2} \hat{c}_p^0(T) = A + Bt + Ct^2 + Dt^3 + \frac{E}{t^2}
\hat{h}^0(T) = At + \frac{Bt^2}{2} + \frac{Ct^3}{3} + \frac{Dt^4}{4} - \hat{h}^0(T) = At + \frac{Bt^2}{2} + \frac{Ct^3}{3} + \frac{Dt^4}{4} -
\frac{E}{t} + F \frac{E}{t} + F
@ -190,7 +190,7 @@ G. This parameterization is used to represent reference-state properties in the
coefficients A through G should be entered precisely as shown there, with no coefficients A through G should be entered precisely as shown there, with no
units attached. Unit conversions to SI will be handled internally. units attached. Unit conversions to SI will be handled internally.
Example usage of the :class:`shomate` directive:: Example usage of the :class:`Shomate` directive::
# use a single Shomate parameterization. # use a single Shomate parameterization.
species(name = "O2", species(name = "O2",
@ -204,7 +204,7 @@ Constant Heat Capacity
In some cases, species properties may only be required at a single temperature In some cases, species properties may only be required at a single temperature
or over a narrow temperature range. In such cases, the heat capacity can be or over a narrow temperature range. In such cases, the heat capacity can be
approximated as constant, and simpler expressions used for the thermodynamic approximated as constant, and simpler expressions can be used for the thermodynamic
properties. The :class:`const_cp` parameterization computes the properties as properties. The :class:`const_cp` parameterization computes the properties as
follows: follows:

View file

@ -107,7 +107,7 @@ should be replaced with::
>>> gas.P >>> gas.P
>>> gas.Y >>> gas.Y
For pure fluid phases, the property `X` refers to the vapor mass fraction or "quality" of the phase. The following:: For pure fluid phases, the property ``X`` refers to the vapor mass fraction or "quality" of the phase. The following::
>>> w = Cantera.liquidvapor.Water() >>> w = Cantera.liquidvapor.Water()
>>> w.set(T=400, Vapor=0.5) >>> w.set(T=400, Vapor=0.5)
@ -134,6 +134,13 @@ should be replaced with::
>>> gas.UV = -1.1e6, 5.5 >>> gas.UV = -1.1e6, 5.5
>>> gas.TPY = 300, 101325, 'H2:1.0' >>> gas.TPY = 300, 101325, 'H2:1.0'
The ``saveState`` and ``restoreState`` methods have been removed. Their
functionality can be replicated as follows::
>>> state = gas.TDY
>>> # (operations that modify gas)
>>> gas.TDY = state
Printing Phase Summaries Printing Phase Summaries
------------------------ ------------------------
@ -246,3 +253,15 @@ should be replaced with::
>>> f.flame.set_steady_tolerances(default=tol_ss) >>> f.flame.set_steady_tolerances(default=tol_ss)
>>> f.flame.set_transient_tolerances(default=tol_ts) >>> f.flame.set_transient_tolerances(default=tol_ts)
>>> f.set_refine_criteria(ratio=4, slope=0.2, curve=0.3, prune=0.04) >>> f.set_refine_criteria(ratio=4, slope=0.2, curve=0.3, prune=0.04)
To change the transport model and enbale calculation of the Soret diffusion term, the following::
>>> gas.addTransportModel('Multi')
>>> gas.switchTransportModel('Multi')
>>> f.flame.setTransportModel(gas)
>>> f.flame.enableSoret()
should be replaced with::
>>> f.transport_model = 'Multi'
>>> f.soret_enabled = True

View file

@ -173,8 +173,8 @@ Properties may be read independently or together::
>>> gas1.UV >>> gas1.UV
(8346188.494954427, 48.8465747765848) (8346188.494954427, 48.8465747765848)
The composition can be set in terms of either mole fractions (`X`) or mass The composition can be set in terms of either mole fractions (``X``) or mass
fractions (`Y`):: fractions (``Y``)::
>>> gas1.X = 'CH4:1, O2:2, N2:7.52' >>> gas1.X = 'CH4:1, O2:2, N2:7.52'
@ -264,7 +264,7 @@ The composition above was specified using a string. The format is a comma-
separated list of ``<species name>:<relative mole numbers>`` pairs. The mole separated list of ``<species name>:<relative mole numbers>`` pairs. The mole
numbers will be normalized to produce the mole fractions, and therefore they numbers will be normalized to produce the mole fractions, and therefore they
are "relative" mole numbers. Mass fractions can be set in this way too by are "relative" mole numbers. Mass fractions can be set in this way too by
changing 'X' to 'Y' in the above statements. changing ``X`` to ``Y`` in the above statements.
The composition can also be set using an array, which must have the same size The composition can also be set using an array, which must have the same size
as the number of species. For example, to set all 53 mole fractions to the as the number of species. For example, to set all 53 mole fractions to the
@ -307,7 +307,7 @@ your system, set environment variable ``CANTERA_DATA`` to the directory where
they are located. Alternatively, you can call function `add_directory` to add they are located. Alternatively, you can call function `add_directory` to add
a directory to the Cantera search path:: a directory to the Cantera search path::
>>> add_directory('/usr/local/cantera/my_data_files') >>> ct.add_directory('/usr/local/cantera/my_data_files')
Cantera input files are plain text files, and can be created with any text Cantera input files are plain text files, and can be created with any text
editor. See the document :ref:`sec-defining-phases` for more information. editor. See the document :ref:`sec-defining-phases` for more information.
@ -321,8 +321,8 @@ two bulk phases and the interface between them from file ``diamond.cti``::
>>> diamond_surf = ct.Interface('diamond.cti' , 'diamond_100', >>> diamond_surf = ct.Interface('diamond.cti' , 'diamond_100',
[gas2, diamond]) [gas2, diamond])
Note that the bulk (i.e., 3D) phases that participate in the surface reactions Note that the bulk (i.e., 3D or homogeneous) phases that participate in the
must also be passed as arguments to `Interface`. surface reactions must also be passed as arguments to `Interface`.
When Cantera reads a ``.cti`` input file, wherever it is located, it always When Cantera reads a ``.cti`` input file, wherever it is located, it always
writes a file of the same name but with extension ``.xml`` *in the local writes a file of the same name but with extension ``.xml`` *in the local
@ -398,7 +398,7 @@ method::
>>> g.TPX = 300.0, ct.one_atm, 'CH4:0.95,O2:2,N2:7.52' >>> g.TPX = 300.0, ct.one_atm, 'CH4:0.95,O2:2,N2:7.52'
>>> g.equilibrate('TP') >>> g.equilibrate('TP')
The above statement sets the state of object 'g' to the state of chemical The above statement sets the state of object ``g`` to the state of chemical
equilibrium holding temperature and pressure fixed. Alternatively, the equilibrium holding temperature and pressure fixed. Alternatively, the
specific enthalpy and pressure can be held fixed:: specific enthalpy and pressure can be held fixed::
@ -411,7 +411,7 @@ Other options are:
- 'SV' fixed specific entropy and specific volume - 'SV' fixed specific entropy and specific volume
- 'SP' fixed specific entropy and pressure - 'SP' fixed specific entropy and pressure
How can you tell if 'equilibrate' has correctly found the chemical equilibrium How can you tell if ``equilibrate`` has correctly found the chemical equilibrium
state? One way is verify that the net rates of progress of all reversible state? One way is verify that the net rates of progress of all reversible
reactions are zero. Here is the code to do this: reactions are zero. Here is the code to do this:
@ -428,12 +428,12 @@ If the magnitudes of the numbers in this list are all very small, then each
reversible reaction is very nearly equilibrated, which only occurs if the gas reversible reaction is very nearly equilibrated, which only occurs if the gas
is in chemical equilibrium. is in chemical equilibrium.
You might be wondering how 'equilibrate' works. (Then again, you might not). You might be wondering how ``equilibrate`` works. (Then again, you might not).
Method 'equilibrate' invokes Cantera's chemical equilibrium solver, which uses Method ``equilibrate`` invokes Cantera's chemical equilibrium solver, which uses
an element potential method. The element potential method is one of a class of an element potential method. The element potential method is one of a class of
equivalent 'nonstoichiometric' methods that all have the characteristic that equivalent *nonstoichiometric* methods that all have the characteristic that
the problem reduces to solving a set of M nonlinear algebraic equations, where the problem reduces to solving a set of M nonlinear algebraic equations, where
M is the number of elements (not species). The so-called 'stoichiometric' M is the number of elements (not species). The so-called *stoichiometric*
methods, on the other hand, (including Gibbs minimization), require solving K methods, on the other hand, (including Gibbs minimization), require solving K
nonlinear equations, where K is the number of species (usually K >> M). See nonlinear equations, where K is the number of species (usually K >> M). See
Smith and Missen, "Chemical Reaction Equilibrium Analysis" for more Smith and Missen, "Chemical Reaction Equilibrium Analysis" for more

View file

@ -24,7 +24,9 @@ Reactors
.. autoclass:: Reservoir .. autoclass:: Reservoir
.. autoclass:: Reactor .. autoclass:: Reactor
.. autoclass:: IdealGasReactor
.. autoclass:: ConstPressureReactor .. autoclass:: ConstPressureReactor
.. autoclass:: IdealGasConstPressureReactor
.. autoclass:: FlowReactor .. autoclass:: FlowReactor
Flow Controllers Flow Controllers

View file

@ -8,14 +8,14 @@ Installation
**How do I install Cantera on Windows?** **How do I install Cantera on Windows?**
Download the MSI installer for Cantera and the corresponding Python module Download the MSI installer for Cantera and the corresponding Python module
from `Google Code <https://code.google.com/p/cantera/downloads/list>`_. from `SourceForge <https://sourceforge.net/projects/cantera/files/cantera/>`_.
Choose between x86 and x64 based on the versions of Python and/or Matlab Choose between x86 and x64 based on the versions of Python and/or Matlab
you want to work with. you want to work with.
**How do I install Cantera on Linux?** **How do I install Cantera on Linux?**
Download the source code from `Google Code Download the source code (e.g. ``cantera-2.1.1.tar.gz``) from `SourceForge
<https://code.google.com/p/cantera/downloads/list>`_ and follow the <https://sourceforge.net/projects/cantera/files/cantera/>`_ and follow the
instructions in the :ref:`sec-compiling`. instructions in the :ref:`sec-compiling`.
General General
@ -62,7 +62,7 @@ Support and Bug Reporting
**What information should I include in my bug report?** **What information should I include in my bug report?**
- The version of Cantera are you using, and how you installed it - The version of Cantera are you using, and how you installed it
- The operating system are you using - The operating system you are using
- If you compiled Cantera, what compiler you used, and what compilation - If you compiled Cantera, what compiler you used, and what compilation
options you specified options you specified
- The version of Python or Matlab are you using, if applicable - The version of Python or Matlab are you using, if applicable

View file

@ -99,15 +99,15 @@ The rate of change in the mass of each species is:
\frac{d(mY_k)}{dt} = \sum_{in} \dot{m}_{in} Y_{k,in} - \frac{d(mY_k)}{dt} = \sum_{in} \dot{m}_{in} Y_{k,in} -
\sum_{out} \dot{m}_{out} Y_k + \sum_{out} \dot{m}_{out} Y_k +
+ \dot{m}_{k,gen} \dot{m}_{k,gen}
Expanding the derivative on the left hand side and substituting the equation Expanding the derivative on the left hand side and substituting the equation
for `dm/dt`, the equation for each homogeneous phase species is: for `dm/dt`, the equation for each homogeneous phase species is:
.. math:: .. math::
m \frac{dY}{dt} = \sum_{in} (Y_{k,in} - Y_k) + m \frac{dY}{dt} = \sum_{in} \dot{m}_{in} (Y_{k,in} - Y_k)+
\dot{m}_{k,gen} - Y_k \dot{m}_{gen} \dot{m}_{k,gen} - Y_k \dot{m}_{wall}
Energy Conservation Energy Conservation
------------------- -------------------
@ -117,7 +117,7 @@ for an open system:
.. math:: .. math::
\frac{dU}{dt} = - p \frac{dV}{dt} - Q + \frac{dU}{dt} = - p \frac{dV}{dt} - \dot{Q} +
\sum_{in} \dot{m}_{in} h_{in} - h \sum_{out} \dot{m}_{out} \sum_{in} \dot{m}_{in} h_{in} - h \sum_{out} \dot{m}_{out}
Ideal Gas Reactor Ideal Gas Reactor
@ -141,9 +141,9 @@ temperature:
.. math:: .. math::
m c_v \frac{dT}{dt} = - p \frac{dV}{dt} - Q m c_v \frac{dT}{dt} = - p \frac{dV}{dt} - \dot{Q}
+ \sum_{in} \dot{m}_{in} \left( h_{in} - \sum_k u_k Y_{k,in} \right) + \sum_{in} \dot{m}_{in} \left( h_{in} - \sum_k u_k Y_{k,in} \right)
- p V \sum_{out} \dot{m}_{out} - \sum_k \dot{m}_{k,gen} u_k - \frac{p V}{m} \sum_{out} \dot{m}_{out} - \sum_k \dot{m}_{k,gen} u_k
While this form of the energy equation is somewhat more complicated, it While this form of the energy equation is somewhat more complicated, it
significantly reduces the cost of evaluating the system Jacobian, since the significantly reduces the cost of evaluating the system Jacobian, since the
@ -168,7 +168,7 @@ Noting that `dp/dt = 0` and substituting into the energy equation yields:
.. math:: .. math::
\frac{dH}{dt} = - Q + \sum_{in} \dot{m}_{in} h_{in} \frac{dH}{dt} = - \dot{Q} + \sum_{in} \dot{m}_{in} h_{in}
- h \sum_{out} \dot{m}_{out} - h \sum_{out} \dot{m}_{out}
The species and continuity equations are the same as for the general reactor The species and continuity equations are the same as for the general reactor
@ -193,5 +193,5 @@ temperature:
.. math:: .. math::
m c_p \frac{dT}{dt} = - Q - \sum_k h_k \dot{m}_{k,gen} m c_p \frac{dT}{dt} = - \dot{Q} - \sum_k h_k \dot{m}_{k,gen}
+ \sum_{in} \dot{m}_{in} \left(h_{in} - \sum_k h_k Y_{k,in} \right) + \sum_{in} \dot{m}_{in} \left(h_{in} - \sum_k h_k Y_{k,in} \right)

View file

@ -81,14 +81,6 @@ if env['build_with_f2c']:
arithenv.Command('#ext/f2c_libs/arith.h', 'f2c_libs/arithchk/arithchk$PROGSUFFIX', arithenv.Command('#ext/f2c_libs/arith.h', 'f2c_libs/arithchk/arithchk$PROGSUFFIX',
'$SOURCE > $TARGET') '$SOURCE > $TARGET')
headerenv = prep_f2c(env)
# Possibly system-dependent headers
headerenv.Command('#ext/f2c_libs/signal1.h', 'f2c_libs/signal1.h0',
Copy('$TARGET', '$SOURCE'))
headerenv.Command('#ext/f2c_libs/sysdep1.h', 'f2c_libs/sysdep1.h0',
Copy('$TARGET', '$SOURCE'))
libs.append(('f2c_libs', 'c', prep_f2c)) libs.append(('f2c_libs', 'c', prep_f2c))
if env['BUILD_BLAS_LAPACK']: if env['BUILD_BLAS_LAPACK']:

View file

@ -1,3 +1 @@
arith.h arith.h
signal1.h
sysdep1.h

View file

@ -1,3 +1,30 @@
Changes for 1.7.0:
* New feature: death tests are supported on OpenBSD and in iOS
simulator now.
* New feature: Google Test now implements a protocol to allow
a test runner to detect that a test program has exited
prematurely and report it as a failure (before it would be
falsely reported as a success if the exit code is 0).
* New feature: Test::RecordProperty() can now be used outside of the
lifespan of a test method, in which case it will be attributed to
the current test case or the test program in the XML report.
* New feature (potentially breaking): --gtest_list_tests now prints
the type parameters and value parameters for each test.
* Improvement: char pointers and char arrays are now escaped properly
in failure messages.
* Improvement: failure summary in XML reports now includes file and
line information.
* Improvement: the <testsuites> XML element now has a timestamp attribute.
* Improvement: When --gtest_filter is specified, XML report now doesn't
contain information about tests that are filtered out.
* Fixed the bug where long --gtest_filter flag values are truncated in
death tests.
* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a
function instead of a macro in order to work better with Clang.
* Compatibility fixes with C++ 11 and various platforms.
* Bug/warning fixes.
Changes for 1.6.0: Changes for 1.6.0:
* New feature: ADD_FAILURE_AT() for reporting a test failure at the * New feature: ADD_FAILURE_AT() for reporting a test failure at the

View file

@ -119,21 +119,22 @@ and Xcode) to compile
${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest-all.cc
with with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR}
in the normal header search path. Assuming a Linux-like system and gcc,
${GTEST_DIR}/include and ${GTEST_DIR}
in the header search path. Assuming a Linux-like system and gcc,
something like the following will do: something like the following will do:
g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
ar -rv libgtest.a gtest-all.o ar -rv libgtest.a gtest-all.o
Next, you should compile your test source file with (We need -pthread as Google Test uses threads.)
${GTEST_DIR}/include in the header search path, and link it with gtest
and any other necessary libraries:
g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test Next, you should compile your test source file with
${GTEST_DIR}/include in the system header search path, and link it
with gtest and any other necessary libraries:
g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
-o your_test
As an example, the make/ directory contains a Makefile that you can As an example, the make/ directory contains a Makefile that you can
use to build Google Test on systems where GNU make is available use to build Google Test on systems where GNU make is available
@ -217,6 +218,16 @@ default build location. See the "xcodebuild" man page for more
information about building different configurations and building in information about building different configurations and building in
different locations. different locations.
If you wish to use the Google Test Xcode project with Xcode 4.x and
above, you need to either:
* update the SDK configuration options in xcode/Config/General.xconfig.
Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If
you choose this route you lose the ability to target earlier versions
of MacOS X.
* Install an SDK for an earlier version. This doesn't appear to be
supported by Apple, but has been reported to work
(http://stackoverflow.com/questions/5378518).
Tweaking Google Test Tweaking Google Test
-------------------- --------------------

View file

@ -51,6 +51,17 @@ GTEST_DECLARE_string_(death_test_style);
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
namespace internal {
// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process. Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests. IMPORTANT: This is an internal utility. Using it may break the
// implementation of death tests. User code MUST NOT use it.
GTEST_API_ bool InDeathTestChild();
} // namespace internal
// The following macros are useful for writing death tests. // The following macros are useful for writing death tests.
// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is // Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
@ -75,7 +86,7 @@ GTEST_DECLARE_string_(death_test_style);
// for (int i = 0; i < 5; i++) { // for (int i = 0; i < 5; i++) {
// EXPECT_DEATH(server.ProcessRequest(i), // EXPECT_DEATH(server.ProcessRequest(i),
// "Invalid request .* in ProcessRequest()") // "Invalid request .* in ProcessRequest()")
// << "Failed to die on request " << i); // << "Failed to die on request " << i;
// } // }
// //
// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); // ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
@ -245,10 +256,10 @@ class GTEST_API_ KilledBySignal {
# ifdef NDEBUG # ifdef NDEBUG
# define EXPECT_DEBUG_DEATH(statement, regex) \ # define EXPECT_DEBUG_DEATH(statement, regex) \
do { statement; } while (::testing::internal::AlwaysFalse()) GTEST_EXECUTE_STATEMENT_(statement, regex)
# define ASSERT_DEBUG_DEATH(statement, regex) \ # define ASSERT_DEBUG_DEATH(statement, regex) \
do { statement; } while (::testing::internal::AlwaysFalse()) GTEST_EXECUTE_STATEMENT_(statement, regex)
# else # else

View file

@ -48,8 +48,11 @@
#include <limits> #include <limits>
#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-port.h"
#include "gtest/internal/gtest-internal.h"
// Ensures that there is at least one operator<< in the global namespace.
// See Message& operator<<(...) below for why.
void operator<<(const testing::internal::Secret&, int);
namespace testing { namespace testing {
@ -87,15 +90,7 @@ class GTEST_API_ Message {
public: public:
// Constructs an empty Message. // Constructs an empty Message.
// We allocate the stringstream separately because otherwise each use of Message();
// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
// stack frame leading to huge stack frames in some cases; gcc does not reuse
// the stack space.
Message() : ss_(new ::std::stringstream) {
// By default, we want there to be enough precision when printing
// a double to a Message.
*ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
}
// Copy constructor. // Copy constructor.
Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
@ -118,7 +113,22 @@ class GTEST_API_ Message {
// Streams a non-pointer value to this object. // Streams a non-pointer value to this object.
template <typename T> template <typename T>
inline Message& operator <<(const T& val) { inline Message& operator <<(const T& val) {
::GTestStreamToHelper(ss_.get(), val); // Some libraries overload << for STL containers. These
// overloads are defined in the global namespace instead of ::std.
//
// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
// overloads are visible in either the std namespace or the global
// namespace, but not other namespaces, including the testing
// namespace which Google Test's Message class is in.
//
// To allow STL containers (and other types that has a << operator
// defined in the global namespace) to be used in Google Test
// assertions, testing::Message must access the custom << operator
// from the global namespace. With this using declaration,
// overloads of << defined in the global namespace and those
// visible via Koenig lookup are both exposed in this function.
using ::operator <<;
*ss_ << val;
return *this; return *this;
} }
@ -140,7 +150,7 @@ class GTEST_API_ Message {
if (pointer == NULL) { if (pointer == NULL) {
*ss_ << "(null)"; *ss_ << "(null)";
} else { } else {
::GTestStreamToHelper(ss_.get(), pointer); *ss_ << pointer;
} }
return *this; return *this;
} }
@ -164,12 +174,8 @@ class GTEST_API_ Message {
// These two overloads allow streaming a wide C string to a Message // These two overloads allow streaming a wide C string to a Message
// using the UTF-8 encoding. // using the UTF-8 encoding.
Message& operator <<(const wchar_t* wide_c_str) { Message& operator <<(const wchar_t* wide_c_str);
return *this << internal::String::ShowWideCString(wide_c_str); Message& operator <<(wchar_t* wide_c_str);
}
Message& operator <<(wchar_t* wide_c_str) {
return *this << internal::String::ShowWideCString(wide_c_str);
}
#if GTEST_HAS_STD_WSTRING #if GTEST_HAS_STD_WSTRING
// Converts the given wide string to a narrow string using the UTF-8 // Converts the given wide string to a narrow string using the UTF-8
@ -183,13 +189,11 @@ class GTEST_API_ Message {
Message& operator <<(const ::wstring& wstr); Message& operator <<(const ::wstring& wstr);
#endif // GTEST_HAS_GLOBAL_WSTRING #endif // GTEST_HAS_GLOBAL_WSTRING
// Gets the text streamed to this object so far as a String. // Gets the text streamed to this object so far as an std::string.
// Each '\0' character in the buffer is replaced with "\\0". // Each '\0' character in the buffer is replaced with "\\0".
// //
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
internal::String GetString() const { std::string GetString() const;
return internal::StringStreamToString(ss_.get());
}
private: private:
@ -199,16 +203,20 @@ class GTEST_API_ Message {
// decide between class template specializations for T and T*, so a // decide between class template specializations for T and T*, so a
// tr1::type_traits-like is_pointer works, and we can overload on that. // tr1::type_traits-like is_pointer works, and we can overload on that.
template <typename T> template <typename T>
inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
if (pointer == NULL) { if (pointer == NULL) {
*ss_ << "(null)"; *ss_ << "(null)";
} else { } else {
::GTestStreamToHelper(ss_.get(), pointer); *ss_ << pointer;
} }
} }
template <typename T> template <typename T>
inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { inline void StreamHelper(internal::false_type /*is_pointer*/,
::GTestStreamToHelper(ss_.get(), value); const T& value) {
// See the comments in Message& operator <<(const T&) above for why
// we need this using statement.
using ::operator <<;
*ss_ << value;
} }
#endif // GTEST_OS_SYMBIAN #endif // GTEST_OS_SYMBIAN
@ -225,6 +233,18 @@ inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
return os << sb.GetString(); return os << sb.GetString();
} }
namespace internal {
// Converts a streamable value to an std::string. A NULL pointer is
// converted to "(null)". When the input value is a ::string,
// ::std::string, ::wstring, or ::std::wstring object, each NUL
// character in it is replaced with "\\0".
template <typename T>
std::string StreamableToString(const T& streamable) {
return (Message() << streamable).GetString();
}
} // namespace internal
} // namespace testing } // namespace testing
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_

View file

@ -1257,7 +1257,7 @@ inline internal::ParamGenerator<bool> Bool() {
// Boolean flags: // Boolean flags:
// //
// class FlagDependentTest // class FlagDependentTest
// : public testing::TestWithParam<tuple(bool, bool)> > { // : public testing::TestWithParam<tuple<bool, bool> > {
// virtual void SetUp() { // virtual void SetUp() {
// // Assigns external_flag_1 and external_flag_2 values from the tuple. // // Assigns external_flag_1 and external_flag_2 values from the tuple.
// tie(external_flag_1, external_flag_2) = GetParam(); // tie(external_flag_1, external_flag_2) = GetParam();

View file

@ -414,7 +414,7 @@ inline internal::ParamGenerator<bool> Bool() {
// Boolean flags: // Boolean flags:
// //
// class FlagDependentTest // class FlagDependentTest
// : public testing::TestWithParam<tuple(bool, bool)> > { // : public testing::TestWithParam<tuple<bool, bool> > {
// virtual void SetUp() { // virtual void SetUp() {
// // Assigns external_flag_1 and external_flag_2 values from the tuple. // // Assigns external_flag_1 and external_flag_2 values from the tuple.
// tie(external_flag_1, external_flag_2) = GetParam(); // tie(external_flag_1, external_flag_2) = GetParam();

View file

@ -630,9 +630,12 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
} }
} }
// This overload prints a (const) char array compactly. // This overload prints a (const) char array compactly.
GTEST_API_ void UniversalPrintArray(const char* begin, GTEST_API_ void UniversalPrintArray(
size_t len, const char* begin, size_t len, ::std::ostream* os);
::std::ostream* os);
// This overload prints a (const) wchar_t array compactly.
GTEST_API_ void UniversalPrintArray(
const wchar_t* begin, size_t len, ::std::ostream* os);
// Implements printing an array type T[N]. // Implements printing an array type T[N].
template <typename T, size_t N> template <typename T, size_t N>
@ -673,19 +676,72 @@ class UniversalPrinter<T&> {
// Prints a value tersely: for a reference type, the referenced value // Prints a value tersely: for a reference type, the referenced value
// (but not the address) is printed; for a (const) char pointer, the // (but not the address) is printed; for a (const) char pointer, the
// NUL-terminated string (but not the pointer) is printed. // NUL-terminated string (but not the pointer) is printed.
template <typename T>
class UniversalTersePrinter {
public:
static void Print(const T& value, ::std::ostream* os) {
UniversalPrint(value, os);
}
};
template <typename T>
class UniversalTersePrinter<T&> {
public:
static void Print(const T& value, ::std::ostream* os) {
UniversalPrint(value, os);
}
};
template <typename T, size_t N>
class UniversalTersePrinter<T[N]> {
public:
static void Print(const T (&value)[N], ::std::ostream* os) {
UniversalPrinter<T[N]>::Print(value, os);
}
};
template <>
class UniversalTersePrinter<const char*> {
public:
static void Print(const char* str, ::std::ostream* os) {
if (str == NULL) {
*os << "NULL";
} else {
UniversalPrint(string(str), os);
}
}
};
template <>
class UniversalTersePrinter<char*> {
public:
static void Print(char* str, ::std::ostream* os) {
UniversalTersePrinter<const char*>::Print(str, os);
}
};
#if GTEST_HAS_STD_WSTRING
template <>
class UniversalTersePrinter<const wchar_t*> {
public:
static void Print(const wchar_t* str, ::std::ostream* os) {
if (str == NULL) {
*os << "NULL";
} else {
UniversalPrint(::std::wstring(str), os);
}
}
};
#endif
template <>
class UniversalTersePrinter<wchar_t*> {
public:
static void Print(wchar_t* str, ::std::ostream* os) {
UniversalTersePrinter<const wchar_t*>::Print(str, os);
}
};
template <typename T> template <typename T>
void UniversalTersePrint(const T& value, ::std::ostream* os) { void UniversalTersePrint(const T& value, ::std::ostream* os) {
UniversalPrint(value, os); UniversalTersePrinter<T>::Print(value, os);
}
inline void UniversalTersePrint(const char* str, ::std::ostream* os) {
if (str == NULL) {
*os << "NULL";
} else {
UniversalPrint(string(str), os);
}
}
inline void UniversalTersePrint(char* str, ::std::ostream* os) {
UniversalTersePrint(static_cast<const char*>(str), os);
} }
// Prints a value using the type inferred by the compiler. The // Prints a value using the type inferred by the compiler. The
@ -694,7 +750,10 @@ inline void UniversalTersePrint(char* str, ::std::ostream* os) {
// NUL-terminated string. // NUL-terminated string.
template <typename T> template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os) { void UniversalPrint(const T& value, ::std::ostream* os) {
UniversalPrinter<T>::Print(value, os); // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
// UniversalPrinter with T directly.
typedef T T1;
UniversalPrinter<T1>::Print(value, os);
} }
#if GTEST_HAS_TR1_TUPLE #if GTEST_HAS_TR1_TUPLE
@ -787,7 +846,7 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
template <typename T> template <typename T>
::std::string PrintToString(const T& value) { ::std::string PrintToString(const T& value) {
::std::stringstream ss; ::std::stringstream ss;
internal::UniversalTersePrint(value, &ss); internal::UniversalTersePrinter<T>::Print(value, &ss);
return ss.str(); return ss.str();
} }

View file

@ -223,7 +223,7 @@ class GTEST_API_ SingleFailureChecker {
(substr));\ (substr));\
{\ {\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
&gtest_failures);\ &gtest_failures);\
if (::testing::internal::AlwaysTrue()) { statement; }\ if (::testing::internal::AlwaysTrue()) { statement; }\
}\ }\

View file

@ -62,7 +62,7 @@ class GTEST_API_ TestPartResult {
int a_line_number, int a_line_number,
const char* a_message) const char* a_message)
: type_(a_type), : type_(a_type),
file_name_(a_file_name), file_name_(a_file_name == NULL ? "" : a_file_name),
line_number_(a_line_number), line_number_(a_line_number),
summary_(ExtractSummary(a_message)), summary_(ExtractSummary(a_message)),
message_(a_message) { message_(a_message) {
@ -73,7 +73,9 @@ class GTEST_API_ TestPartResult {
// Gets the name of the source file where the test part took place, or // Gets the name of the source file where the test part took place, or
// NULL if it's unknown. // NULL if it's unknown.
const char* file_name() const { return file_name_.c_str(); } const char* file_name() const {
return file_name_.empty() ? NULL : file_name_.c_str();
}
// Gets the line in the source file where the test part took place, // Gets the line in the source file where the test part took place,
// or -1 if it's unknown. // or -1 if it's unknown.
@ -96,21 +98,22 @@ class GTEST_API_ TestPartResult {
// Returns true iff the test part fatally failed. // Returns true iff the test part fatally failed.
bool fatally_failed() const { return type_ == kFatalFailure; } bool fatally_failed() const { return type_ == kFatalFailure; }
private: private:
Type type_; Type type_;
// Gets the summary of the failure message by omitting the stack // Gets the summary of the failure message by omitting the stack
// trace in it. // trace in it.
static internal::String ExtractSummary(const char* message); static std::string ExtractSummary(const char* message);
// The name of the source file where the test part took place, or // The name of the source file where the test part took place, or
// NULL if the source file is unknown. // "" if the source file is unknown.
internal::String file_name_; std::string file_name_;
// The line in the source file where the test part took place, or -1 // The line in the source file where the test part took place, or -1
// if the line number is unknown. // if the line number is unknown.
int line_number_; int line_number_;
internal::String summary_; // The test failure summary. std::string summary_; // The test failure summary.
internal::String message_; // The test failure message. std::string message_; // The test failure message.
}; };
// Prints a TestPartResult object. // Prints a TestPartResult object.

View file

@ -52,6 +52,7 @@
#define GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_
#include <limits> #include <limits>
#include <ostream>
#include <vector> #include <vector>
#include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-internal.h"
@ -153,25 +154,15 @@ class ExecDeathTest;
class NoExecDeathTest; class NoExecDeathTest;
class FinalSuccessChecker; class FinalSuccessChecker;
class GTestFlagSaver; class GTestFlagSaver;
class StreamingListenerTest;
class TestResultAccessor; class TestResultAccessor;
class TestEventListenersAccessor; class TestEventListenersAccessor;
class TestEventRepeater; class TestEventRepeater;
class UnitTestRecordPropertyTestHelper;
class WindowsDeathTest; class WindowsDeathTest;
class UnitTestImpl* GetUnitTestImpl(); class UnitTestImpl* GetUnitTestImpl();
void ReportFailureInUnknownLocation(TestPartResult::Type result_type, void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
const String& message); const std::string& message);
// Converts a streamable value to a String. A NULL pointer is
// converted to "(null)". When the input value is a ::string,
// ::std::string, ::wstring, or ::std::wstring object, each NUL
// character in it is replaced with "\\0".
// Declared in gtest-internal.h but defined here, so that it has access
// to the definition of the Message class, required by the ARM
// compiler.
template <typename T>
String StreamableToString(const T& streamable) {
return (Message() << streamable).GetString();
}
} // namespace internal } // namespace internal
@ -391,20 +382,21 @@ class GTEST_API_ Test {
// non-fatal) failure. // non-fatal) failure.
static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
// Logs a property for the current test. Only the last value for a given // Logs a property for the current test, test case, or for the entire
// key is remembered. // invocation of the test program when used outside of the context of a
// These are public static so they can be called from utility functions // test case. Only the last value for a given key is remembered. These
// that are not members of the test fixture. // are public static so they can be called from utility functions that are
// The arguments are const char* instead strings, as Google Test is used // not members of the test fixture. Calls to RecordProperty made during
// on platforms where string doesn't compile. // lifespan of the test (from the moment its constructor starts to the
// // moment its destructor finishes) will be output in XML as attributes of
// Note that a driving consideration for these RecordProperty methods // the <testcase> element. Properties recorded from fixture's
// was to produce xml output suited to the Greenspan charting utility, // SetUpTestCase or TearDownTestCase are logged as attributes of the
// which at present will only chart values that fit in a 32-bit int. It // corresponding <testsuite> element. Calls to RecordProperty made in the
// is the user's responsibility to restrict their values to 32-bit ints // global context (before or after invocation of RUN_ALL_TESTS and from
// if they intend them to be used with Greenspan. // SetUp/TearDown method of Environment objects registered with Google
static void RecordProperty(const char* key, const char* value); // Test) will be output as attributes of the <testsuites> element.
static void RecordProperty(const char* key, int value); static void RecordProperty(const std::string& key, const std::string& value);
static void RecordProperty(const std::string& key, int value);
protected: protected:
// Creates a Test object. // Creates a Test object.
@ -473,7 +465,7 @@ class TestProperty {
// C'tor. TestProperty does NOT have a default constructor. // C'tor. TestProperty does NOT have a default constructor.
// Always use this constructor (with parameters) to create a // Always use this constructor (with parameters) to create a
// TestProperty object. // TestProperty object.
TestProperty(const char* a_key, const char* a_value) : TestProperty(const std::string& a_key, const std::string& a_value) :
key_(a_key), value_(a_value) { key_(a_key), value_(a_value) {
} }
@ -488,15 +480,15 @@ class TestProperty {
} }
// Sets a new value, overriding the one supplied in the constructor. // Sets a new value, overriding the one supplied in the constructor.
void SetValue(const char* new_value) { void SetValue(const std::string& new_value) {
value_ = new_value; value_ = new_value;
} }
private: private:
// The key supplied by the user. // The key supplied by the user.
internal::String key_; std::string key_;
// The value supplied by the user. // The value supplied by the user.
internal::String value_; std::string value_;
}; };
// The result of a single Test. This includes a list of // The result of a single Test. This includes a list of
@ -547,6 +539,7 @@ class GTEST_API_ TestResult {
private: private:
friend class TestInfo; friend class TestInfo;
friend class TestCase;
friend class UnitTest; friend class UnitTest;
friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::DefaultGlobalTestPartResultReporter;
friend class internal::ExecDeathTest; friend class internal::ExecDeathTest;
@ -571,13 +564,16 @@ class GTEST_API_ TestResult {
// a non-fatal failure if invalid (e.g., if it conflicts with reserved // a non-fatal failure if invalid (e.g., if it conflicts with reserved
// key names). If a property is already recorded for the same key, the // key names). If a property is already recorded for the same key, the
// value will be updated, rather than storing multiple values for the same // value will be updated, rather than storing multiple values for the same
// key. // key. xml_element specifies the element for which the property is being
void RecordProperty(const TestProperty& test_property); // recorded and is used for validation.
void RecordProperty(const std::string& xml_element,
const TestProperty& test_property);
// Adds a failure if the key is a reserved attribute of Google Test // Adds a failure if the key is a reserved attribute of Google Test
// testcase tags. Returns true if the property is valid. // testcase tags. Returns true if the property is valid.
// TODO(russr): Validate attribute names are legal and human readable. // TODO(russr): Validate attribute names are legal and human readable.
static bool ValidateTestProperty(const TestProperty& test_property); static bool ValidateTestProperty(const std::string& xml_element,
const TestProperty& test_property);
// Adds a test part result to the list. // Adds a test part result to the list.
void AddTestPartResult(const TestPartResult& test_part_result); void AddTestPartResult(const TestPartResult& test_part_result);
@ -650,9 +646,9 @@ class GTEST_API_ TestInfo {
return NULL; return NULL;
} }
// Returns true if this test should run, that is if the test is not disabled // Returns true if this test should run, that is if the test is not
// (or it is disabled but the also_run_disabled_tests flag has been specified) // disabled (or it is disabled but the also_run_disabled_tests flag has
// and its full name matches the user-specified filter. // been specified) and its full name matches the user-specified filter.
// //
// Google Test allows the user to filter the tests by their full names. // Google Test allows the user to filter the tests by their full names.
// The full name of a test Bar in test case Foo is defined as // The full name of a test Bar in test case Foo is defined as
@ -668,19 +664,28 @@ class GTEST_API_ TestInfo {
// contains the character 'A' or starts with "Foo.". // contains the character 'A' or starts with "Foo.".
bool should_run() const { return should_run_; } bool should_run() const { return should_run_; }
// Returns true iff this test will appear in the XML report.
bool is_reportable() const {
// For now, the XML report includes all tests matching the filter.
// In the future, we may trim tests that are excluded because of
// sharding.
return matches_filter_;
}
// Returns the result of the test. // Returns the result of the test.
const TestResult* result() const { return &result_; } const TestResult* result() const { return &result_; }
private: private:
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
friend class internal::DefaultDeathTestFactory; friend class internal::DefaultDeathTestFactory;
#endif // GTEST_HAS_DEATH_TEST #endif // GTEST_HAS_DEATH_TEST
friend class Test; friend class Test;
friend class TestCase; friend class TestCase;
friend class internal::UnitTestImpl; friend class internal::UnitTestImpl;
friend class internal::StreamingListenerTest;
friend TestInfo* internal::MakeAndRegisterTestInfo( friend TestInfo* internal::MakeAndRegisterTestInfo(
const char* test_case_name, const char* name, const char* test_case_name,
const char* name,
const char* type_param, const char* type_param,
const char* value_param, const char* value_param,
internal::TypeId fixture_class_id, internal::TypeId fixture_class_id,
@ -690,9 +695,10 @@ class GTEST_API_ TestInfo {
// Constructs a TestInfo object. The newly constructed instance assumes // Constructs a TestInfo object. The newly constructed instance assumes
// ownership of the factory object. // ownership of the factory object.
TestInfo(const char* test_case_name, const char* name, TestInfo(const std::string& test_case_name,
const char* a_type_param, const std::string& name,
const char* a_value_param, const char* a_type_param, // NULL if not a type-parameterized test
const char* a_value_param, // NULL if not a value-parameterized test
internal::TypeId fixture_class_id, internal::TypeId fixture_class_id,
internal::TestFactoryBase* factory); internal::TestFactoryBase* factory);
@ -778,9 +784,15 @@ class GTEST_API_ TestCase {
// Gets the number of failed tests in this test case. // Gets the number of failed tests in this test case.
int failed_test_count() const; int failed_test_count() const;
// Gets the number of disabled tests that will be reported in the XML report.
int reportable_disabled_test_count() const;
// Gets the number of disabled tests in this test case. // Gets the number of disabled tests in this test case.
int disabled_test_count() const; int disabled_test_count() const;
// Gets the number of tests to be printed in the XML report.
int reportable_test_count() const;
// Get the number of tests in this test case that should run. // Get the number of tests in this test case that should run.
int test_to_run_count() const; int test_to_run_count() const;
@ -800,6 +812,10 @@ class GTEST_API_ TestCase {
// total_test_count() - 1. If i is not in that range, returns NULL. // total_test_count() - 1. If i is not in that range, returns NULL.
const TestInfo* GetTestInfo(int i) const; const TestInfo* GetTestInfo(int i) const;
// Returns the TestResult that holds test properties recorded during
// execution of SetUpTestCase and TearDownTestCase.
const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
private: private:
friend class Test; friend class Test;
friend class internal::UnitTestImpl; friend class internal::UnitTestImpl;
@ -852,11 +868,22 @@ class GTEST_API_ TestCase {
return test_info->should_run() && test_info->result()->Failed(); return test_info->should_run() && test_info->result()->Failed();
} }
// Returns true iff the test is disabled and will be reported in the XML
// report.
static bool TestReportableDisabled(const TestInfo* test_info) {
return test_info->is_reportable() && test_info->is_disabled_;
}
// Returns true iff test is disabled. // Returns true iff test is disabled.
static bool TestDisabled(const TestInfo* test_info) { static bool TestDisabled(const TestInfo* test_info) {
return test_info->is_disabled_; return test_info->is_disabled_;
} }
// Returns true iff this test will appear in the XML report.
static bool TestReportable(const TestInfo* test_info) {
return test_info->is_reportable();
}
// Returns true if the given test should run. // Returns true if the given test should run.
static bool ShouldRunTest(const TestInfo* test_info) { static bool ShouldRunTest(const TestInfo* test_info) {
return test_info->should_run(); return test_info->should_run();
@ -869,7 +896,7 @@ class GTEST_API_ TestCase {
void UnshuffleTests(); void UnshuffleTests();
// Name of the test case. // Name of the test case.
internal::String name_; std::string name_;
// Name of the parameter type, or NULL if this is not a typed or a // Name of the parameter type, or NULL if this is not a typed or a
// type-parameterized test. // type-parameterized test.
const internal::scoped_ptr<const ::std::string> type_param_; const internal::scoped_ptr<const ::std::string> type_param_;
@ -888,6 +915,9 @@ class GTEST_API_ TestCase {
bool should_run_; bool should_run_;
// Elapsed time, in milliseconds. // Elapsed time, in milliseconds.
TimeInMillis elapsed_time_; TimeInMillis elapsed_time_;
// Holds test properties recorded during execution of SetUpTestCase and
// TearDownTestCase.
TestResult ad_hoc_test_result_;
// We disallow copying TestCases. // We disallow copying TestCases.
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
@ -1107,11 +1137,13 @@ class GTEST_API_ UnitTest {
// Returns the TestCase object for the test that's currently running, // Returns the TestCase object for the test that's currently running,
// or NULL if no test is running. // or NULL if no test is running.
const TestCase* current_test_case() const; const TestCase* current_test_case() const
GTEST_LOCK_EXCLUDED_(mutex_);
// Returns the TestInfo object for the test that's currently running, // Returns the TestInfo object for the test that's currently running,
// or NULL if no test is running. // or NULL if no test is running.
const TestInfo* current_test_info() const; const TestInfo* current_test_info() const
GTEST_LOCK_EXCLUDED_(mutex_);
// Returns the random seed used at the start of the current test run. // Returns the random seed used at the start of the current test run.
int random_seed() const; int random_seed() const;
@ -1121,7 +1153,8 @@ class GTEST_API_ UnitTest {
// value-parameterized tests and instantiate and register them. // value-parameterized tests and instantiate and register them.
// //
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
GTEST_LOCK_EXCLUDED_(mutex_);
#endif // GTEST_HAS_PARAM_TEST #endif // GTEST_HAS_PARAM_TEST
// Gets the number of successful test cases. // Gets the number of successful test cases.
@ -1143,15 +1176,25 @@ class GTEST_API_ UnitTest {
// Gets the number of failed tests. // Gets the number of failed tests.
int failed_test_count() const; int failed_test_count() const;
// Gets the number of disabled tests that will be reported in the XML report.
int reportable_disabled_test_count() const;
// Gets the number of disabled tests. // Gets the number of disabled tests.
int disabled_test_count() const; int disabled_test_count() const;
// Gets the number of tests to be printed in the XML report.
int reportable_test_count() const;
// Gets the number of all tests. // Gets the number of all tests.
int total_test_count() const; int total_test_count() const;
// Gets the number of tests that should run. // Gets the number of tests that should run.
int test_to_run_count() const; int test_to_run_count() const;
// Gets the time of the test program start, in ms from the start of the
// UNIX epoch.
TimeInMillis start_timestamp() const;
// Gets the elapsed time, in milliseconds. // Gets the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const; TimeInMillis elapsed_time() const;
@ -1166,6 +1209,10 @@ class GTEST_API_ UnitTest {
// total_test_case_count() - 1. If i is not in that range, returns NULL. // total_test_case_count() - 1. If i is not in that range, returns NULL.
const TestCase* GetTestCase(int i) const; const TestCase* GetTestCase(int i) const;
// Returns the TestResult containing information on test failures and
// properties logged outside of individual test cases.
const TestResult& ad_hoc_test_result() const;
// Returns the list of event listeners that can be used to track events // Returns the list of event listeners that can be used to track events
// inside Google Test. // inside Google Test.
TestEventListeners& listeners(); TestEventListeners& listeners();
@ -1189,12 +1236,16 @@ class GTEST_API_ UnitTest {
void AddTestPartResult(TestPartResult::Type result_type, void AddTestPartResult(TestPartResult::Type result_type,
const char* file_name, const char* file_name,
int line_number, int line_number,
const internal::String& message, const std::string& message,
const internal::String& os_stack_trace); const std::string& os_stack_trace)
GTEST_LOCK_EXCLUDED_(mutex_);
// Adds a TestProperty to the current TestResult object. If the result already // Adds a TestProperty to the current TestResult object when invoked from
// contains a property with the same key, the value will be updated. // inside a test, to current TestCase's ad_hoc_test_result_ when invoked
void RecordPropertyForCurrentTest(const char* key, const char* value); // from SetUpTestCase or TearDownTestCase, or to the global property set
// when invoked elsewhere. If the result already contains a property with
// the same key, the value will be updated.
void RecordProperty(const std::string& key, const std::string& value);
// Gets the i-th test case among all the test cases. i can range from 0 to // Gets the i-th test case among all the test cases. i can range from 0 to
// total_test_case_count() - 1. If i is not in that range, returns NULL. // total_test_case_count() - 1. If i is not in that range, returns NULL.
@ -1209,11 +1260,13 @@ class GTEST_API_ UnitTest {
friend class Test; friend class Test;
friend class internal::AssertHelper; friend class internal::AssertHelper;
friend class internal::ScopedTrace; friend class internal::ScopedTrace;
friend class internal::StreamingListenerTest;
friend class internal::UnitTestRecordPropertyTestHelper;
friend Environment* AddGlobalTestEnvironment(Environment* env); friend Environment* AddGlobalTestEnvironment(Environment* env);
friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend internal::UnitTestImpl* internal::GetUnitTestImpl();
friend void internal::ReportFailureInUnknownLocation( friend void internal::ReportFailureInUnknownLocation(
TestPartResult::Type result_type, TestPartResult::Type result_type,
const internal::String& message); const std::string& message);
// Creates an empty UnitTest. // Creates an empty UnitTest.
UnitTest(); UnitTest();
@ -1223,10 +1276,12 @@ class GTEST_API_ UnitTest {
// Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
// Google Test trace stack. // Google Test trace stack.
void PushGTestTrace(const internal::TraceInfo& trace); void PushGTestTrace(const internal::TraceInfo& trace)
GTEST_LOCK_EXCLUDED_(mutex_);
// Pops a trace from the per-thread Google Test trace stack. // Pops a trace from the per-thread Google Test trace stack.
void PopGTestTrace(); void PopGTestTrace()
GTEST_LOCK_EXCLUDED_(mutex_);
// Protects mutable state in *impl_. This is mutable as some const // Protects mutable state in *impl_. This is mutable as some const
// methods need to lock it too. // methods need to lock it too.
@ -1281,24 +1336,101 @@ GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
namespace internal { namespace internal {
// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
// value of type ToPrint that is an operand of a comparison assertion
// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
// the comparison, and is used to help determine the best way to
// format the value. In particular, when the value is a C string
// (char pointer) and the other operand is an STL string object, we
// want to format the C string as a string, since we know it is
// compared by value with the string object. If the value is a char
// pointer but the other operand is not an STL string object, we don't
// know whether the pointer is supposed to point to a NUL-terminated
// string, and thus want to print it as a pointer to be safe.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
// The default case.
template <typename ToPrint, typename OtherOperand>
class FormatForComparison {
public:
static ::std::string Format(const ToPrint& value) {
return ::testing::PrintToString(value);
}
};
// Array.
template <typename ToPrint, size_t N, typename OtherOperand>
class FormatForComparison<ToPrint[N], OtherOperand> {
public:
static ::std::string Format(const ToPrint* value) {
return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
}
};
// By default, print C string as pointers to be safe, as we don't know
// whether they actually point to a NUL-terminated string.
#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
template <typename OtherOperand> \
class FormatForComparison<CharType*, OtherOperand> { \
public: \
static ::std::string Format(CharType* value) { \
return ::testing::PrintToString(static_cast<const void*>(value)); \
} \
}
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
// If a C string is compared with an STL string object, we know it's meant
// to point to a NUL-terminated string, and thus can print it as a string.
#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
template <> \
class FormatForComparison<CharType*, OtherStringType> { \
public: \
static ::std::string Format(CharType* value) { \
return ::testing::PrintToString(value); \
} \
}
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
#if GTEST_HAS_GLOBAL_STRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
#endif
#if GTEST_HAS_GLOBAL_WSTRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
#endif
#if GTEST_HAS_STD_WSTRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
#endif
#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
// operand to be used in a failure message. The type (but not value) // operand to be used in a failure message. The type (but not value)
// of the other operand may affect the format. This allows us to // of the other operand may affect the format. This allows us to
// print a char* as a raw pointer when it is compared against another // print a char* as a raw pointer when it is compared against another
// char*, and print it as a C string when it is compared against an // char* or void*, and print it as a C string when it is compared
// std::string object, for example. // against an std::string object, for example.
//
// The default implementation ignores the type of the other operand.
// Some specialized versions are used to handle formatting wide or
// narrow C strings.
// //
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
template <typename T1, typename T2> template <typename T1, typename T2>
String FormatForComparisonFailureMessage(const T1& value, std::string FormatForComparisonFailureMessage(
const T2& /* other_operand */) { const T1& value, const T2& /* other_operand */) {
// C++Builder compiles this incorrectly if the namespace isn't explicitly return FormatForComparison<T1, T2>::Format(value);
// given.
return ::testing::PrintToString(value);
} }
// The helper function for {ASSERT|EXPECT}_EQ. // The helper function for {ASSERT|EXPECT}_EQ.
@ -1310,7 +1442,7 @@ AssertionResult CmpHelperEQ(const char* expected_expression,
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(push) // Saves the current warning state. # pragma warning(push) // Saves the current warning state.
# pragma warning(disable:4389) // Temporarily disables warning on # pragma warning(disable:4389) // Temporarily disables warning on
// signed/unsigned mismatch. // signed/unsigned mismatch.
#endif #endif
if (expected == actual) { if (expected == actual) {
@ -1446,11 +1578,11 @@ GTEST_IMPL_CMP_HELPER_(NE, !=);
// Implements the helper function for {ASSERT|EXPECT}_LE // Implements the helper function for {ASSERT|EXPECT}_LE
GTEST_IMPL_CMP_HELPER_(LE, <=); GTEST_IMPL_CMP_HELPER_(LE, <=);
// Implements the helper function for {ASSERT|EXPECT}_LT // Implements the helper function for {ASSERT|EXPECT}_LT
GTEST_IMPL_CMP_HELPER_(LT, < ); GTEST_IMPL_CMP_HELPER_(LT, <);
// Implements the helper function for {ASSERT|EXPECT}_GE // Implements the helper function for {ASSERT|EXPECT}_GE
GTEST_IMPL_CMP_HELPER_(GE, >=); GTEST_IMPL_CMP_HELPER_(GE, >=);
// Implements the helper function for {ASSERT|EXPECT}_GT // Implements the helper function for {ASSERT|EXPECT}_GT
GTEST_IMPL_CMP_HELPER_(GT, > ); GTEST_IMPL_CMP_HELPER_(GT, >);
#undef GTEST_IMPL_CMP_HELPER_ #undef GTEST_IMPL_CMP_HELPER_
@ -1614,9 +1746,9 @@ class GTEST_API_ AssertHelper {
: type(t), file(srcfile), line(line_num), message(msg) { } : type(t), file(srcfile), line(line_num), message(msg) { }
TestPartResult::Type const type; TestPartResult::Type const type;
const char* const file; const char* const file;
int const line; int const line;
String const message; std::string const message;
private: private:
GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
@ -1675,7 +1807,12 @@ class WithParamInterface {
// references static data, to reduce the opportunity for incorrect uses // references static data, to reduce the opportunity for incorrect uses
// like writing 'WithParamInterface<bool>::GetParam()' for a test that // like writing 'WithParamInterface<bool>::GetParam()' for a test that
// uses a fixture whose parameter type is int. // uses a fixture whose parameter type is int.
const ParamType& GetParam() const { return *parameter_; } const ParamType& GetParam() const {
GTEST_CHECK_(parameter_ != NULL)
<< "GetParam() can only be called inside a value-parameterized test "
<< "-- did you intend to write TEST_P instead of TEST_F?";
return *parameter_;
}
private: private:
// Sets parameter value. The caller is responsible for making sure the value // Sets parameter value. The caller is responsible for making sure the value
@ -1721,12 +1858,6 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// usually want the fail-fast behavior of FAIL and ASSERT_*, but those // usually want the fail-fast behavior of FAIL and ASSERT_*, but those
// writing data-driven tests often find themselves using ADD_FAILURE // writing data-driven tests often find themselves using ADD_FAILURE
// and EXPECT_* more. // and EXPECT_* more.
//
// Examples:
//
// EXPECT_TRUE(server.StatusIsOK());
// ASSERT_FALSE(server.HasPendingRequest(port))
// << "There are still pending requests " << "on port " << port;
// Generates a nonfatal failure with a generic message. // Generates a nonfatal failure with a generic message.
#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
@ -1900,7 +2031,7 @@ class TestWithParam : public Test, public WithParamInterface<T> {
# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
#endif #endif
// C String Comparisons. All tests treat NULL and any non-NULL string // C-string Comparisons. All tests treat NULL and any non-NULL string
// as different. Two NULLs are equal. // as different. Two NULLs are equal.
// //
// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
@ -2141,15 +2272,20 @@ bool StaticAssertTypeEq() {
GTEST_TEST_(test_fixture, test_name, test_fixture, \ GTEST_TEST_(test_fixture, test_name, test_fixture, \
::testing::internal::GetTypeId<test_fixture>()) ::testing::internal::GetTypeId<test_fixture>())
// Use this macro in main() to run all tests. It returns 0 if all } // namespace testing
// Use this function in main() to run all tests. It returns 0 if all
// tests are successful, or 1 otherwise. // tests are successful, or 1 otherwise.
// //
// RUN_ALL_TESTS() should be invoked after the command line has been // RUN_ALL_TESTS() should be invoked after the command line has been
// parsed by InitGoogleTest(). // parsed by InitGoogleTest().
//
// This function was formerly a macro; thus, it is in the global
// namespace and has an all-caps name.
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
#define RUN_ALL_TESTS()\ inline int RUN_ALL_TESTS() {
(::testing::UnitTest::GetInstance()->Run()) return ::testing::UnitTest::GetInstance()->Run();
}
} // namespace testing
#endif // GTEST_INCLUDE_GTEST_GTEST_H_ #endif // GTEST_INCLUDE_GTEST_GTEST_H_

View file

@ -27,7 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command // This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
// //
// Implements a family of generic predicate assertion macros. // Implements a family of generic predicate assertion macros.
@ -98,7 +98,7 @@ AssertionResult AssertPred1Helper(const char* pred_text,
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
// Don't use this in your code. // Don't use this in your code.
#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
GTEST_ASSERT_(pred_format(#v1, v1),\ GTEST_ASSERT_(pred_format(#v1, v1), \
on_failure) on_failure)
// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
@ -144,7 +144,7 @@ AssertionResult AssertPred2Helper(const char* pred_text,
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
// Don't use this in your code. // Don't use this in your code.
#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
on_failure) on_failure)
// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
@ -197,7 +197,7 @@ AssertionResult AssertPred3Helper(const char* pred_text,
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
// Don't use this in your code. // Don't use this in your code.
#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
on_failure) on_failure)
// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
@ -257,7 +257,7 @@ AssertionResult AssertPred4Helper(const char* pred_text,
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
// Don't use this in your code. // Don't use this in your code.
#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
on_failure) on_failure)
// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
@ -324,7 +324,7 @@ AssertionResult AssertPred5Helper(const char* pred_text,
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
// Don't use this in your code. // Don't use this in your code.
#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
on_failure) on_failure)
// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use

View file

@ -127,11 +127,11 @@ class GTEST_API_ DeathTest {
// the last death test. // the last death test.
static const char* LastMessage(); static const char* LastMessage();
static void set_last_death_test_message(const String& message); static void set_last_death_test_message(const std::string& message);
private: private:
// A string containing a description of the outcome of the last death test. // A string containing a description of the outcome of the last death test.
static String last_death_test_message_; static std::string last_death_test_message_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
}; };
@ -217,12 +217,23 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
// The symbol "fail" here expands to something into which a message // The symbol "fail" here expands to something into which a message
// can be streamed. // can be streamed.
// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
// NDEBUG mode. In this case we need the statements to be executed, the regex is
// ignored, and the macro must accept a streamed message even though the message
// is never printed.
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::internal::AlwaysTrue()) { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} else \
::testing::Message()
// A class representing the parsed contents of the // A class representing the parsed contents of the
// --gtest_internal_run_death_test flag, as it existed when // --gtest_internal_run_death_test flag, as it existed when
// RUN_ALL_TESTS was called. // RUN_ALL_TESTS was called.
class InternalRunDeathTestFlag { class InternalRunDeathTestFlag {
public: public:
InternalRunDeathTestFlag(const String& a_file, InternalRunDeathTestFlag(const std::string& a_file,
int a_line, int a_line,
int an_index, int an_index,
int a_write_fd) int a_write_fd)
@ -234,13 +245,13 @@ class InternalRunDeathTestFlag {
posix::Close(write_fd_); posix::Close(write_fd_);
} }
String file() const { return file_; } const std::string& file() const { return file_; }
int line() const { return line_; } int line() const { return line_; }
int index() const { return index_; } int index() const { return index_; }
int write_fd() const { return write_fd_; } int write_fd() const { return write_fd_; }
private: private:
String file_; std::string file_;
int line_; int line_;
int index_; int index_;
int write_fd_; int write_fd_;

View file

@ -61,11 +61,7 @@ class GTEST_API_ FilePath {
FilePath() : pathname_("") { } FilePath() : pathname_("") { }
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
explicit FilePath(const char* pathname) : pathname_(pathname) { explicit FilePath(const std::string& pathname) : pathname_(pathname) {
Normalize();
}
explicit FilePath(const String& pathname) : pathname_(pathname) {
Normalize(); Normalize();
} }
@ -78,7 +74,7 @@ class GTEST_API_ FilePath {
pathname_ = rhs.pathname_; pathname_ = rhs.pathname_;
} }
String ToString() const { return pathname_; } const std::string& string() const { return pathname_; }
const char* c_str() const { return pathname_.c_str(); } const char* c_str() const { return pathname_.c_str(); }
// Returns the current working directory, or "" if unsuccessful. // Returns the current working directory, or "" if unsuccessful.
@ -111,8 +107,8 @@ class GTEST_API_ FilePath {
const FilePath& base_name, const FilePath& base_name,
const char* extension); const char* extension);
// Returns true iff the path is NULL or "". // Returns true iff the path is "".
bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } bool IsEmpty() const { return pathname_.empty(); }
// If input name has a trailing separator character, removes it and returns // If input name has a trailing separator character, removes it and returns
// the name, otherwise return the name string unmodified. // the name, otherwise return the name string unmodified.
@ -201,7 +197,7 @@ class GTEST_API_ FilePath {
// separators. Returns NULL if no path separator was found. // separators. Returns NULL if no path separator was found.
const char* FindLastPathSeparator() const; const char* FindLastPathSeparator() const;
String pathname_; std::string pathname_;
}; // class FilePath }; // class FilePath
} // namespace internal } // namespace internal

View file

@ -46,12 +46,18 @@
# include <unistd.h> # include <unistd.h>
#endif // GTEST_OS_LINUX #endif // GTEST_OS_LINUX
#if GTEST_HAS_EXCEPTIONS
# include <stdexcept>
#endif
#include <ctype.h> #include <ctype.h>
#include <float.h>
#include <string.h> #include <string.h>
#include <iomanip> #include <iomanip>
#include <limits> #include <limits>
#include <set> #include <set>
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-string.h"
#include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-filepath.h"
#include "gtest/internal/gtest-type-util.h" #include "gtest/internal/gtest-type-util.h"
@ -67,36 +73,6 @@
#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
// Google Test defines the testing::Message class to allow construction of
// test messages via the << operator. The idea is that anything
// streamable to std::ostream can be streamed to a testing::Message.
// This allows a user to use his own types in Google Test assertions by
// overloading the << operator.
//
// util/gtl/stl_logging-inl.h overloads << for STL containers. These
// overloads cannot be defined in the std namespace, as that will be
// undefined behavior. Therefore, they are defined in the global
// namespace instead.
//
// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
// overloads are visible in either the std namespace or the global
// namespace, but not other namespaces, including the testing
// namespace which Google Test's Message class is in.
//
// To allow STL containers (and other types that has a << operator
// defined in the global namespace) to be used in Google Test assertions,
// testing::Message must access the custom << operator from the global
// namespace. Hence this helper function.
//
// Note: Jeffrey Yasskin suggested an alternative fix by "using
// ::operator<<;" in the definition of Message's operator<<. That fix
// doesn't require a helper function, but unfortunately doesn't
// compile with MSVC.
template <typename T>
inline void GTestStreamToHelper(std::ostream* os, const T& val) {
*os << val;
}
class ProtocolMessage; class ProtocolMessage;
namespace proto2 { class Message; } namespace proto2 { class Message; }
@ -122,17 +98,12 @@ class TestInfoImpl; // Opaque implementation of TestInfo
class UnitTestImpl; // Opaque implementation of UnitTest class UnitTestImpl; // Opaque implementation of UnitTest
// How many times InitGoogleTest() has been called. // How many times InitGoogleTest() has been called.
extern int g_init_gtest_count; GTEST_API_ extern int g_init_gtest_count;
// The text used in failure messages to indicate the start of the // The text used in failure messages to indicate the start of the
// stack trace. // stack trace.
GTEST_API_ extern const char kStackTraceMarker[]; GTEST_API_ extern const char kStackTraceMarker[];
// A secret type that Google Test users don't know about. It has no
// definition on purpose. Therefore it's impossible to create a
// Secret object, which is what we want.
class Secret;
// Two overloaded helpers for checking at compile time whether an // Two overloaded helpers for checking at compile time whether an
// expression is a null pointer literal (i.e. NULL or any 0-valued // expression is a null pointer literal (i.e. NULL or any 0-valued
// compile-time integral constant). Their return values have // compile-time integral constant). Their return values have
@ -163,8 +134,23 @@ char (&IsNullLiteralHelper(...))[2]; // NOLINT
#endif // GTEST_ELLIPSIS_NEEDS_POD_ #endif // GTEST_ELLIPSIS_NEEDS_POD_
// Appends the user-supplied message to the Google-Test-generated message. // Appends the user-supplied message to the Google-Test-generated message.
GTEST_API_ String AppendUserMessage(const String& gtest_msg, GTEST_API_ std::string AppendUserMessage(
const Message& user_msg); const std::string& gtest_msg, const Message& user_msg);
#if GTEST_HAS_EXCEPTIONS
// This exception is thrown by (and only by) a failed Google Test
// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
// are enabled). We derive it from std::runtime_error, which is for
// errors presumably detectable only at run time. Since
// std::runtime_error inherits from std::exception, many testing
// frameworks know how to extract and print the message inside it.
class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
public:
explicit GoogleTestFailureException(const TestPartResult& failure);
};
#endif // GTEST_HAS_EXCEPTIONS
// A helper class for creating scoped traces in user programs. // A helper class for creating scoped traces in user programs.
class GTEST_API_ ScopedTrace { class GTEST_API_ ScopedTrace {
@ -185,77 +171,6 @@ class GTEST_API_ ScopedTrace {
// c'tor and d'tor. Therefore it doesn't // c'tor and d'tor. Therefore it doesn't
// need to be used otherwise. // need to be used otherwise.
// Converts a streamable value to a String. A NULL pointer is
// converted to "(null)". When the input value is a ::string,
// ::std::string, ::wstring, or ::std::wstring object, each NUL
// character in it is replaced with "\\0".
// Declared here but defined in gtest.h, so that it has access
// to the definition of the Message class, required by the ARM
// compiler.
template <typename T>
String StreamableToString(const T& streamable);
// The Symbian compiler has a bug that prevents it from selecting the
// correct overload of FormatForComparisonFailureMessage (see below)
// unless we pass the first argument by reference. If we do that,
// however, Visual Age C++ 10.1 generates a compiler error. Therefore
// we only apply the work-around for Symbian.
#if defined(__SYMBIAN32__)
# define GTEST_CREF_WORKAROUND_ const&
#else
# define GTEST_CREF_WORKAROUND_
#endif
// When this operand is a const char* or char*, if the other operand
// is a ::std::string or ::string, we print this operand as a C string
// rather than a pointer (we do the same for wide strings); otherwise
// we print it as a pointer to be safe.
// This internal macro is used to avoid duplicated code.
#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
inline String FormatForComparisonFailureMessage(\
operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
const operand2_type& /*operand2*/) {\
return operand1_printer(str);\
}\
inline String FormatForComparisonFailureMessage(\
const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
const operand2_type& /*operand2*/) {\
return operand1_printer(str);\
}
GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
#if GTEST_HAS_STD_WSTRING
GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
#endif // GTEST_HAS_STD_WSTRING
#if GTEST_HAS_GLOBAL_STRING
GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
#endif // GTEST_HAS_GLOBAL_STRING
#if GTEST_HAS_GLOBAL_WSTRING
GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
#endif // GTEST_HAS_GLOBAL_WSTRING
#undef GTEST_FORMAT_IMPL_
// The next four overloads handle the case where the operand being
// printed is a char/wchar_t pointer and the other operand is not a
// string/wstring object. In such cases, we just print the operand as
// a pointer to be safe.
#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \
template <typename T> \
String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \
const T&) { \
return PrintToString(static_cast<const void*>(p)); \
}
GTEST_FORMAT_CHAR_PTR_IMPL_(char)
GTEST_FORMAT_CHAR_PTR_IMPL_(const char)
GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t)
GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t)
#undef GTEST_FORMAT_CHAR_PTR_IMPL_
// Constructs and returns the message for an equality assertion // Constructs and returns the message for an equality assertion
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
// //
@ -273,12 +188,12 @@ GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t)
// be inserted into the message. // be inserted into the message.
GTEST_API_ AssertionResult EqFailure(const char* expected_expression, GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
const char* actual_expression, const char* actual_expression,
const String& expected_value, const std::string& expected_value,
const String& actual_value, const std::string& actual_value,
bool ignoring_case); bool ignoring_case);
// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. // Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
GTEST_API_ String GetBoolAssertionFailureMessage( GTEST_API_ std::string GetBoolAssertionFailureMessage(
const AssertionResult& assertion_result, const AssertionResult& assertion_result,
const char* expression_text, const char* expression_text,
const char* actual_predicate_value, const char* actual_predicate_value,
@ -353,7 +268,7 @@ class FloatingPoint {
// bits. Therefore, 4 should be enough for ordinary use. // bits. Therefore, 4 should be enough for ordinary use.
// //
// See the following article for more details on ULP: // See the following article for more details on ULP:
// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
static const size_t kMaxUlps = 4; static const size_t kMaxUlps = 4;
// Constructs a FloatingPoint from a raw floating-point number. // Constructs a FloatingPoint from a raw floating-point number.
@ -380,6 +295,9 @@ class FloatingPoint {
return ReinterpretBits(kExponentBitMask); return ReinterpretBits(kExponentBitMask);
} }
// Returns the maximum representable finite floating-point number.
static RawType Max();
// Non-static methods // Non-static methods
// Returns the bits that represents this number. // Returns the bits that represents this number.
@ -460,6 +378,13 @@ class FloatingPoint {
FloatingPointUnion u_; FloatingPointUnion u_;
}; };
// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
// macro defined by <windows.h>.
template <>
inline float FloatingPoint<float>::Max() { return FLT_MAX; }
template <>
inline double FloatingPoint<double>::Max() { return DBL_MAX; }
// Typedefs the instances of the FloatingPoint template class that we // Typedefs the instances of the FloatingPoint template class that we
// care to use. // care to use.
typedef FloatingPoint<float> Float; typedef FloatingPoint<float> Float;
@ -554,7 +479,7 @@ typedef void (*TearDownTestCaseFunc)();
// test_case_name: name of the test case // test_case_name: name of the test case
// name: name of the test // name: name of the test
// type_param the name of the test's type parameter, or NULL if // type_param the name of the test's type parameter, or NULL if
// this is not a typed or a type-parameterized test. // this is not a typed or a type-parameterized test.
// value_param text representation of the test's value parameter, // value_param text representation of the test's value parameter,
// or NULL if this is not a type-parameterized test. // or NULL if this is not a type-parameterized test.
// fixture_class_id: ID of the test fixture class // fixture_class_id: ID of the test fixture class
@ -564,7 +489,8 @@ typedef void (*TearDownTestCaseFunc)();
// The newly created TestInfo instance will assume // The newly created TestInfo instance will assume
// ownership of the factory object. // ownership of the factory object.
GTEST_API_ TestInfo* MakeAndRegisterTestInfo( GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
const char* test_case_name, const char* name, const char* test_case_name,
const char* name,
const char* type_param, const char* type_param,
const char* value_param, const char* value_param,
TypeId fixture_class_id, TypeId fixture_class_id,
@ -624,9 +550,9 @@ inline const char* SkipComma(const char* str) {
// Returns the prefix of 'str' before the first comma in it; returns // Returns the prefix of 'str' before the first comma in it; returns
// the entire string if it contains no comma. // the entire string if it contains no comma.
inline String GetPrefixUntilComma(const char* str) { inline std::string GetPrefixUntilComma(const char* str) {
const char* comma = strchr(str, ','); const char* comma = strchr(str, ',');
return comma == NULL ? String(str) : String(str, comma - str); return comma == NULL ? str : std::string(str, comma);
} }
// TypeParameterizedTest<Fixture, TestSel, Types>::Register() // TypeParameterizedTest<Fixture, TestSel, Types>::Register()
@ -652,8 +578,8 @@ class TypeParameterizedTest {
// First, registers the first type-parameterized test in the type // First, registers the first type-parameterized test in the type
// list. // list.
MakeAndRegisterTestInfo( MakeAndRegisterTestInfo(
String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
case_name, index).c_str(), + StreamableToString(index)).c_str(),
GetPrefixUntilComma(test_names).c_str(), GetPrefixUntilComma(test_names).c_str(),
GetTypeName<Type>().c_str(), GetTypeName<Type>().c_str(),
NULL, // No value parameter. NULL, // No value parameter.
@ -711,7 +637,7 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
// Returns the current OS stack trace as a String. // Returns the current OS stack trace as an std::string.
// //
// The maximum number of stack frames to be included is specified by // The maximum number of stack frames to be included is specified by
// the gtest_stack_trace_depth flag. The skip_count parameter // the gtest_stack_trace_depth flag. The skip_count parameter
@ -721,8 +647,8 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
// For example, if Foo() calls Bar(), which in turn calls // For example, if Foo() calls Bar(), which in turn calls
// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
int skip_count); UnitTest* unit_test, int skip_count);
// Helpers for suppressing warnings on unreachable code or constant // Helpers for suppressing warnings on unreachable code or constant
// condition. // condition.
@ -797,13 +723,19 @@ struct RemoveConst<const T> { typedef T type; }; // NOLINT
// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above // MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
// definition to fail to remove the const in 'const int[3]' and 'const // definition to fail to remove the const in 'const int[3]' and 'const
// char[3][4]'. The following specialization works around the bug. // char[3][4]'. The following specialization works around the bug.
// However, it causes trouble with GCC and thus needs to be
// conditionally compiled.
#if defined(_MSC_VER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
template <typename T, size_t N> template <typename T, size_t N>
struct RemoveConst<const T[N]> { struct RemoveConst<const T[N]> {
typedef typename RemoveConst<T>::type type[N]; typedef typename RemoveConst<T>::type type[N];
}; };
#if defined(_MSC_VER) && _MSC_VER < 1400
// This is the only specialization that allows VC++ 7.1 to remove const in
// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC
// and thus needs to be conditionally compiled.
template <typename T, size_t N>
struct RemoveConst<T[N]> {
typedef typename RemoveConst<T>::type type[N];
};
#endif #endif
// A handy wrapper around RemoveConst that works when the argument // A handy wrapper around RemoveConst that works when the argument

View file

@ -105,8 +105,8 @@ class linked_ptr_internal {
// framework. // framework.
// Join an existing circle. // Join an existing circle.
// L < g_linked_ptr_mutex void join(linked_ptr_internal const* ptr)
void join(linked_ptr_internal const* ptr) { GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
MutexLock lock(&g_linked_ptr_mutex); MutexLock lock(&g_linked_ptr_mutex);
linked_ptr_internal const* p = ptr; linked_ptr_internal const* p = ptr;
@ -117,8 +117,8 @@ class linked_ptr_internal {
// Leave whatever circle we're part of. Returns true if we were the // Leave whatever circle we're part of. Returns true if we were the
// last member of the circle. Once this is done, you can join() another. // last member of the circle. Once this is done, you can join() another.
// L < g_linked_ptr_mutex bool depart()
bool depart() { GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
MutexLock lock(&g_linked_ptr_mutex); MutexLock lock(&g_linked_ptr_mutex);
if (next_ == this) return true; if (next_ == this) return true;

View file

@ -95,7 +95,7 @@ class ValueArray2 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -114,7 +114,8 @@ class ValueArray3 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -135,7 +136,8 @@ class ValueArray4 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -157,7 +159,8 @@ class ValueArray5 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -181,7 +184,9 @@ class ValueArray6 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -206,7 +211,9 @@ class ValueArray7 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -233,7 +240,9 @@ class ValueArray8 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -261,7 +270,10 @@ class ValueArray9 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -290,7 +302,10 @@ class ValueArray10 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -321,7 +336,10 @@ class ValueArray11 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -353,8 +371,11 @@ class ValueArray12 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -388,8 +409,11 @@ class ValueArray13 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -424,8 +448,11 @@ class ValueArray14 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -461,8 +488,12 @@ class ValueArray15 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -501,8 +532,12 @@ class ValueArray16 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -542,8 +577,12 @@ class ValueArray17 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -584,8 +623,13 @@ class ValueArray18 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -627,8 +671,13 @@ class ValueArray19 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -672,8 +721,13 @@ class ValueArray20 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -719,8 +773,14 @@ class ValueArray21 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -767,8 +827,14 @@ class ValueArray22 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -817,9 +883,14 @@ class ValueArray23 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v23_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -869,9 +940,15 @@ class ValueArray24 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -922,9 +999,15 @@ class ValueArray25 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -977,9 +1060,15 @@ class ValueArray26 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1034,9 +1123,16 @@ class ValueArray27 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1092,9 +1188,16 @@ class ValueArray28 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1151,9 +1254,16 @@ class ValueArray29 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1212,9 +1322,17 @@ class ValueArray30 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1275,9 +1393,17 @@ class ValueArray31 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1339,9 +1465,17 @@ class ValueArray32 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1405,9 +1539,18 @@ class ValueArray33 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1472,9 +1615,18 @@ class ValueArray34 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1540,10 +1692,18 @@ class ValueArray35 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v35_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1611,10 +1771,19 @@ class ValueArray36 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1684,10 +1853,19 @@ class ValueArray37 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1758,10 +1936,19 @@ class ValueArray38 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1833,10 +2020,20 @@ class ValueArray39 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1910,10 +2107,20 @@ class ValueArray40 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -1989,10 +2196,20 @@ class ValueArray41 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2069,10 +2286,21 @@ class ValueArray42 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2150,10 +2378,21 @@ class ValueArray43 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2233,10 +2472,21 @@ class ValueArray44 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2317,10 +2567,22 @@ class ValueArray45 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
static_cast<T>(v45_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2403,10 +2665,22 @@ class ValueArray46 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
static_cast<T>(v45_), static_cast<T>(v46_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2491,11 +2765,22 @@ class ValueArray47 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
v47_}; static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2581,11 +2866,23 @@ class ValueArray48 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
v48_}; static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
static_cast<T>(v48_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2672,11 +2969,23 @@ class ValueArray49 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
v48_, v49_}; static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
static_cast<T>(v48_), static_cast<T>(v49_)};
return ValuesIn(array); return ValuesIn(array);
} }
@ -2764,11 +3073,23 @@ class ValueArray50 {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
v48_, v49_, v50_}; static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
static_cast<T>(v48_), static_cast<T>(v49_), static_cast<T>(v50_)};
return ValuesIn(array); return ValuesIn(array);
} }

View file

@ -98,7 +98,7 @@ class ValueArray$i {
template <typename T> template <typename T>
operator ParamGenerator<T>() const { operator ParamGenerator<T>() const {
const T array[] = {$for j, [[v$(j)_]]}; const T array[] = {$for j, [[static_cast<T>(v$(j)_)]]};
return ValuesIn(array); return ValuesIn(array);
} }

View file

@ -494,10 +494,10 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
const string& instantiation_name = gen_it->first; const string& instantiation_name = gen_it->first;
ParamGenerator<ParamType> generator((*gen_it->second)()); ParamGenerator<ParamType> generator((*gen_it->second)());
Message test_case_name_stream; string test_case_name;
if ( !instantiation_name.empty() ) if ( !instantiation_name.empty() )
test_case_name_stream << instantiation_name << "/"; test_case_name = instantiation_name + "/";
test_case_name_stream << test_info->test_case_base_name; test_case_name += test_info->test_case_base_name;
int i = 0; int i = 0;
for (typename ParamGenerator<ParamType>::iterator param_it = for (typename ParamGenerator<ParamType>::iterator param_it =
@ -506,7 +506,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
Message test_name_stream; Message test_name_stream;
test_name_stream << test_info->test_base_name << "/" << i; test_name_stream << test_info->test_base_name << "/" << i;
MakeAndRegisterTestInfo( MakeAndRegisterTestInfo(
test_case_name_stream.GetString().c_str(), test_case_name.c_str(),
test_name_stream.GetString().c_str(), test_name_stream.GetString().c_str(),
NULL, // No type parameter. NULL, // No type parameter.
PrintToString(*param_it).c_str(), PrintToString(*param_it).c_str(),

View file

@ -32,6 +32,10 @@
// Low-level types and utilities for porting Google Test to various // Low-level types and utilities for porting Google Test to various
// platforms. They are subject to change without notice. DO NOT USE // platforms. They are subject to change without notice. DO NOT USE
// THEM IN USER CODE. // THEM IN USER CODE.
//
// This file is fundamental to Google Test. All other Google Test source
// files are expected to #include this. Therefore, it cannot #include
// any other Google Test header.
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
@ -72,6 +76,8 @@
// Test's own tr1 tuple implementation should be // Test's own tr1 tuple implementation should be
// used. Unused when the user sets // used. Unused when the user sets
// GTEST_HAS_TR1_TUPLE to 0. // GTEST_HAS_TR1_TUPLE to 0.
// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test
// is building in C++11/C++98 mode.
// GTEST_LINKED_AS_SHARED_LIBRARY // GTEST_LINKED_AS_SHARED_LIBRARY
// - Define to 1 when compiling tests that use // - Define to 1 when compiling tests that use
// Google Test as a shared library (known as // Google Test as a shared library (known as
@ -90,7 +96,11 @@
// GTEST_OS_LINUX - Linux // GTEST_OS_LINUX - Linux
// GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_LINUX_ANDROID - Google Android
// GTEST_OS_MAC - Mac OS X // GTEST_OS_MAC - Mac OS X
// GTEST_OS_IOS - iOS
// GTEST_OS_IOS_SIMULATOR - iOS simulator
// GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_NACL - Google Native Client (NaCl)
// GTEST_OS_OPENBSD - OpenBSD
// GTEST_OS_QNX - QNX
// GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SOLARIS - Sun Solaris
// GTEST_OS_SYMBIAN - Symbian // GTEST_OS_SYMBIAN - Symbian
// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
@ -175,7 +185,7 @@
// GTEST_FLAG() - references a flag. // GTEST_FLAG() - references a flag.
// GTEST_DECLARE_*() - declares a flag. // GTEST_DECLARE_*() - declares a flag.
// GTEST_DEFINE_*() - defines a flag. // GTEST_DEFINE_*() - defines a flag.
// GetArgvs() - returns the command line as a vector of strings. // GetInjectableArgvs() - returns the command line as a vector of strings.
// //
// Environment variable utilities: // Environment variable utilities:
// GetEnv() - gets the value of an environment variable. // GetEnv() - gets the value of an environment variable.
@ -193,6 +203,11 @@
# include <sys/stat.h> # include <sys/stat.h>
#endif // !_WIN32_WCE #endif // !_WIN32_WCE
#if defined __APPLE__
# include <AvailabilityMacros.h>
# include <TargetConditionals.h>
#endif
#include <iostream> // NOLINT #include <iostream> // NOLINT
#include <sstream> // NOLINT #include <sstream> // NOLINT
#include <string> // NOLINT #include <string> // NOLINT
@ -227,11 +242,17 @@
# endif // _WIN32_WCE # endif // _WIN32_WCE
#elif defined __APPLE__ #elif defined __APPLE__
# define GTEST_OS_MAC 1 # define GTEST_OS_MAC 1
# if TARGET_OS_IPHONE
# define GTEST_OS_IOS 1
# if TARGET_IPHONE_SIMULATOR
# define GTEST_OS_IOS_SIMULATOR 1
# endif
# endif
#elif defined __linux__ #elif defined __linux__
# define GTEST_OS_LINUX 1 # define GTEST_OS_LINUX 1
# ifdef ANDROID # if defined __ANDROID__
# define GTEST_OS_LINUX_ANDROID 1 # define GTEST_OS_LINUX_ANDROID 1
# endif // ANDROID # endif
#elif defined __MVS__ #elif defined __MVS__
# define GTEST_OS_ZOS 1 # define GTEST_OS_ZOS 1
#elif defined(__sun) && defined(__SVR4) #elif defined(__sun) && defined(__SVR4)
@ -242,8 +263,25 @@
# define GTEST_OS_HPUX 1 # define GTEST_OS_HPUX 1
#elif defined __native_client__ #elif defined __native_client__
# define GTEST_OS_NACL 1 # define GTEST_OS_NACL 1
#elif defined __OpenBSD__
# define GTEST_OS_OPENBSD 1
#elif defined __QNX__
# define GTEST_OS_QNX 1
#endif // __CYGWIN__ #endif // __CYGWIN__
#ifndef GTEST_LANG_CXX11
// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a
// value for __cplusplus, and recent versions of clang, gcc, and
// probably other compilers set that too in C++11 mode.
# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
// Compiling in at least C++11 mode.
# define GTEST_LANG_CXX11 1
# else
# define GTEST_LANG_CXX11 0
# endif
#endif
// Brings in definitions for functions used in the testing::internal::posix // Brings in definitions for functions used in the testing::internal::posix
// namespace (read, write, close, chdir, isatty, stat). We do not currently // namespace (read, write, close, chdir, isatty, stat). We do not currently
// use them on Windows Mobile. // use them on Windows Mobile.
@ -252,20 +290,25 @@
// is not the case, we need to include headers that provide the functions // is not the case, we need to include headers that provide the functions
// mentioned above. // mentioned above.
# include <unistd.h> # include <unistd.h>
# if !GTEST_OS_NACL # include <strings.h>
// TODO(vladl@google.com): Remove this condition when Native Client SDK adds
// strings.h (tracked in
// http://code.google.com/p/nativeclient/issues/detail?id=1175).
# include <strings.h> // Native Client doesn't provide strings.h.
# endif
#elif !GTEST_OS_WINDOWS_MOBILE #elif !GTEST_OS_WINDOWS_MOBILE
# include <direct.h> # include <direct.h>
# include <io.h> # include <io.h>
#endif #endif
#if GTEST_OS_LINUX_ANDROID
// Used to define __ANDROID_API__ matching the target NDK API level.
# include <android/api-level.h> // NOLINT
#endif
// Defines this to true iff Google Test can use POSIX regular expressions. // Defines this to true iff Google Test can use POSIX regular expressions.
#ifndef GTEST_HAS_POSIX_RE #ifndef GTEST_HAS_POSIX_RE
# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # if GTEST_OS_LINUX_ANDROID
// On Android, <regex.h> is only available starting with Gingerbread.
# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
# else
# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
# endif
#endif #endif
#if GTEST_HAS_POSIX_RE #if GTEST_HAS_POSIX_RE
@ -380,11 +423,27 @@
# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
# ifdef __GXX_RTTI # ifdef __GXX_RTTI
# define GTEST_HAS_RTTI 1 // When building against STLport with the Android NDK and with
// -frtti -fno-exceptions, the build fails at link time with undefined
// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
// so disable RTTI when detected.
# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
!defined(__EXCEPTIONS)
# define GTEST_HAS_RTTI 0
# else
# define GTEST_HAS_RTTI 1
# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
# else # else
# define GTEST_HAS_RTTI 0 # define GTEST_HAS_RTTI 0
# endif // __GXX_RTTI # endif // __GXX_RTTI
// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
// first version with C++ support.
# elif defined(__clang__)
# define GTEST_HAS_RTTI __has_feature(cxx_rtti)
// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
// both the typeid and dynamic_cast features are present. // both the typeid and dynamic_cast features are present.
# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) # elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
@ -417,7 +476,8 @@
// //
// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
// to your compiler flags. // to your compiler flags.
# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX) # define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
|| GTEST_OS_QNX)
#endif // GTEST_HAS_PTHREAD #endif // GTEST_HAS_PTHREAD
#if GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD
@ -433,8 +493,13 @@
// this macro to 0 to prevent Google Test from using tuple (any // this macro to 0 to prevent Google Test from using tuple (any
// feature depending on tuple with be disabled in this mode). // feature depending on tuple with be disabled in this mode).
#ifndef GTEST_HAS_TR1_TUPLE #ifndef GTEST_HAS_TR1_TUPLE
# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR)
// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>.
# define GTEST_HAS_TR1_TUPLE 0
# else
// The user didn't tell us not to do it, so we assume it's OK. // The user didn't tell us not to do it, so we assume it's OK.
# define GTEST_HAS_TR1_TUPLE 1 # define GTEST_HAS_TR1_TUPLE 1
# endif
#endif // GTEST_HAS_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE
// Determines whether Google Test's own tr1 tuple implementation // Determines whether Google Test's own tr1 tuple implementation
@ -443,14 +508,28 @@
// The user didn't tell us, so we need to figure it out. // The user didn't tell us, so we need to figure it out.
// We use our own TR1 tuple if we aren't sure the user has an // We use our own TR1 tuple if we aren't sure the user has an
// implementation of it already. At this time, GCC 4.0.0+ and MSVC // implementation of it already. At this time, libstdc++ 4.0.0+ and
// 2010 are the only mainstream compilers that come with a TR1 tuple // MSVC 2010 are the only mainstream standard libraries that come
// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by // with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler
// defining __GNUC__ and friends, but cannot compile GCC's tuple // pretends to be GCC by defining __GNUC__ and friends, but cannot
// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB // compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1
// Feature Pack download, which we cannot assume the user has. // tuple in a 323 MB Feature Pack download, which we cannot assume the
# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ // user has. QNX's QCC compiler is a modified GCC but it doesn't
|| _MSC_VER >= 1600 // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode,
// and it can be used with some compilers that define __GNUC__.
# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \
&& !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600
# define GTEST_ENV_HAS_TR1_TUPLE_ 1
# endif
// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used
// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6
// can build with clang but need to use gcc4.2's libstdc++).
# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
# define GTEST_ENV_HAS_STD_TUPLE_ 1
# endif
# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
# define GTEST_USE_OWN_TR1_TUPLE 0 # define GTEST_USE_OWN_TR1_TUPLE 0
# else # else
# define GTEST_USE_OWN_TR1_TUPLE 1 # define GTEST_USE_OWN_TR1_TUPLE 1
@ -465,6 +544,22 @@
# if GTEST_USE_OWN_TR1_TUPLE # if GTEST_USE_OWN_TR1_TUPLE
# include "gtest/internal/gtest-tuple.h" # include "gtest/internal/gtest-tuple.h"
# elif GTEST_ENV_HAS_STD_TUPLE_
# include <tuple>
// C++11 puts its tuple into the ::std namespace rather than
// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there.
// This causes undefined behavior, but supported compilers react in
// the way we intend.
namespace std {
namespace tr1 {
using ::std::get;
using ::std::make_tuple;
using ::std::tuple;
using ::std::tuple_element;
using ::std::tuple_size;
}
}
# elif GTEST_OS_SYMBIAN # elif GTEST_OS_SYMBIAN
// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
@ -515,7 +610,16 @@
// The user didn't tell us, so we need to figure it out. // The user didn't tell us, so we need to figure it out.
# if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX && !defined(__ia64__)
# define GTEST_HAS_CLONE 1 # if GTEST_OS_LINUX_ANDROID
// On Android, clone() is only available on ARM starting with Gingerbread.
# if defined(__arm__) && __ANDROID_API__ >= 9
# define GTEST_HAS_CLONE 1
# else
# define GTEST_HAS_CLONE 0
# endif
# else
# define GTEST_HAS_CLONE 1
# endif
# else # else
# define GTEST_HAS_CLONE 0 # define GTEST_HAS_CLONE 0
# endif // GTEST_OS_LINUX && !defined(__ia64__) # endif // GTEST_OS_LINUX && !defined(__ia64__)
@ -538,9 +642,11 @@
// Google Test does not support death tests for VC 7.1 and earlier as // Google Test does not support death tests for VC 7.1 and earlier as
// abort() in a VC 7.1 application compiled as GUI in debug config // abort() in a VC 7.1 application compiled as GUI in debug config
// pops up a dialog window that cannot be suppressed programmatically. // pops up a dialog window that cannot be suppressed programmatically.
#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
(GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
(GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX) GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
GTEST_OS_OPENBSD || GTEST_OS_QNX)
# define GTEST_HAS_DEATH_TEST 1 # define GTEST_HAS_DEATH_TEST 1
# include <vector> // NOLINT # include <vector> // NOLINT
#endif #endif
@ -669,13 +775,23 @@
# define GTEST_NO_INLINE_ # define GTEST_NO_INLINE_
#endif #endif
// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
# define GTEST_HAS_CXXABI_H_ 1
#else
# define GTEST_HAS_CXXABI_H_ 0
#endif
namespace testing { namespace testing {
class Message; class Message;
namespace internal { namespace internal {
class String; // A secret type that Google Test users don't know about. It has no
// definition on purpose. Therefore it's impossible to create a
// Secret object, which is what we want.
class Secret;
// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time // The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the // expression is true. For example, you could use it to verify the
@ -697,8 +813,8 @@ struct CompileAssert {
}; };
#define GTEST_COMPILE_ASSERT_(expr, msg) \ #define GTEST_COMPILE_ASSERT_(expr, msg) \
typedef ::testing::internal::CompileAssert<(bool(expr))> \ typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
msg[bool(expr) ? 1 : -1] msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
// Implementation details of GTEST_COMPILE_ASSERT_: // Implementation details of GTEST_COMPILE_ASSERT_:
// //
@ -796,6 +912,7 @@ class scoped_ptr {
ptr_ = p; ptr_ = p;
} }
} }
private: private:
T* ptr_; T* ptr_;
@ -858,10 +975,9 @@ class GTEST_API_ RE {
private: private:
void Init(const char* regex); void Init(const char* regex);
// We use a const char* instead of a string, as Google Test may be used // We use a const char* instead of an std::string, as Google Test used to be
// where string is not available. We also do not use Google Test's own // used where std::string is not available. TODO(wan@google.com): change to
// String type here, in order to simplify dependencies between the // std::string.
// files.
const char* pattern_; const char* pattern_;
bool is_valid_; bool is_valid_;
@ -1044,20 +1160,21 @@ Derived* CheckedDowncastToActualType(Base* base) {
// GetCapturedStderr - stops capturing stderr and returns the captured string. // GetCapturedStderr - stops capturing stderr and returns the captured string.
// //
GTEST_API_ void CaptureStdout(); GTEST_API_ void CaptureStdout();
GTEST_API_ String GetCapturedStdout(); GTEST_API_ std::string GetCapturedStdout();
GTEST_API_ void CaptureStderr(); GTEST_API_ void CaptureStderr();
GTEST_API_ String GetCapturedStderr(); GTEST_API_ std::string GetCapturedStderr();
#endif // GTEST_HAS_STREAM_REDIRECTION #endif // GTEST_HAS_STREAM_REDIRECTION
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
// A copy of all command line arguments. Set by InitGoogleTest(). const ::std::vector<testing::internal::string>& GetInjectableArgvs();
extern ::std::vector<String> g_argvs; void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
new_argvs);
// GTEST_HAS_DEATH_TEST implies we have ::std::string. // A copy of all command line arguments. Set by InitGoogleTest().
const ::std::vector<String>& GetArgvs(); extern ::std::vector<testing::internal::string> g_argvs;
#endif // GTEST_HAS_DEATH_TEST #endif // GTEST_HAS_DEATH_TEST
@ -1084,22 +1201,37 @@ inline void SleepMilliseconds(int n) {
// use it in user tests, either directly or indirectly. // use it in user tests, either directly or indirectly.
class Notification { class Notification {
public: public:
Notification() : notified_(false) {} Notification() : notified_(false) {
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
}
~Notification() {
pthread_mutex_destroy(&mutex_);
}
// Notifies all threads created with this notification to start. Must // Notifies all threads created with this notification to start. Must
// be called from the controller thread. // be called from the controller thread.
void Notify() { notified_ = true; } void Notify() {
pthread_mutex_lock(&mutex_);
notified_ = true;
pthread_mutex_unlock(&mutex_);
}
// Blocks until the controller thread notifies. Must be called from a test // Blocks until the controller thread notifies. Must be called from a test
// thread. // thread.
void WaitForNotification() { void WaitForNotification() {
while(!notified_) { for (;;) {
pthread_mutex_lock(&mutex_);
const bool notified = notified_;
pthread_mutex_unlock(&mutex_);
if (notified)
break;
SleepMilliseconds(10); SleepMilliseconds(10);
} }
} }
private: private:
volatile bool notified_; pthread_mutex_t mutex_;
bool notified_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
}; };
@ -1207,21 +1339,23 @@ class MutexBase {
void Lock() { void Lock() {
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
owner_ = pthread_self(); owner_ = pthread_self();
has_owner_ = true;
} }
// Releases this mutex. // Releases this mutex.
void Unlock() { void Unlock() {
// We don't protect writing to owner_ here, as it's the caller's // Since the lock is being released the owner_ field should no longer be
// responsibility to ensure that the current thread holds the // considered valid. We don't protect writing to has_owner_ here, as it's
// the caller's responsibility to ensure that the current thread holds the
// mutex when this is called. // mutex when this is called.
owner_ = 0; has_owner_ = false;
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
} }
// Does nothing if the current thread holds the mutex. Otherwise, crashes // Does nothing if the current thread holds the mutex. Otherwise, crashes
// with high probability. // with high probability.
void AssertHeld() const { void AssertHeld() const {
GTEST_CHECK_(owner_ == pthread_self()) GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
<< "The current thread is not holding the mutex @" << this; << "The current thread is not holding the mutex @" << this;
} }
@ -1232,7 +1366,14 @@ class MutexBase {
// have to be public. // have to be public.
public: public:
pthread_mutex_t mutex_; // The underlying pthread mutex. pthread_mutex_t mutex_; // The underlying pthread mutex.
pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. // has_owner_ indicates whether the owner_ field below contains a valid thread
// ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
// accesses to the owner_ field should be protected by a check of this field.
// An alternative might be to memset() owner_ to all zeros, but there's no
// guarantee that a zero'd pthread_t is necessarily invalid or even different
// from pthread_self().
bool has_owner_;
pthread_t owner_; // The thread holding the mutex.
}; };
// Forward-declares a static mutex. // Forward-declares a static mutex.
@ -1240,8 +1381,13 @@ class MutexBase {
extern ::testing::internal::MutexBase mutex extern ::testing::internal::MutexBase mutex
// Defines and statically (i.e. at link time) initializes a static mutex. // Defines and statically (i.e. at link time) initializes a static mutex.
// The initialization list here does not explicitly initialize each field,
// instead relying on default initialization for the unspecified fields. In
// particular, the owner_ field (a pthread_t) is not explicitly initialized.
// This allows initialization to work whether pthread_t is a scalar or struct.
// The flag -Wmissing-field-initializers must not be specified for this to work.
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
// The Mutex class can only be used for mutexes created at runtime. It // The Mutex class can only be used for mutexes created at runtime. It
// shares its API with MutexBase otherwise. // shares its API with MutexBase otherwise.
@ -1249,7 +1395,7 @@ class Mutex : public MutexBase {
public: public:
Mutex() { Mutex() {
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
owner_ = 0; has_owner_ = false;
} }
~Mutex() { ~Mutex() {
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
@ -1399,6 +1545,8 @@ class ThreadLocal {
class Mutex { class Mutex {
public: public:
Mutex() {} Mutex() {}
void Lock() {}
void Unlock() {}
void AssertHeld() const {} void AssertHeld() const {}
}; };
@ -1529,6 +1677,10 @@ inline bool IsUpper(char ch) {
inline bool IsXDigit(char ch) { inline bool IsXDigit(char ch) {
return isxdigit(static_cast<unsigned char>(ch)) != 0; return isxdigit(static_cast<unsigned char>(ch)) != 0;
} }
inline bool IsXDigit(wchar_t ch) {
const unsigned char low_byte = static_cast<unsigned char>(ch);
return ch == low_byte && isxdigit(low_byte) != 0;
}
inline char ToLower(char ch) { inline char ToLower(char ch) {
return static_cast<char>(tolower(static_cast<unsigned char>(ch))); return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
@ -1666,6 +1818,23 @@ inline void Abort() { abort(); }
} // namespace posix } // namespace posix
// MSVC "deprecates" snprintf and issues warnings wherever it is used. In
// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate
// function in order to achieve that. We use macro definition here because
// snprintf is a variadic function.
#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
// MSVC 2005 and above support variadic macros.
# define GTEST_SNPRINTF_(buffer, size, format, ...) \
_snprintf_s(buffer, size, size, format, __VA_ARGS__)
#elif defined(_MSC_VER)
// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't
// complain about _snprintf.
# define GTEST_SNPRINTF_ _snprintf
#else
# define GTEST_SNPRINTF_ snprintf
#endif
// The maximum number a BiggestInt can represent. This definition // The maximum number a BiggestInt can represent. This definition
// works no matter BiggestInt is represented in one's complement or // works no matter BiggestInt is represented in one's complement or
// two's complement. // two's complement.
@ -1718,7 +1887,6 @@ class TypeWithSize<4> {
template <> template <>
class TypeWithSize<8> { class TypeWithSize<8> {
public: public:
#if GTEST_OS_WINDOWS #if GTEST_OS_WINDOWS
typedef __int64 Int; typedef __int64 Int;
typedef unsigned __int64 UInt; typedef unsigned __int64 UInt;
@ -1745,7 +1913,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
#define GTEST_DECLARE_int32_(name) \ #define GTEST_DECLARE_int32_(name) \
GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
#define GTEST_DECLARE_string_(name) \ #define GTEST_DECLARE_string_(name) \
GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) GTEST_API_ extern ::std::string GTEST_FLAG(name)
// Macros for defining flags. // Macros for defining flags.
#define GTEST_DEFINE_bool_(name, default_val, doc) \ #define GTEST_DEFINE_bool_(name, default_val, doc) \
@ -1753,7 +1921,11 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
#define GTEST_DEFINE_int32_(name, default_val, doc) \ #define GTEST_DEFINE_int32_(name, default_val, doc) \
GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
#define GTEST_DEFINE_string_(name, default_val, doc) \ #define GTEST_DEFINE_string_(name, default_val, doc) \
GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
// Thread annotations
#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
#define GTEST_LOCK_EXCLUDED_(locks)
// Parses 'str' for a 32-bit signed integer. If successful, writes the result // Parses 'str' for a 32-bit signed integer. If successful, writes the result
// to *value and returns true; otherwise leaves *value unchanged and returns // to *value and returns true; otherwise leaves *value unchanged and returns

View file

@ -47,50 +47,18 @@
#endif #endif
#include <string.h> #include <string.h>
#include "gtest/internal/gtest-port.h"
#include <string> #include <string>
#include "gtest/internal/gtest-port.h"
namespace testing { namespace testing {
namespace internal { namespace internal {
// String - a UTF-8 string class. // String - an abstract class holding static string utilities.
//
// For historic reasons, we don't use std::string.
//
// TODO(wan@google.com): replace this class with std::string or
// implement it in terms of the latter.
//
// Note that String can represent both NULL and the empty string,
// while std::string cannot represent NULL.
//
// NULL and the empty string are considered different. NULL is less
// than anything (including the empty string) except itself.
//
// This class only provides minimum functionality necessary for
// implementing Google Test. We do not intend to implement a full-fledged
// string class here.
//
// Since the purpose of this class is to provide a substitute for
// std::string on platforms where it cannot be used, we define a copy
// constructor and assignment operators such that we don't need
// conditional compilation in a lot of places.
//
// In order to make the representation efficient, the d'tor of String
// is not virtual. Therefore DO NOT INHERIT FROM String.
class GTEST_API_ String { class GTEST_API_ String {
public: public:
// Static utility methods // Static utility methods
// Returns the input enclosed in double quotes if it's not NULL;
// otherwise returns "(null)". For example, "\"Hello\"" is returned
// for input "Hello".
//
// This is useful for printing a C string in the syntax of a literal.
//
// Known issue: escape sequences are not handled yet.
static String ShowCStringQuoted(const char* c_str);
// Clones a 0-terminated C string, allocating memory using new. The // Clones a 0-terminated C string, allocating memory using new. The
// caller is responsible for deleting the return value using // caller is responsible for deleting the return value using
// delete[]. Returns the cloned string, or NULL if the input is // delete[]. Returns the cloned string, or NULL if the input is
@ -137,11 +105,7 @@ class GTEST_API_ String {
// NULL will be converted to "(null)". If an error occurred during // NULL will be converted to "(null)". If an error occurred during
// the conversion, "(failed to convert from wide string)" is // the conversion, "(failed to convert from wide string)" is
// returned. // returned.
static String ShowWideCString(const wchar_t* wide_c_str); static std::string ShowWideCString(const wchar_t* wide_c_str);
// Similar to ShowWideCString(), except that this function encloses
// the converted string in double quotes.
static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
// Compares two wide C strings. Returns true iff they have the same // Compares two wide C strings. Returns true iff they have the same
// content. // content.
@ -175,174 +139,27 @@ class GTEST_API_ String {
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
const wchar_t* rhs); const wchar_t* rhs);
// Formats a list of arguments to a String, using the same format // Returns true iff the given string ends with the given suffix, ignoring
// spec string as for printf. // case. Any string is considered to end with an empty suffix.
// static bool EndsWithCaseInsensitive(
// We do not use the StringPrintf class as it is not universally const std::string& str, const std::string& suffix);
// available.
//
// The result is limited to 4096 characters (including the tailing
// 0). If 4096 characters are not enough to format the input,
// "<buffer exceeded>" is returned.
static String Format(const char* format, ...);
// C'tors // Formats an int value as "%02d".
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
// The default c'tor constructs a NULL string. // Formats an int value as "%X".
String() : c_str_(NULL), length_(0) {} static std::string FormatHexInt(int value);
// Constructs a String by cloning a 0-terminated C string. // Formats a byte as "%02X".
String(const char* a_c_str) { // NOLINT static std::string FormatByte(unsigned char value);
if (a_c_str == NULL) {
c_str_ = NULL;
length_ = 0;
} else {
ConstructNonNull(a_c_str, strlen(a_c_str));
}
}
// Constructs a String by copying a given number of chars from a
// buffer. E.g. String("hello", 3) creates the string "hel",
// String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
// and String(NULL, 1) results in access violation.
String(const char* buffer, size_t a_length) {
ConstructNonNull(buffer, a_length);
}
// The copy c'tor creates a new copy of the string. The two
// String objects do not share content.
String(const String& str) : c_str_(NULL), length_(0) { *this = str; }
// D'tor. String is intended to be a final class, so the d'tor
// doesn't need to be virtual.
~String() { delete[] c_str_; }
// Allows a String to be implicitly converted to an ::std::string or
// ::string, and vice versa. Converting a String containing a NULL
// pointer to ::std::string or ::string is undefined behavior.
// Converting a ::std::string or ::string containing an embedded NUL
// character to a String will result in the prefix up to the first
// NUL character.
String(const ::std::string& str) {
ConstructNonNull(str.c_str(), str.length());
}
operator ::std::string() const { return ::std::string(c_str(), length()); }
#if GTEST_HAS_GLOBAL_STRING
String(const ::string& str) {
ConstructNonNull(str.c_str(), str.length());
}
operator ::string() const { return ::string(c_str(), length()); }
#endif // GTEST_HAS_GLOBAL_STRING
// Returns true iff this is an empty string (i.e. "").
bool empty() const { return (c_str() != NULL) && (length() == 0); }
// Compares this with another String.
// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
// if this is greater than rhs.
int Compare(const String& rhs) const;
// Returns true iff this String equals the given C string. A NULL
// string and a non-NULL string are considered not equal.
bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; }
// Returns true iff this String is less than the given String. A
// NULL string is considered less than "".
bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
// Returns true iff this String doesn't equal the given C string. A NULL
// string and a non-NULL string are considered not equal.
bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); }
// Returns true iff this String ends with the given suffix. *Any*
// String is considered to end with a NULL or empty suffix.
bool EndsWith(const char* suffix) const;
// Returns true iff this String ends with the given suffix, not considering
// case. Any String is considered to end with a NULL or empty suffix.
bool EndsWithCaseInsensitive(const char* suffix) const;
// Returns the length of the encapsulated string, or 0 if the
// string is NULL.
size_t length() const { return length_; }
// Gets the 0-terminated C string this String object represents.
// The String object still owns the string. Therefore the caller
// should NOT delete the return value.
const char* c_str() const { return c_str_; }
// Assigns a C string to this object. Self-assignment works.
const String& operator=(const char* a_c_str) {
return *this = String(a_c_str);
}
// Assigns a String object to this object. Self-assignment works.
const String& operator=(const String& rhs) {
if (this != &rhs) {
delete[] c_str_;
if (rhs.c_str() == NULL) {
c_str_ = NULL;
length_ = 0;
} else {
ConstructNonNull(rhs.c_str(), rhs.length());
}
}
return *this;
}
private: private:
// Constructs a non-NULL String from the given content. This String(); // Not meant to be instantiated.
// function can only be called when c_str_ has not been allocated.
// ConstructNonNull(NULL, 0) results in an empty string ("").
// ConstructNonNull(NULL, non_zero) is undefined behavior.
void ConstructNonNull(const char* buffer, size_t a_length) {
char* const str = new char[a_length + 1];
memcpy(str, buffer, a_length);
str[a_length] = '\0';
c_str_ = str;
length_ = a_length;
}
const char* c_str_;
size_t length_;
}; // class String }; // class String
// Streams a String to an ostream. Each '\0' character in the String // Gets the content of the stringstream's buffer as an std::string. Each '\0'
// is replaced with "\\0".
inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
if (str.c_str() == NULL) {
os << "(null)";
} else {
const char* const c_str = str.c_str();
for (size_t i = 0; i != str.length(); i++) {
if (c_str[i] == '\0') {
os << "\\0";
} else {
os << c_str[i];
}
}
}
return os;
}
// Gets the content of the stringstream's buffer as a String. Each '\0'
// character in the buffer is replaced with "\\0". // character in the buffer is replaced with "\\0".
GTEST_API_ String StringStreamToString(::std::stringstream* stream); GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
// Converts a streamable value to a String. A NULL pointer is
// converted to "(null)". When the input value is a ::string,
// ::std::string, ::wstring, or ::std::wstring object, each NUL
// character in it is replaced with "\\0".
// Declared here but defined in gtest.h, so that it has access
// to the definition of the Message class, required by the ARM
// compiler.
template <typename T>
String StreamableToString(const T& streamable);
} // namespace internal } // namespace internal
} // namespace testing } // namespace testing

View file

@ -1,4 +1,6 @@
// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // This file was GENERATED by command:
// pump.py gtest-tuple.h.pump
// DO NOT EDIT BY HAND!!!
// Copyright 2009 Google Inc. // Copyright 2009 Google Inc.
// All Rights Reserved. // All Rights Reserved.
@ -140,34 +142,54 @@ template <bool kIndexValid, int kIndex, class Tuple>
struct TupleElement; struct TupleElement;
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 0, GTEST_10_TUPLE_(T)> { typedef T0 type; }; struct TupleElement<true, 0, GTEST_10_TUPLE_(T) > {
typedef T0 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 1, GTEST_10_TUPLE_(T)> { typedef T1 type; }; struct TupleElement<true, 1, GTEST_10_TUPLE_(T) > {
typedef T1 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 2, GTEST_10_TUPLE_(T)> { typedef T2 type; }; struct TupleElement<true, 2, GTEST_10_TUPLE_(T) > {
typedef T2 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 3, GTEST_10_TUPLE_(T)> { typedef T3 type; }; struct TupleElement<true, 3, GTEST_10_TUPLE_(T) > {
typedef T3 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 4, GTEST_10_TUPLE_(T)> { typedef T4 type; }; struct TupleElement<true, 4, GTEST_10_TUPLE_(T) > {
typedef T4 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 5, GTEST_10_TUPLE_(T)> { typedef T5 type; }; struct TupleElement<true, 5, GTEST_10_TUPLE_(T) > {
typedef T5 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 6, GTEST_10_TUPLE_(T)> { typedef T6 type; }; struct TupleElement<true, 6, GTEST_10_TUPLE_(T) > {
typedef T6 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 7, GTEST_10_TUPLE_(T)> { typedef T7 type; }; struct TupleElement<true, 7, GTEST_10_TUPLE_(T) > {
typedef T7 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 8, GTEST_10_TUPLE_(T)> { typedef T8 type; }; struct TupleElement<true, 8, GTEST_10_TUPLE_(T) > {
typedef T8 type;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 9, GTEST_10_TUPLE_(T)> { typedef T9 type; }; struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
typedef T9 type;
};
} // namespace gtest_internal } // namespace gtest_internal
@ -708,37 +730,59 @@ inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
template <typename Tuple> struct tuple_size; template <typename Tuple> struct tuple_size;
template <GTEST_0_TYPENAMES_(T)> template <GTEST_0_TYPENAMES_(T)>
struct tuple_size<GTEST_0_TUPLE_(T)> { static const int value = 0; }; struct tuple_size<GTEST_0_TUPLE_(T) > {
static const int value = 0;
};
template <GTEST_1_TYPENAMES_(T)> template <GTEST_1_TYPENAMES_(T)>
struct tuple_size<GTEST_1_TUPLE_(T)> { static const int value = 1; }; struct tuple_size<GTEST_1_TUPLE_(T) > {
static const int value = 1;
};
template <GTEST_2_TYPENAMES_(T)> template <GTEST_2_TYPENAMES_(T)>
struct tuple_size<GTEST_2_TUPLE_(T)> { static const int value = 2; }; struct tuple_size<GTEST_2_TUPLE_(T) > {
static const int value = 2;
};
template <GTEST_3_TYPENAMES_(T)> template <GTEST_3_TYPENAMES_(T)>
struct tuple_size<GTEST_3_TUPLE_(T)> { static const int value = 3; }; struct tuple_size<GTEST_3_TUPLE_(T) > {
static const int value = 3;
};
template <GTEST_4_TYPENAMES_(T)> template <GTEST_4_TYPENAMES_(T)>
struct tuple_size<GTEST_4_TUPLE_(T)> { static const int value = 4; }; struct tuple_size<GTEST_4_TUPLE_(T) > {
static const int value = 4;
};
template <GTEST_5_TYPENAMES_(T)> template <GTEST_5_TYPENAMES_(T)>
struct tuple_size<GTEST_5_TUPLE_(T)> { static const int value = 5; }; struct tuple_size<GTEST_5_TUPLE_(T) > {
static const int value = 5;
};
template <GTEST_6_TYPENAMES_(T)> template <GTEST_6_TYPENAMES_(T)>
struct tuple_size<GTEST_6_TUPLE_(T)> { static const int value = 6; }; struct tuple_size<GTEST_6_TUPLE_(T) > {
static const int value = 6;
};
template <GTEST_7_TYPENAMES_(T)> template <GTEST_7_TYPENAMES_(T)>
struct tuple_size<GTEST_7_TUPLE_(T)> { static const int value = 7; }; struct tuple_size<GTEST_7_TUPLE_(T) > {
static const int value = 7;
};
template <GTEST_8_TYPENAMES_(T)> template <GTEST_8_TYPENAMES_(T)>
struct tuple_size<GTEST_8_TUPLE_(T)> { static const int value = 8; }; struct tuple_size<GTEST_8_TUPLE_(T) > {
static const int value = 8;
};
template <GTEST_9_TYPENAMES_(T)> template <GTEST_9_TYPENAMES_(T)>
struct tuple_size<GTEST_9_TUPLE_(T)> { static const int value = 9; }; struct tuple_size<GTEST_9_TUPLE_(T) > {
static const int value = 9;
};
template <GTEST_10_TYPENAMES_(T)> template <GTEST_10_TYPENAMES_(T)>
struct tuple_size<GTEST_10_TUPLE_(T)> { static const int value = 10; }; struct tuple_size<GTEST_10_TUPLE_(T) > {
static const int value = 10;
};
template <int k, class Tuple> template <int k, class Tuple>
struct tuple_element { struct tuple_element {
@ -922,8 +966,8 @@ template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
inline bool operator==(const GTEST_10_TUPLE_(T)& t, inline bool operator==(const GTEST_10_TUPLE_(T)& t,
const GTEST_10_TUPLE_(U)& u) { const GTEST_10_TUPLE_(U)& u) {
return gtest_internal::SameSizeTuplePrefixComparator< return gtest_internal::SameSizeTuplePrefixComparator<
tuple_size<GTEST_10_TUPLE_(T)>::value, tuple_size<GTEST_10_TUPLE_(T) >::value,
tuple_size<GTEST_10_TUPLE_(U)>::value>::Eq(t, u); tuple_size<GTEST_10_TUPLE_(U) >::value>::Eq(t, u);
} }
template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)> template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>

View file

@ -118,8 +118,9 @@ struct TupleElement;
$for i [[ $for i [[
template <GTEST_$(n)_TYPENAMES_(T)> template <GTEST_$(n)_TYPENAMES_(T)>
struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T)> [[]] struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T) > {
{ typedef T$i type; }; typedef T$i type;
};
]] ]]
@ -220,7 +221,9 @@ template <typename Tuple> struct tuple_size;
$for j [[ $for j [[
template <GTEST_$(j)_TYPENAMES_(T)> template <GTEST_$(j)_TYPENAMES_(T)>
struct tuple_size<GTEST_$(j)_TUPLE_(T)> { static const int value = $j; }; struct tuple_size<GTEST_$(j)_TUPLE_(T) > {
static const int value = $j;
};
]] ]]
@ -302,8 +305,8 @@ template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
const GTEST_$(n)_TUPLE_(U)& u) { const GTEST_$(n)_TUPLE_(U)& u) {
return gtest_internal::SameSizeTuplePrefixComparator< return gtest_internal::SameSizeTuplePrefixComparator<
tuple_size<GTEST_$(n)_TUPLE_(T)>::value, tuple_size<GTEST_$(n)_TUPLE_(T) >::value,
tuple_size<GTEST_$(n)_TUPLE_(U)>::value>::Eq(t, u); tuple_size<GTEST_$(n)_TUPLE_(U) >::value>::Eq(t, u);
} }
template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)> template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>

View file

@ -45,15 +45,14 @@
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
#include "gtest/internal/gtest-string.h"
// #ifdef __GNUC__ is too general here. It is possible to use gcc without using // #ifdef __GNUC__ is too general here. It is possible to use gcc without using
// libstdc++ (which is where cxxabi.h comes from). // libstdc++ (which is where cxxabi.h comes from).
# ifdef __GLIBCXX__ # if GTEST_HAS_CXXABI_H_
# include <cxxabi.h> # include <cxxabi.h>
# elif defined(__HP_aCC) # elif defined(__HP_aCC)
# include <acxx_demangle.h> # include <acxx_demangle.h>
# endif // __GLIBCXX__ # endif // GTEST_HASH_CXXABI_H_
namespace testing { namespace testing {
namespace internal { namespace internal {
@ -62,24 +61,24 @@ namespace internal {
// NB: This function is also used in Google Mock, so don't move it inside of // NB: This function is also used in Google Mock, so don't move it inside of
// the typed-test-only section below. // the typed-test-only section below.
template <typename T> template <typename T>
String GetTypeName() { std::string GetTypeName() {
# if GTEST_HAS_RTTI # if GTEST_HAS_RTTI
const char* const name = typeid(T).name(); const char* const name = typeid(T).name();
# if defined(__GLIBCXX__) || defined(__HP_aCC) # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
int status = 0; int status = 0;
// gcc's implementation of typeid(T).name() mangles the type name, // gcc's implementation of typeid(T).name() mangles the type name,
// so we have to demangle it. // so we have to demangle it.
# ifdef __GLIBCXX__ # if GTEST_HAS_CXXABI_H_
using abi::__cxa_demangle; using abi::__cxa_demangle;
# endif // __GLIBCXX__ # endif // GTEST_HAS_CXXABI_H_
char* const readable_name = __cxa_demangle(name, 0, 0, &status); char* const readable_name = __cxa_demangle(name, 0, 0, &status);
const String name_str(status == 0 ? readable_name : name); const std::string name_str(status == 0 ? readable_name : name);
free(readable_name); free(readable_name);
return name_str; return name_str;
# else # else
return name; return name;
# endif // __GLIBCXX__ || __HP_aCC # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
# else # else
@ -3300,7 +3299,9 @@ struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
// INSTANTIATE_TYPED_TEST_CASE_P(). // INSTANTIATE_TYPED_TEST_CASE_P().
template <typename T> template <typename T>
struct TypeList { typedef Types1<T> type; }; struct TypeList {
typedef Types1<T> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5, template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10, typename T6, typename T7, typename T8, typename T9, typename T10,

View file

@ -43,15 +43,14 @@ $var n = 50 $$ Maximum length of type lists we want to support.
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
#include "gtest/internal/gtest-string.h"
// #ifdef __GNUC__ is too general here. It is possible to use gcc without using // #ifdef __GNUC__ is too general here. It is possible to use gcc without using
// libstdc++ (which is where cxxabi.h comes from). // libstdc++ (which is where cxxabi.h comes from).
# ifdef __GLIBCXX__ # if GTEST_HAS_CXXABI_H_
# include <cxxabi.h> # include <cxxabi.h>
# elif defined(__HP_aCC) # elif defined(__HP_aCC)
# include <acxx_demangle.h> # include <acxx_demangle.h>
# endif // __GLIBCXX__ # endif // GTEST_HASH_CXXABI_H_
namespace testing { namespace testing {
namespace internal { namespace internal {
@ -60,24 +59,24 @@ namespace internal {
// NB: This function is also used in Google Mock, so don't move it inside of // NB: This function is also used in Google Mock, so don't move it inside of
// the typed-test-only section below. // the typed-test-only section below.
template <typename T> template <typename T>
String GetTypeName() { std::string GetTypeName() {
# if GTEST_HAS_RTTI # if GTEST_HAS_RTTI
const char* const name = typeid(T).name(); const char* const name = typeid(T).name();
# if defined(__GLIBCXX__) || defined(__HP_aCC) # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
int status = 0; int status = 0;
// gcc's implementation of typeid(T).name() mangles the type name, // gcc's implementation of typeid(T).name() mangles the type name,
// so we have to demangle it. // so we have to demangle it.
# ifdef __GLIBCXX__ # if GTEST_HAS_CXXABI_H_
using abi::__cxa_demangle; using abi::__cxa_demangle;
# endif // __GLIBCXX__ # endif // GTEST_HAS_CXXABI_H_
char* const readable_name = __cxa_demangle(name, 0, 0, &status); char* const readable_name = __cxa_demangle(name, 0, 0, &status);
const String name_str(status == 0 ? readable_name : name); const std::string name_str(status == 0 ? readable_name : name);
free(readable_name); free(readable_name);
return name_str; return name_str;
# else # else
return name; return name;
# endif // __GLIBCXX__ || __HP_aCC # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
# else # else
@ -279,7 +278,9 @@ struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
// INSTANTIATE_TYPED_TEST_CASE_P(). // INSTANTIATE_TYPED_TEST_CASE_P().
template <typename T> template <typename T>
struct TypeList { typedef Types1<T> type; }; struct TypeList {
typedef Types1<T> type;
};
$range i 1..n $range i 1..n

View file

@ -43,6 +43,11 @@
# include <errno.h> # include <errno.h>
# include <fcntl.h> # include <fcntl.h>
# include <limits.h> # include <limits.h>
# if GTEST_OS_LINUX
# include <signal.h>
# endif // GTEST_OS_LINUX
# include <stdarg.h> # include <stdarg.h>
# if GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS
@ -52,6 +57,10 @@
# include <sys/wait.h> # include <sys/wait.h>
# endif // GTEST_OS_WINDOWS # endif // GTEST_OS_WINDOWS
# if GTEST_OS_QNX
# include <spawn.h>
# endif // GTEST_OS_QNX
#endif // GTEST_HAS_DEATH_TEST #endif // GTEST_HAS_DEATH_TEST
#include "gtest/gtest-message.h" #include "gtest/gtest-message.h"
@ -100,13 +109,42 @@ GTEST_DEFINE_string_(
"Indicates the file, line number, temporal index of " "Indicates the file, line number, temporal index of "
"the single death test to run, and a file descriptor to " "the single death test to run, and a file descriptor to "
"which a success code may be sent, all separated by " "which a success code may be sent, all separated by "
"colons. This flag is specified if and only if the current " "the '|' characters. This flag is specified if and only if the current "
"process is a sub-process launched for running a thread-safe " "process is a sub-process launched for running a thread-safe "
"death test. FOR INTERNAL USE ONLY."); "death test. FOR INTERNAL USE ONLY.");
} // namespace internal } // namespace internal
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
namespace internal {
// Valid only for fast death tests. Indicates the code is running in the
// child process of a fast style death test.
static bool g_in_fast_death_test_child = false;
// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process. Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests. IMPORTANT: This is an internal utility. Using it may break the
// implementation of death tests. User code MUST NOT use it.
bool InDeathTestChild() {
# if GTEST_OS_WINDOWS
// On Windows, death tests are thread-safe regardless of the value of the
// death_test_style flag.
return !GTEST_FLAG(internal_run_death_test).empty();
# else
if (GTEST_FLAG(death_test_style) == "threadsafe")
return !GTEST_FLAG(internal_run_death_test).empty();
else
return g_in_fast_death_test_child;
#endif
}
} // namespace internal
// ExitedWithCode constructor. // ExitedWithCode constructor.
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
} }
@ -141,7 +179,7 @@ namespace internal {
// Generates a textual description of a given exit code, in the format // Generates a textual description of a given exit code, in the format
// specified by wait(2). // specified by wait(2).
static String ExitSummary(int exit_code) { static std::string ExitSummary(int exit_code) {
Message m; Message m;
# if GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS
@ -176,7 +214,7 @@ bool ExitedUnsuccessfully(int exit_status) {
// one thread running, or cannot determine the number of threads, prior // one thread running, or cannot determine the number of threads, prior
// to executing the given statement. It is the responsibility of the // to executing the given statement. It is the responsibility of the
// caller not to pass a thread_count of 1. // caller not to pass a thread_count of 1.
static String DeathTestThreadWarning(size_t thread_count) { static std::string DeathTestThreadWarning(size_t thread_count) {
Message msg; Message msg;
msg << "Death tests use fork(), which is unsafe particularly" msg << "Death tests use fork(), which is unsafe particularly"
<< " in a threaded context. For this test, " << GTEST_NAME_ << " "; << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
@ -210,7 +248,7 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
// message is propagated back to the parent process. Otherwise, the // message is propagated back to the parent process. Otherwise, the
// message is simply printed to stderr. In either case, the program // message is simply printed to stderr. In either case, the program
// then exits with status 1. // then exits with status 1.
void DeathTestAbort(const String& message) { void DeathTestAbort(const std::string& message) {
// On a POSIX system, this function may be called from a threadsafe-style // On a POSIX system, this function may be called from a threadsafe-style
// death test child process, which operates on a very small stack. Use // death test child process, which operates on a very small stack. Use
// the heap for any additional non-minuscule memory requirements. // the heap for any additional non-minuscule memory requirements.
@ -234,9 +272,10 @@ void DeathTestAbort(const String& message) {
# define GTEST_DEATH_TEST_CHECK_(expression) \ # define GTEST_DEATH_TEST_CHECK_(expression) \
do { \ do { \
if (!::testing::internal::IsTrue(expression)) { \ if (!::testing::internal::IsTrue(expression)) { \
DeathTestAbort(::testing::internal::String::Format( \ DeathTestAbort( \
"CHECK failed: File %s, line %d: %s", \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
__FILE__, __LINE__, #expression)); \ + ::testing::internal::StreamableToString(__LINE__) + ": " \
+ #expression); \
} \ } \
} while (::testing::internal::AlwaysFalse()) } while (::testing::internal::AlwaysFalse())
@ -254,15 +293,16 @@ void DeathTestAbort(const String& message) {
gtest_retval = (expression); \ gtest_retval = (expression); \
} while (gtest_retval == -1 && errno == EINTR); \ } while (gtest_retval == -1 && errno == EINTR); \
if (gtest_retval == -1) { \ if (gtest_retval == -1) { \
DeathTestAbort(::testing::internal::String::Format( \ DeathTestAbort( \
"CHECK failed: File %s, line %d: %s != -1", \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
__FILE__, __LINE__, #expression)); \ + ::testing::internal::StreamableToString(__LINE__) + ": " \
+ #expression + " != -1"); \
} \ } \
} while (::testing::internal::AlwaysFalse()) } while (::testing::internal::AlwaysFalse())
// Returns the message describing the last system error in errno. // Returns the message describing the last system error in errno.
String GetLastErrnoDescription() { std::string GetLastErrnoDescription() {
return String(errno == 0 ? "" : posix::StrError(errno)); return errno == 0 ? "" : posix::StrError(errno);
} }
// This is called from a death test parent process to read a failure // This is called from a death test parent process to read a failure
@ -312,11 +352,11 @@ const char* DeathTest::LastMessage() {
return last_death_test_message_.c_str(); return last_death_test_message_.c_str();
} }
void DeathTest::set_last_death_test_message(const String& message) { void DeathTest::set_last_death_test_message(const std::string& message) {
last_death_test_message_ = message; last_death_test_message_ = message;
} }
String DeathTest::last_death_test_message_; std::string DeathTest::last_death_test_message_;
// Provides cross platform implementation for some death functionality. // Provides cross platform implementation for some death functionality.
class DeathTestImpl : public DeathTest { class DeathTestImpl : public DeathTest {
@ -491,7 +531,7 @@ bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned()) if (!spawned())
return false; return false;
const String error_message = GetCapturedStderr(); const std::string error_message = GetCapturedStderr();
bool success = false; bool success = false;
Message buffer; Message buffer;
@ -673,22 +713,19 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
FALSE, // The initial state is non-signalled. FALSE, // The initial state is non-signalled.
NULL)); // The even is unnamed. NULL)); // The even is unnamed.
GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
const String filter_flag = String::Format("--%s%s=%s.%s", const std::string filter_flag =
GTEST_FLAG_PREFIX_, kFilterFlag, std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
info->test_case_name(), info->test_case_name() + "." + info->name();
info->name()); const std::string internal_flag =
const String internal_flag = String::Format( std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
"--%s%s=%s|%d|%d|%u|%Iu|%Iu", "=" + file_ + "|" + StreamableToString(line_) + "|" +
GTEST_FLAG_PREFIX_, StreamableToString(death_test_index) + "|" +
kInternalRunDeathTestFlag, StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
file_, line_, // size_t has the same width as pointers on both 32-bit and 64-bit
death_test_index,
static_cast<unsigned int>(::GetCurrentProcessId()),
// size_t has the same with as pointers on both 32-bit and 64-bit
// Windows platforms. // Windows platforms.
// See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
reinterpret_cast<size_t>(write_handle), "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
reinterpret_cast<size_t>(event_handle_.Get())); "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
char executable_path[_MAX_PATH + 1]; // NOLINT char executable_path[_MAX_PATH + 1]; // NOLINT
GTEST_DEATH_TEST_CHECK_( GTEST_DEATH_TEST_CHECK_(
@ -696,10 +733,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
executable_path, executable_path,
_MAX_PATH)); _MAX_PATH));
String command_line = String::Format("%s %s \"%s\"", std::string command_line =
::GetCommandLineA(), std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
filter_flag.c_str(), internal_flag + "\"";
internal_flag.c_str());
DeathTest::set_last_death_test_message(""); DeathTest::set_last_death_test_message("");
@ -816,6 +852,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// Event forwarding to the listeners of event listener API mush be shut // Event forwarding to the listeners of event listener API mush be shut
// down in death test subprocesses. // down in death test subprocesses.
GetUnitTestImpl()->listeners()->SuppressEventForwarding(); GetUnitTestImpl()->listeners()->SuppressEventForwarding();
g_in_fast_death_test_child = true;
return EXECUTE_TEST; return EXECUTE_TEST;
} else { } else {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
@ -835,6 +872,11 @@ class ExecDeathTest : public ForkingDeathTest {
ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
virtual TestRole AssumeRole(); virtual TestRole AssumeRole();
private: private:
static ::std::vector<testing::internal::string>
GetArgvsForDeathTestChildProcess() {
::std::vector<testing::internal::string> args = GetInjectableArgvs();
return args;
}
// The name of the file in which the death test is located. // The name of the file in which the death test is located.
const char* const file_; const char* const file_;
// The line number on which the death test is located. // The line number on which the death test is located.
@ -869,6 +911,7 @@ class Arguments {
char* const* Argv() { char* const* Argv() {
return &args_[0]; return &args_[0];
} }
private: private:
std::vector<char*> args_; std::vector<char*> args_;
}; };
@ -894,6 +937,7 @@ extern "C" char** environ;
inline char** GetEnviron() { return environ; } inline char** GetEnviron() { return environ; }
# endif // GTEST_OS_MAC # endif // GTEST_OS_MAC
# if !GTEST_OS_QNX
// The main function for a threadsafe-style death test child process. // The main function for a threadsafe-style death test child process.
// This function is called in a clone()-ed process and thus must avoid // This function is called in a clone()-ed process and thus must avoid
// any potentially unsafe operations like malloc or libc functions. // any potentially unsafe operations like malloc or libc functions.
@ -908,9 +952,8 @@ static int ExecDeathTestChildMain(void* child_arg) {
UnitTest::GetInstance()->original_working_dir(); UnitTest::GetInstance()->original_working_dir();
// We can safely call chdir() as it's a direct system call. // We can safely call chdir() as it's a direct system call.
if (chdir(original_dir) != 0) { if (chdir(original_dir) != 0) {
DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
original_dir, GetLastErrnoDescription());
GetLastErrnoDescription().c_str()));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -920,12 +963,12 @@ static int ExecDeathTestChildMain(void* child_arg) {
// invoke the test program via a valid path that contains at least // invoke the test program via a valid path that contains at least
// one path separator. // one path separator.
execve(args->argv[0], args->argv, GetEnviron()); execve(args->argv[0], args->argv, GetEnviron());
DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
args->argv[0], original_dir + " failed: " +
original_dir, GetLastErrnoDescription());
GetLastErrnoDescription().c_str()));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
# endif // !GTEST_OS_QNX
// Two utility routines that together determine the direction the stack // Two utility routines that together determine the direction the stack
// grows. // grows.
@ -936,25 +979,75 @@ static int ExecDeathTestChildMain(void* child_arg) {
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
// StackLowerThanAddress into StackGrowsDown, which then doesn't give // StackLowerThanAddress into StackGrowsDown, which then doesn't give
// correct answer. // correct answer.
bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
bool StackLowerThanAddress(const void* ptr) { void StackLowerThanAddress(const void* ptr, bool* result) {
int dummy; int dummy;
return &dummy < ptr; *result = (&dummy < ptr);
} }
bool StackGrowsDown() { bool StackGrowsDown() {
int dummy; int dummy;
return StackLowerThanAddress(&dummy); bool result;
StackLowerThanAddress(&dummy, &result);
return result;
} }
// A threadsafe implementation of fork(2) for threadsafe-style death tests // Spawns a child process with the same executable as the current process in
// that uses clone(2). It dies with an error message if anything goes // a thread-safe manner and instructs it to run the death test. The
// wrong. // implementation uses fork(2) + exec. On systems where clone(2) is
static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { // available, it is used instead, being slightly more thread-safe. On QNX,
// fork supports only single-threaded environments, so this function uses
// spawn(2) there instead. The function dies with an error message if
// anything goes wrong.
static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
ExecDeathTestArgs args = { argv, close_fd }; ExecDeathTestArgs args = { argv, close_fd };
pid_t child_pid = -1; pid_t child_pid = -1;
# if GTEST_HAS_CLONE # if GTEST_OS_QNX
// Obtains the current directory and sets it to be closed in the child
// process.
const int cwd_fd = open(".", O_RDONLY);
GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
// We need to execute the test program in the same environment where
// it was originally invoked. Therefore we change to the original
// working directory first.
const char* const original_dir =
UnitTest::GetInstance()->original_working_dir();
// We can safely call chdir() as it's a direct system call.
if (chdir(original_dir) != 0) {
DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
GetLastErrnoDescription());
return EXIT_FAILURE;
}
int fd_flags;
// Set close_fd to be closed after spawn.
GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
fd_flags | FD_CLOEXEC));
struct inheritance inherit = {0};
// spawn is a system call.
child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
// Restores the current working directory.
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
# else // GTEST_OS_QNX
# if GTEST_OS_LINUX
// When a SIGPROF signal is received while fork() or clone() are executing,
// the process may hang. To avoid this, we ignore SIGPROF here and re-enable
// it after the call to fork()/clone() is complete.
struct sigaction saved_sigprof_action;
struct sigaction ignore_sigprof_action;
memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
sigemptyset(&ignore_sigprof_action.sa_mask);
ignore_sigprof_action.sa_handler = SIG_IGN;
GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
# endif // GTEST_OS_LINUX
# if GTEST_HAS_CLONE
const bool use_fork = GTEST_FLAG(death_test_use_fork); const bool use_fork = GTEST_FLAG(death_test_use_fork);
if (!use_fork) { if (!use_fork) {
@ -964,21 +1057,37 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0); MAP_ANON | MAP_PRIVATE, -1, 0);
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
// Maximum stack alignment in bytes: For a downward-growing stack, this
// amount is subtracted from size of the stack space to get an address
// that is within the stack space and is aligned on all systems we care
// about. As far as I know there is no ABI with stack alignment greater
// than 64. We assume stack and stack_size already have alignment of
// kMaxStackAlignment.
const size_t kMaxStackAlignment = 64;
void* const stack_top = void* const stack_top =
static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0); static_cast<char*>(stack) +
(stack_grows_down ? stack_size - kMaxStackAlignment : 0);
GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
} }
# else # else
const bool use_fork = true; const bool use_fork = true;
# endif // GTEST_HAS_CLONE # endif // GTEST_HAS_CLONE
if (use_fork && (child_pid = fork()) == 0) { if (use_fork && (child_pid = fork()) == 0) {
ExecDeathTestChildMain(&args); ExecDeathTestChildMain(&args);
_exit(0); _exit(0);
} }
# endif // GTEST_OS_QNX
# if GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_SYSCALL_(
sigaction(SIGPROF, &saved_sigprof_action, NULL));
# endif // GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_(child_pid != -1); GTEST_DEATH_TEST_CHECK_(child_pid != -1);
return child_pid; return child_pid;
@ -1006,16 +1115,16 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
// it be closed when the child process does an exec: // it be closed when the child process does an exec:
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
const String filter_flag = const std::string filter_flag =
String::Format("--%s%s=%s.%s", std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name() + "." + info->name();
info->test_case_name(), info->name()); const std::string internal_flag =
const String internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
String::Format("--%s%s=%s|%d|%d|%d", + file_ + "|" + StreamableToString(line_) + "|"
GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + StreamableToString(death_test_index) + "|"
file_, line_, death_test_index, pipe_fd[1]); + StreamableToString(pipe_fd[1]);
Arguments args; Arguments args;
args.AddArguments(GetArgvs()); args.AddArguments(GetArgvsForDeathTestChildProcess());
args.AddArgument(filter_flag.c_str()); args.AddArgument(filter_flag.c_str());
args.AddArgument(internal_flag.c_str()); args.AddArgument(internal_flag.c_str());
@ -1026,7 +1135,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
// is necessary. // is necessary.
FlushInfoLog(); FlushInfoLog();
const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
set_child_pid(child_pid); set_child_pid(child_pid);
set_read_fd(pipe_fd[0]); set_read_fd(pipe_fd[0]);
@ -1052,9 +1161,10 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
if (flag != NULL) { if (flag != NULL) {
if (death_test_index > flag->index()) { if (death_test_index > flag->index()) {
DeathTest::set_last_death_test_message(String::Format( DeathTest::set_last_death_test_message(
"Death test count (%d) somehow exceeded expected maximum (%d)", "Death test count (" + StreamableToString(death_test_index)
death_test_index, flag->index())); + ") somehow exceeded expected maximum ("
+ StreamableToString(flag->index()) + ")");
return false; return false;
} }
@ -1083,9 +1193,9 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
# endif // GTEST_OS_WINDOWS # endif // GTEST_OS_WINDOWS
else { // NOLINT - this is more readable than unbalanced brackets inside #if. else { // NOLINT - this is more readable than unbalanced brackets inside #if.
DeathTest::set_last_death_test_message(String::Format( DeathTest::set_last_death_test_message(
"Unknown death test style \"%s\" encountered", "Unknown death test style \"" + GTEST_FLAG(death_test_style)
GTEST_FLAG(death_test_style).c_str())); + "\" encountered");
return false; return false;
} }
@ -1123,8 +1233,8 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
FALSE, // Non-inheritable. FALSE, // Non-inheritable.
parent_process_id)); parent_process_id));
if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
DeathTestAbort(String::Format("Unable to open parent process %u", DeathTestAbort("Unable to open parent process " +
parent_process_id)); StreamableToString(parent_process_id));
} }
// TODO(vladl@google.com): Replace the following check with a // TODO(vladl@google.com): Replace the following check with a
@ -1144,9 +1254,10 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
// DUPLICATE_SAME_ACCESS is used. // DUPLICATE_SAME_ACCESS is used.
FALSE, // Request non-inheritable handler. FALSE, // Request non-inheritable handler.
DUPLICATE_SAME_ACCESS)) { DUPLICATE_SAME_ACCESS)) {
DeathTestAbort(String::Format( DeathTestAbort("Unable to duplicate the pipe handle " +
"Unable to duplicate the pipe handle %Iu from the parent process %u", StreamableToString(write_handle_as_size_t) +
write_handle_as_size_t, parent_process_id)); " from the parent process " +
StreamableToString(parent_process_id));
} }
const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t); const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
@ -1157,17 +1268,18 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
0x0, 0x0,
FALSE, FALSE,
DUPLICATE_SAME_ACCESS)) { DUPLICATE_SAME_ACCESS)) {
DeathTestAbort(String::Format( DeathTestAbort("Unable to duplicate the event handle " +
"Unable to duplicate the event handle %Iu from the parent process %u", StreamableToString(event_handle_as_size_t) +
event_handle_as_size_t, parent_process_id)); " from the parent process " +
StreamableToString(parent_process_id));
} }
const int write_fd = const int write_fd =
::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND); ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
if (write_fd == -1) { if (write_fd == -1) {
DeathTestAbort(String::Format( DeathTestAbort("Unable to convert pipe handle " +
"Unable to convert pipe handle %Iu to a file descriptor", StreamableToString(write_handle_as_size_t) +
write_handle_as_size_t)); " to a file descriptor");
} }
// Signals the parent that the write end of the pipe has been acquired // Signals the parent that the write end of the pipe has been acquired
@ -1204,9 +1316,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
|| !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[3], &parent_process_id)
|| !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
|| !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
DeathTestAbort(String::Format( DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
"Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test));
GTEST_FLAG(internal_run_death_test).c_str()));
} }
write_fd = GetStatusFileDescriptor(parent_process_id, write_fd = GetStatusFileDescriptor(parent_process_id,
write_handle_as_size_t, write_handle_as_size_t,
@ -1217,9 +1328,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
|| !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[1], &line)
|| !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[2], &index)
|| !ParseNaturalNumber(fields[3], &write_fd)) { || !ParseNaturalNumber(fields[3], &write_fd)) {
DeathTestAbort(String::Format( DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
"Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test));
GTEST_FLAG(internal_run_death_test).c_str()));
} }
# endif // GTEST_OS_WINDOWS # endif // GTEST_OS_WINDOWS

View file

@ -29,6 +29,7 @@
// //
// Authors: keith.ray@gmail.com (Keith Ray) // Authors: keith.ray@gmail.com (Keith Ray)
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-filepath.h"
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
@ -39,8 +40,8 @@
#elif GTEST_OS_WINDOWS #elif GTEST_OS_WINDOWS
# include <direct.h> # include <direct.h>
# include <io.h> # include <io.h>
#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL #elif GTEST_OS_SYMBIAN
// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h // Symbian OpenC has PATH_MAX in sys/syslimits.h
# include <sys/syslimits.h> # include <sys/syslimits.h>
#else #else
# include <limits.h> # include <limits.h>
@ -116,9 +117,10 @@ FilePath FilePath::GetCurrentDir() {
// FilePath("dir/file"). If a case-insensitive extension is not // FilePath("dir/file"). If a case-insensitive extension is not
// found, returns a copy of the original FilePath. // found, returns a copy of the original FilePath.
FilePath FilePath::RemoveExtension(const char* extension) const { FilePath FilePath::RemoveExtension(const char* extension) const {
String dot_extension(String::Format(".%s", extension)); const std::string dot_extension = std::string(".") + extension;
if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); return FilePath(pathname_.substr(
0, pathname_.length() - dot_extension.length()));
} }
return *this; return *this;
} }
@ -147,7 +149,7 @@ const char* FilePath::FindLastPathSeparator() const {
// On Windows platform, '\' is the path separator, otherwise it is '/'. // On Windows platform, '\' is the path separator, otherwise it is '/'.
FilePath FilePath::RemoveDirectoryName() const { FilePath FilePath::RemoveDirectoryName() const {
const char* const last_sep = FindLastPathSeparator(); const char* const last_sep = FindLastPathSeparator();
return last_sep ? FilePath(String(last_sep + 1)) : *this; return last_sep ? FilePath(last_sep + 1) : *this;
} }
// RemoveFileName returns the directory path with the filename removed. // RemoveFileName returns the directory path with the filename removed.
@ -158,9 +160,9 @@ FilePath FilePath::RemoveDirectoryName() const {
// On Windows platform, '\' is the path separator, otherwise it is '/'. // On Windows platform, '\' is the path separator, otherwise it is '/'.
FilePath FilePath::RemoveFileName() const { FilePath FilePath::RemoveFileName() const {
const char* const last_sep = FindLastPathSeparator(); const char* const last_sep = FindLastPathSeparator();
String dir; std::string dir;
if (last_sep) { if (last_sep) {
dir = String(c_str(), last_sep + 1 - c_str()); dir = std::string(c_str(), last_sep + 1 - c_str());
} else { } else {
dir = kCurrentDirectoryString; dir = kCurrentDirectoryString;
} }
@ -177,11 +179,12 @@ FilePath FilePath::MakeFileName(const FilePath& directory,
const FilePath& base_name, const FilePath& base_name,
int number, int number,
const char* extension) { const char* extension) {
String file; std::string file;
if (number == 0) { if (number == 0) {
file = String::Format("%s.%s", base_name.c_str(), extension); file = base_name.string() + "." + extension;
} else { } else {
file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); file = base_name.string() + "_" + StreamableToString(number)
+ "." + extension;
} }
return ConcatPaths(directory, FilePath(file)); return ConcatPaths(directory, FilePath(file));
} }
@ -193,8 +196,7 @@ FilePath FilePath::ConcatPaths(const FilePath& directory,
if (directory.IsEmpty()) if (directory.IsEmpty())
return relative_path; return relative_path;
const FilePath dir(directory.RemoveTrailingPathSeparator()); const FilePath dir(directory.RemoveTrailingPathSeparator());
return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, return FilePath(dir.string() + kPathSeparator + relative_path.string());
relative_path.c_str()));
} }
// Returns true if pathname describes something findable in the file-system, // Returns true if pathname describes something findable in the file-system,
@ -338,7 +340,7 @@ bool FilePath::CreateFolder() const {
// On Windows platform, uses \ as the separator, other platforms use /. // On Windows platform, uses \ as the separator, other platforms use /.
FilePath FilePath::RemoveTrailingPathSeparator() const { FilePath FilePath::RemoveTrailingPathSeparator() const {
return IsDirectory() return IsDirectory()
? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) ? FilePath(pathname_.substr(0, pathname_.length() - 1))
: *this; : *this;
} }

View file

@ -58,6 +58,11 @@
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
#if GTEST_CAN_STREAM_RESULTS_
# include <arpa/inet.h> // NOLINT
# include <netdb.h> // NOLINT
#endif
#if GTEST_OS_WINDOWS #if GTEST_OS_WINDOWS
# include <windows.h> // NOLINT # include <windows.h> // NOLINT
#endif // GTEST_OS_WINDOWS #endif // GTEST_OS_WINDOWS
@ -112,6 +117,12 @@ GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
// Formats the given time in milliseconds as seconds. // Formats the given time in milliseconds as seconds.
GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
// Converts the given time in milliseconds to a date string in the ISO 8601
// format, without the timezone information. N.B.: due to the use the
// non-reentrant localtime() function, this function is not thread safe. Do
// not use it in any code that can be called from multiple threads.
GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
// Parses a string for an Int32 flag, in the form of "--flag=value". // Parses a string for an Int32 flag, in the form of "--flag=value".
// //
// On success, stores the value of the flag in *value, and returns // On success, stores the value of the flag in *value, and returns
@ -190,37 +201,35 @@ class GTestFlagSaver {
GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(stream_result_to) = stream_result_to_;
GTEST_FLAG(throw_on_failure) = throw_on_failure_; GTEST_FLAG(throw_on_failure) = throw_on_failure_;
} }
private: private:
// Fields for saving the original values of flags. // Fields for saving the original values of flags.
bool also_run_disabled_tests_; bool also_run_disabled_tests_;
bool break_on_failure_; bool break_on_failure_;
bool catch_exceptions_; bool catch_exceptions_;
String color_; std::string color_;
String death_test_style_; std::string death_test_style_;
bool death_test_use_fork_; bool death_test_use_fork_;
String filter_; std::string filter_;
String internal_run_death_test_; std::string internal_run_death_test_;
bool list_tests_; bool list_tests_;
String output_; std::string output_;
bool print_time_; bool print_time_;
bool pretty_;
internal::Int32 random_seed_; internal::Int32 random_seed_;
internal::Int32 repeat_; internal::Int32 repeat_;
bool shuffle_; bool shuffle_;
internal::Int32 stack_trace_depth_; internal::Int32 stack_trace_depth_;
String stream_result_to_; std::string stream_result_to_;
bool throw_on_failure_; bool throw_on_failure_;
} GTEST_ATTRIBUTE_UNUSED_; } GTEST_ATTRIBUTE_UNUSED_;
// Converts a Unicode code point to a narrow string in UTF-8 encoding. // Converts a Unicode code point to a narrow string in UTF-8 encoding.
// code_point parameter is of type UInt32 because wchar_t may not be // code_point parameter is of type UInt32 because wchar_t may not be
// wide enough to contain a code point. // wide enough to contain a code point.
// The output buffer str must containt at least 32 characters.
// The function returns the address of the output buffer.
// If the code_point is not a valid Unicode code point // If the code_point is not a valid Unicode code point
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
// as '(Invalid Unicode 0xXXXXXXXX)'. // to "(Invalid Unicode 0xXXXXXXXX)".
GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
// Converts a wide string to a narrow string in UTF-8 encoding. // Converts a wide string to a narrow string in UTF-8 encoding.
// The wide string is assumed to have the following encoding: // The wide string is assumed to have the following encoding:
@ -235,7 +244,7 @@ GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str);
// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
// and contains invalid UTF-16 surrogate pairs, values in those pairs // and contains invalid UTF-16 surrogate pairs, values in those pairs
// will be encoded as individual Unicode characters from Basic Normal Plane. // will be encoded as individual Unicode characters from Basic Normal Plane.
GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);
// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
// if the variable is present. If a file already exists at this location, this // if the variable is present. If a file already exists at this location, this
@ -339,16 +348,15 @@ class TestPropertyKeyIs {
// Constructor. // Constructor.
// //
// TestPropertyKeyIs has NO default constructor. // TestPropertyKeyIs has NO default constructor.
explicit TestPropertyKeyIs(const char* key) explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
: key_(key) {}
// Returns true iff the test name of test property matches on key_. // Returns true iff the test name of test property matches on key_.
bool operator()(const TestProperty& test_property) const { bool operator()(const TestProperty& test_property) const {
return String(test_property.key()).Compare(key_) == 0; return test_property.key() == key_;
} }
private: private:
String key_; std::string key_;
}; };
// Class UnitTestOptions. // Class UnitTestOptions.
@ -366,12 +374,12 @@ class GTEST_API_ UnitTestOptions {
// Functions for processing the gtest_output flag. // Functions for processing the gtest_output flag.
// Returns the output format, or "" for normal printed output. // Returns the output format, or "" for normal printed output.
static String GetOutputFormat(); static std::string GetOutputFormat();
// Returns the absolute path of the requested output file, or the // Returns the absolute path of the requested output file, or the
// default (test_detail.xml in the original working directory) if // default (test_detail.xml in the original working directory) if
// none was explicitly specified. // none was explicitly specified.
static String GetAbsolutePathToOutputFile(); static std::string GetAbsolutePathToOutputFile();
// Functions for processing the gtest_filter flag. // Functions for processing the gtest_filter flag.
@ -384,8 +392,8 @@ class GTEST_API_ UnitTestOptions {
// Returns true iff the user-specified filter matches the test case // Returns true iff the user-specified filter matches the test case
// name and the test name. // name and the test name.
static bool FilterMatchesTest(const String &test_case_name, static bool FilterMatchesTest(const std::string &test_case_name,
const String &test_name); const std::string &test_name);
#if GTEST_OS_WINDOWS #if GTEST_OS_WINDOWS
// Function for supporting the gtest_catch_exception flag. // Function for supporting the gtest_catch_exception flag.
@ -398,7 +406,7 @@ class GTEST_API_ UnitTestOptions {
// Returns true if "name" matches the ':' separated list of glob-style // Returns true if "name" matches the ':' separated list of glob-style
// filters in "filter". // filters in "filter".
static bool MatchesFilter(const String& name, const char* filter); static bool MatchesFilter(const std::string& name, const char* filter);
}; };
// Returns the current application's name, removing directory path if that // Returns the current application's name, removing directory path if that
@ -411,13 +419,13 @@ class OsStackTraceGetterInterface {
OsStackTraceGetterInterface() {} OsStackTraceGetterInterface() {}
virtual ~OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {}
// Returns the current OS stack trace as a String. Parameters: // Returns the current OS stack trace as an std::string. Parameters:
// //
// max_depth - the maximum number of stack frames to be included // max_depth - the maximum number of stack frames to be included
// in the trace. // in the trace.
// skip_count - the number of top frames to be skipped; doesn't count // skip_count - the number of top frames to be skipped; doesn't count
// against max_depth. // against max_depth.
virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; virtual string CurrentStackTrace(int max_depth, int skip_count) = 0;
// UponLeavingGTest() should be called immediately before Google Test calls // UponLeavingGTest() should be called immediately before Google Test calls
// user code. It saves some information about the current stack that // user code. It saves some information about the current stack that
@ -432,8 +440,11 @@ class OsStackTraceGetterInterface {
class OsStackTraceGetter : public OsStackTraceGetterInterface { class OsStackTraceGetter : public OsStackTraceGetterInterface {
public: public:
OsStackTraceGetter() : caller_frame_(NULL) {} OsStackTraceGetter() : caller_frame_(NULL) {}
virtual String CurrentStackTrace(int max_depth, int skip_count);
virtual void UponLeavingGTest(); virtual string CurrentStackTrace(int max_depth, int skip_count)
GTEST_LOCK_EXCLUDED_(mutex_);
virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
// This string is inserted in place of stack frames that are part of // This string is inserted in place of stack frames that are part of
// Google Test's implementation. // Google Test's implementation.
@ -455,7 +466,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface {
struct TraceInfo { struct TraceInfo {
const char* file; const char* file;
int line; int line;
String message; std::string message;
}; };
// This is the default global test part result reporter used in UnitTestImpl. // This is the default global test part result reporter used in UnitTestImpl.
@ -539,15 +550,25 @@ class GTEST_API_ UnitTestImpl {
// Gets the number of failed tests. // Gets the number of failed tests.
int failed_test_count() const; int failed_test_count() const;
// Gets the number of disabled tests that will be reported in the XML report.
int reportable_disabled_test_count() const;
// Gets the number of disabled tests. // Gets the number of disabled tests.
int disabled_test_count() const; int disabled_test_count() const;
// Gets the number of tests to be printed in the XML report.
int reportable_test_count() const;
// Gets the number of all tests. // Gets the number of all tests.
int total_test_count() const; int total_test_count() const;
// Gets the number of tests that should run. // Gets the number of tests that should run.
int test_to_run_count() const; int test_to_run_count() const;
// Gets the time of the test program start, in ms from the start of the
// UNIX epoch.
TimeInMillis start_timestamp() const { return start_timestamp_; }
// Gets the elapsed time, in milliseconds. // Gets the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const { return elapsed_time_; } TimeInMillis elapsed_time() const { return elapsed_time_; }
@ -596,7 +617,7 @@ class GTEST_API_ UnitTestImpl {
// getter, and returns it. // getter, and returns it.
OsStackTraceGetterInterface* os_stack_trace_getter(); OsStackTraceGetterInterface* os_stack_trace_getter();
// Returns the current OS stack trace as a String. // Returns the current OS stack trace as an std::string.
// //
// The maximum number of stack frames to be included is specified by // The maximum number of stack frames to be included is specified by
// the gtest_stack_trace_depth flag. The skip_count parameter // the gtest_stack_trace_depth flag. The skip_count parameter
@ -606,7 +627,7 @@ class GTEST_API_ UnitTestImpl {
// For example, if Foo() calls Bar(), which in turn calls // For example, if Foo() calls Bar(), which in turn calls
// CurrentOsStackTraceExceptTop(1), Foo() will be included in the // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
// trace but Bar() and CurrentOsStackTraceExceptTop() won't. // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
String CurrentOsStackTraceExceptTop(int skip_count); std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
// Finds and returns a TestCase with the given name. If one doesn't // Finds and returns a TestCase with the given name. If one doesn't
// exist, creates one and returns it. // exist, creates one and returns it.
@ -696,6 +717,12 @@ class GTEST_API_ UnitTestImpl {
ad_hoc_test_result_.Clear(); ad_hoc_test_result_.Clear();
} }
// Adds a TestProperty to the current TestResult object when invoked in a
// context of a test or a test case, or to the global property set. If the
// result already contains a property with the same key, the value will be
// updated.
void RecordProperty(const TestProperty& test_property);
enum ReactionToSharding { enum ReactionToSharding {
HONOR_SHARDING_PROTOCOL, HONOR_SHARDING_PROTOCOL,
IGNORE_SHARDING_PROTOCOL IGNORE_SHARDING_PROTOCOL
@ -880,6 +907,10 @@ class GTEST_API_ UnitTestImpl {
// Our random number generator. // Our random number generator.
internal::Random random_; internal::Random random_;
// The time of the test program start, in ms from the start of the
// UNIX epoch.
TimeInMillis start_timestamp_;
// How long the test took to run, in milliseconds. // How long the test took to run, in milliseconds.
TimeInMillis elapsed_time_; TimeInMillis elapsed_time_;
@ -935,7 +966,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
// Returns the message describing the last system error, regardless of the // Returns the message describing the last system error, regardless of the
// platform. // platform.
GTEST_API_ String GetLastErrnoDescription(); GTEST_API_ std::string GetLastErrnoDescription();
# if GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS
// Provides leak-safe Windows kernel handle ownership. // Provides leak-safe Windows kernel handle ownership.
@ -1018,8 +1049,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
class TestResultAccessor { class TestResultAccessor {
public: public:
static void RecordProperty(TestResult* test_result, static void RecordProperty(TestResult* test_result,
const std::string& xml_element,
const TestProperty& property) { const TestProperty& property) {
test_result->RecordProperty(property); test_result->RecordProperty(xml_element, property);
} }
static void ClearTestPartResults(TestResult* test_result) { static void ClearTestPartResults(TestResult* test_result) {
@ -1032,6 +1064,154 @@ class TestResultAccessor {
} }
}; };
#if GTEST_CAN_STREAM_RESULTS_
// Streams test results to the given port on the given host machine.
class StreamingListener : public EmptyTestEventListener {
public:
// Abstract base class for writing strings to a socket.
class AbstractSocketWriter {
public:
virtual ~AbstractSocketWriter() {}
// Sends a string to the socket.
virtual void Send(const string& message) = 0;
// Closes the socket.
virtual void CloseConnection() {}
// Sends a string and a newline to the socket.
void SendLn(const string& message) {
Send(message + "\n");
}
};
// Concrete class for actually writing strings to a socket.
class SocketWriter : public AbstractSocketWriter {
public:
SocketWriter(const string& host, const string& port)
: sockfd_(-1), host_name_(host), port_num_(port) {
MakeConnection();
}
virtual ~SocketWriter() {
if (sockfd_ != -1)
CloseConnection();
}
// Sends a string to the socket.
virtual void Send(const string& message) {
GTEST_CHECK_(sockfd_ != -1)
<< "Send() can be called only when there is a connection.";
const int len = static_cast<int>(message.length());
if (write(sockfd_, message.c_str(), len) != len) {
GTEST_LOG_(WARNING)
<< "stream_result_to: failed to stream to "
<< host_name_ << ":" << port_num_;
}
}
private:
// Creates a client socket and connects to the server.
void MakeConnection();
// Closes the socket.
void CloseConnection() {
GTEST_CHECK_(sockfd_ != -1)
<< "CloseConnection() can be called only when there is a connection.";
close(sockfd_);
sockfd_ = -1;
}
int sockfd_; // socket file descriptor
const string host_name_;
const string port_num_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
}; // class SocketWriter
// Escapes '=', '&', '%', and '\n' characters in str as "%xx".
static string UrlEncode(const char* str);
StreamingListener(const string& host, const string& port)
: socket_writer_(new SocketWriter(host, port)) { Start(); }
explicit StreamingListener(AbstractSocketWriter* socket_writer)
: socket_writer_(socket_writer) { Start(); }
void OnTestProgramStart(const UnitTest& /* unit_test */) {
SendLn("event=TestProgramStart");
}
void OnTestProgramEnd(const UnitTest& unit_test) {
// Note that Google Test current only report elapsed time for each
// test iteration, not for the entire test program.
SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
// Notify the streaming server to stop.
socket_writer_->CloseConnection();
}
void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
SendLn("event=TestIterationStart&iteration=" +
StreamableToString(iteration));
}
void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
SendLn("event=TestIterationEnd&passed=" +
FormatBool(unit_test.Passed()) + "&elapsed_time=" +
StreamableToString(unit_test.elapsed_time()) + "ms");
}
void OnTestCaseStart(const TestCase& test_case) {
SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
}
void OnTestCaseEnd(const TestCase& test_case) {
SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
+ "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
+ "ms");
}
void OnTestStart(const TestInfo& test_info) {
SendLn(std::string("event=TestStart&name=") + test_info.name());
}
void OnTestEnd(const TestInfo& test_info) {
SendLn("event=TestEnd&passed=" +
FormatBool((test_info.result())->Passed()) +
"&elapsed_time=" +
StreamableToString((test_info.result())->elapsed_time()) + "ms");
}
void OnTestPartResult(const TestPartResult& test_part_result) {
const char* file_name = test_part_result.file_name();
if (file_name == NULL)
file_name = "";
SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
"&line=" + StreamableToString(test_part_result.line_number()) +
"&message=" + UrlEncode(test_part_result.message()));
}
private:
// Sends the given message and a newline to the socket.
void SendLn(const string& message) { socket_writer_->SendLn(message); }
// Called at the start of streaming to notify the receiver what
// protocol we are using.
void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
string FormatBool(bool value) { return value ? "1" : "0"; }
const scoped_ptr<AbstractSocketWriter> socket_writer_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
}; // class StreamingListener
#endif // GTEST_CAN_STREAM_RESULTS_
} // namespace internal } // namespace internal
} // namespace testing } // namespace testing

View file

@ -51,6 +51,11 @@
# include <mach/vm_map.h> # include <mach/vm_map.h>
#endif // GTEST_OS_MAC #endif // GTEST_OS_MAC
#if GTEST_OS_QNX
# include <devctl.h>
# include <sys/procfs.h>
#endif // GTEST_OS_QNX
#include "gtest/gtest-spi.h" #include "gtest/gtest-spi.h"
#include "gtest/gtest-message.h" #include "gtest/gtest-message.h"
#include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-internal.h"
@ -98,6 +103,26 @@ size_t GetThreadCount() {
} }
} }
#elif GTEST_OS_QNX
// Returns the number of threads running in the process, or 0 to indicate that
// we cannot detect it.
size_t GetThreadCount() {
const int fd = open("/proc/self/as", O_RDONLY);
if (fd < 0) {
return 0;
}
procfs_info process_info;
const int status =
devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
close(fd);
if (status == EOK) {
return static_cast<size_t>(process_info.num_threads);
} else {
return 0;
}
}
#else #else
size_t GetThreadCount() { size_t GetThreadCount() {
@ -222,7 +247,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
} }
// Helper function used by ValidateRegex() to format error messages. // Helper function used by ValidateRegex() to format error messages.
String FormatRegexSyntaxError(const char* regex, int index) { std::string FormatRegexSyntaxError(const char* regex, int index) {
return (Message() << "Syntax error at index " << index return (Message() << "Syntax error at index " << index
<< " in simple regular expression \"" << regex << "\": ").GetString(); << " in simple regular expression \"" << regex << "\": ").GetString();
} }
@ -429,15 +454,15 @@ const char kUnknownFile[] = "unknown file";
// Formats a source file path and a line number as they would appear // Formats a source file path and a line number as they would appear
// in an error message from the compiler used to compile this code. // in an error message from the compiler used to compile this code.
GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
const char* const file_name = file == NULL ? kUnknownFile : file; const std::string file_name(file == NULL ? kUnknownFile : file);
if (line < 0) { if (line < 0) {
return String::Format("%s:", file_name).c_str(); return file_name + ":";
} }
#ifdef _MSC_VER #ifdef _MSC_VER
return String::Format("%s(%d):", file_name, line).c_str(); return file_name + "(" + StreamableToString(line) + "):";
#else #else
return String::Format("%s:%d:", file_name, line).c_str(); return file_name + ":" + StreamableToString(line) + ":";
#endif // _MSC_VER #endif // _MSC_VER
} }
@ -448,12 +473,12 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
// to the file location it produces, unlike FormatFileLocation(). // to the file location it produces, unlike FormatFileLocation().
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
const char* file, int line) { const char* file, int line) {
const char* const file_name = file == NULL ? kUnknownFile : file; const std::string file_name(file == NULL ? kUnknownFile : file);
if (line < 0) if (line < 0)
return file_name; return file_name;
else else
return String::Format("%s:%d", file_name, line).c_str(); return file_name + ":" + StreamableToString(line);
} }
@ -488,8 +513,7 @@ GTestLog::~GTestLog() {
class CapturedStream { class CapturedStream {
public: public:
// The ctor redirects the stream to a temporary file. // The ctor redirects the stream to a temporary file.
CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
# if GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
@ -506,10 +530,29 @@ class CapturedStream {
<< temp_file_path; << temp_file_path;
filename_ = temp_file_path; filename_ = temp_file_path;
# else # else
// There's no guarantee that a test has write access to the // There's no guarantee that a test has write access to the current
// current directory, so we create the temporary file in the /tmp // directory, so we create the temporary file in the /tmp directory
// directory instead. // instead. We use /tmp on most systems, and /sdcard on Android.
// That's because Android doesn't have /tmp.
# if GTEST_OS_LINUX_ANDROID
// Note: Android applications are expected to call the framework's
// Context.getExternalStorageDirectory() method through JNI to get
// the location of the world-writable SD Card directory. However,
// this requires a Context handle, which cannot be retrieved
// globally from native code. Doing so also precludes running the
// code as part of a regular standalone executable, which doesn't
// run in a Dalvik process (e.g. when running it through 'adb shell').
//
// The location /sdcard is directly accessible from native code
// and is the only location (unofficially) supported by the Android
// team. It's generally a symlink to the real SD Card mount point
// which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
// other OEM-customized locations. Never rely on these, and always
// use /sdcard.
char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
# else
char name_template[] = "/tmp/captured_stream.XXXXXX"; char name_template[] = "/tmp/captured_stream.XXXXXX";
# endif // GTEST_OS_LINUX_ANDROID
const int captured_fd = mkstemp(name_template); const int captured_fd = mkstemp(name_template);
filename_ = name_template; filename_ = name_template;
# endif // GTEST_OS_WINDOWS # endif // GTEST_OS_WINDOWS
@ -522,7 +565,7 @@ class CapturedStream {
remove(filename_.c_str()); remove(filename_.c_str());
} }
String GetCapturedString() { std::string GetCapturedString() {
if (uncaptured_fd_ != -1) { if (uncaptured_fd_ != -1) {
// Restores the original stream. // Restores the original stream.
fflush(NULL); fflush(NULL);
@ -532,14 +575,14 @@ class CapturedStream {
} }
FILE* const file = posix::FOpen(filename_.c_str(), "r"); FILE* const file = posix::FOpen(filename_.c_str(), "r");
const String content = ReadEntireFile(file); const std::string content = ReadEntireFile(file);
posix::FClose(file); posix::FClose(file);
return content; return content;
} }
private: private:
// Reads the entire content of a file as a String. // Reads the entire content of a file as an std::string.
static String ReadEntireFile(FILE* file); static std::string ReadEntireFile(FILE* file);
// Returns the size (in bytes) of a file. // Returns the size (in bytes) of a file.
static size_t GetFileSize(FILE* file); static size_t GetFileSize(FILE* file);
@ -559,7 +602,7 @@ size_t CapturedStream::GetFileSize(FILE* file) {
} }
// Reads the entire content of a file as a string. // Reads the entire content of a file as a string.
String CapturedStream::ReadEntireFile(FILE* file) { std::string CapturedStream::ReadEntireFile(FILE* file) {
const size_t file_size = GetFileSize(file); const size_t file_size = GetFileSize(file);
char* const buffer = new char[file_size]; char* const buffer = new char[file_size];
@ -575,7 +618,7 @@ String CapturedStream::ReadEntireFile(FILE* file) {
bytes_read += bytes_last_read; bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size); } while (bytes_last_read > 0 && bytes_read < file_size);
const String content(buffer, bytes_read); const std::string content(buffer, bytes_read);
delete[] buffer; delete[] buffer;
return content; return content;
@ -598,8 +641,8 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
} }
// Stops capturing the output stream and returns the captured string. // Stops capturing the output stream and returns the captured string.
String GetCapturedStream(CapturedStream** captured_stream) { std::string GetCapturedStream(CapturedStream** captured_stream) {
const String content = (*captured_stream)->GetCapturedString(); const std::string content = (*captured_stream)->GetCapturedString();
delete *captured_stream; delete *captured_stream;
*captured_stream = NULL; *captured_stream = NULL;
@ -618,21 +661,37 @@ void CaptureStderr() {
} }
// Stops capturing stdout and returns the captured string. // Stops capturing stdout and returns the captured string.
String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } std::string GetCapturedStdout() {
return GetCapturedStream(&g_captured_stdout);
}
// Stops capturing stderr and returns the captured string. // Stops capturing stderr and returns the captured string.
String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } std::string GetCapturedStderr() {
return GetCapturedStream(&g_captured_stderr);
}
#endif // GTEST_HAS_STREAM_REDIRECTION #endif // GTEST_HAS_STREAM_REDIRECTION
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
// A copy of all command line arguments. Set by InitGoogleTest(). // A copy of all command line arguments. Set by InitGoogleTest().
::std::vector<String> g_argvs; ::std::vector<testing::internal::string> g_argvs;
// Returns the command line as a vector of strings. static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
const ::std::vector<String>& GetArgvs() { return g_argvs; } NULL; // Owned.
void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
if (g_injected_test_argvs != argvs)
delete g_injected_test_argvs;
g_injected_test_argvs = argvs;
}
const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
if (g_injected_test_argvs != NULL) {
return *g_injected_test_argvs;
}
return g_argvs;
}
#endif // GTEST_HAS_DEATH_TEST #endif // GTEST_HAS_DEATH_TEST
#if GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS_MOBILE
@ -647,8 +706,8 @@ void Abort() {
// Returns the name of the environment variable corresponding to the // Returns the name of the environment variable corresponding to the
// given flag. For example, FlagToEnvVar("foo") will return // given flag. For example, FlagToEnvVar("foo") will return
// "GTEST_FOO" in the open-source version. // "GTEST_FOO" in the open-source version.
static String FlagToEnvVar(const char* flag) { static std::string FlagToEnvVar(const char* flag) {
const String full_flag = const std::string full_flag =
(Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
Message env_var; Message env_var;
@ -705,7 +764,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
// //
// The value is considered true iff it's not "0". // The value is considered true iff it's not "0".
bool BoolFromGTestEnv(const char* flag, bool default_value) { bool BoolFromGTestEnv(const char* flag, bool default_value) {
const String env_var = FlagToEnvVar(flag); const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = posix::GetEnv(env_var.c_str()); const char* const string_value = posix::GetEnv(env_var.c_str());
return string_value == NULL ? return string_value == NULL ?
default_value : strcmp(string_value, "0") != 0; default_value : strcmp(string_value, "0") != 0;
@ -715,7 +774,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) {
// variable corresponding to the given flag; if it isn't set or // variable corresponding to the given flag; if it isn't set or
// doesn't represent a valid 32-bit integer, returns default_value. // doesn't represent a valid 32-bit integer, returns default_value.
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
const String env_var = FlagToEnvVar(flag); const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = posix::GetEnv(env_var.c_str()); const char* const string_value = posix::GetEnv(env_var.c_str());
if (string_value == NULL) { if (string_value == NULL) {
// The environment variable is not set. // The environment variable is not set.
@ -737,7 +796,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
// Reads and returns the string environment variable corresponding to // Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value. // the given flag; if it's not set, returns default_value.
const char* StringFromGTestEnv(const char* flag, const char* default_value) { const char* StringFromGTestEnv(const char* flag, const char* default_value) {
const String env_var = FlagToEnvVar(flag); const std::string env_var = FlagToEnvVar(flag);
const char* const value = posix::GetEnv(env_var.c_str()); const char* const value = posix::GetEnv(env_var.c_str());
return value == NULL ? default_value : value; return value == NULL ? default_value : value;
} }

View file

@ -55,14 +55,6 @@ namespace {
using ::std::ostream; using ::std::ostream;
#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s.
# define snprintf _snprintf
#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf.
# define snprintf _snprintf_s
#elif _MSC_VER
# define snprintf _snprintf
#endif // GTEST_OS_WINDOWS_MOBILE
// Prints a segment of bytes in the given object. // Prints a segment of bytes in the given object.
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
size_t count, ostream* os) { size_t count, ostream* os) {
@ -77,7 +69,7 @@ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
else else
*os << '-'; *os << '-';
} }
snprintf(text, sizeof(text), "%02X", obj_bytes[j]); GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
*os << text; *os << text;
} }
} }
@ -184,16 +176,16 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
*os << static_cast<char>(c); *os << static_cast<char>(c);
return kAsIs; return kAsIs;
} else { } else {
*os << String::Format("\\x%X", static_cast<UnsignedChar>(c)); *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
return kHexEscape; return kHexEscape;
} }
} }
return kSpecialEscape; return kSpecialEscape;
} }
// Prints a char c as if it's part of a string literal, escaping it when // Prints a wchar_t c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted. // necessary; returns how c was formatted.
static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
switch (c) { switch (c) {
case L'\'': case L'\'':
*os << "'"; *os << "'";
@ -208,8 +200,9 @@ static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
// Prints a char c as if it's part of a string literal, escaping it when // Prints a char c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted. // necessary; returns how c was formatted.
static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
return PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os); return PrintAsStringLiteralTo(
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
} }
// Prints a wide or narrow character c and its code. '\0' is printed // Prints a wide or narrow character c and its code. '\0' is printed
@ -228,7 +221,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
// obvious). // obvious).
if (c == 0) if (c == 0)
return; return;
*os << " (" << String::Format("%d", c).c_str(); *os << " (" << static_cast<int>(c);
// For more convenience, we print c's code again in hexidecimal, // For more convenience, we print c's code again in hexidecimal,
// unless c was already printed in the form '\x##' or the code is in // unless c was already printed in the form '\x##' or the code is in
@ -236,8 +229,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
if (format == kHexEscape || (1 <= c && c <= 9)) { if (format == kHexEscape || (1 <= c && c <= 9)) {
// Do nothing. // Do nothing.
} else { } else {
*os << String::Format(", 0x%X", *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
static_cast<UnsignedChar>(c)).c_str();
} }
*os << ")"; *os << ")";
} }
@ -255,48 +247,63 @@ void PrintTo(wchar_t wc, ostream* os) {
PrintCharAndCodeTo<wchar_t>(wc, os); PrintCharAndCodeTo<wchar_t>(wc, os);
} }
// Prints the given array of characters to the ostream. // Prints the given array of characters to the ostream. CharType must be either
// The array starts at *begin, the length is len, it may include '\0' characters // char or wchar_t.
// and may not be null-terminated. // The array starts at begin, the length is len, it may include '\0' characters
static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { // and may not be NUL-terminated.
*os << "\""; template <typename CharType>
static void PrintCharsAsStringTo(
const CharType* begin, size_t len, ostream* os) {
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
*os << kQuoteBegin;
bool is_previous_hex = false; bool is_previous_hex = false;
for (size_t index = 0; index < len; ++index) { for (size_t index = 0; index < len; ++index) {
const char cur = begin[index]; const CharType cur = begin[index];
if (is_previous_hex && IsXDigit(cur)) { if (is_previous_hex && IsXDigit(cur)) {
// Previous character is of '\x..' form and this character can be // Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to // interpreted as another hexadecimal digit in its number. Break string to
// disambiguate. // disambiguate.
*os << "\" \""; *os << "\" " << kQuoteBegin;
} }
is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
} }
*os << "\""; *os << "\"";
} }
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
// 'begin'. CharType must be either char or wchar_t.
template <typename CharType>
static void UniversalPrintCharArray(
const CharType* begin, size_t len, ostream* os) {
// The code
// const char kFoo[] = "foo";
// generates an array of 4, not 3, elements, with the last one being '\0'.
//
// Therefore when printing a char array, we don't print the last element if
// it's '\0', such that the output matches the string literal as it's
// written in the source code.
if (len > 0 && begin[len - 1] == '\0') {
PrintCharsAsStringTo(begin, len - 1, os);
return;
}
// If, however, the last element in the array is not '\0', e.g.
// const char kFoo[] = { 'f', 'o', 'o' };
// we must print the entire array. We also print a message to indicate
// that the array is not NUL-terminated.
PrintCharsAsStringTo(begin, len, os);
*os << " (no terminating NUL)";
}
// Prints a (const) char array of 'len' elements, starting at address 'begin'. // Prints a (const) char array of 'len' elements, starting at address 'begin'.
void UniversalPrintArray(const char* begin, size_t len, ostream* os) { void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
PrintCharsAsStringTo(begin, len, os); UniversalPrintCharArray(begin, len, os);
} }
// Prints the given array of wide characters to the ostream. // Prints a (const) wchar_t array of 'len' elements, starting at address
// The array starts at *begin, the length is len, it may include L'\0' // 'begin'.
// characters and may not be null-terminated. void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, UniversalPrintCharArray(begin, len, os);
ostream* os) {
*os << "L\"";
bool is_previous_hex = false;
for (size_t index = 0; index < len; ++index) {
const wchar_t cur = begin[index];
if (is_previous_hex && isascii(cur) && IsXDigit(static_cast<char>(cur))) {
// Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to
// disambiguate.
*os << "\" L\"";
}
is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape;
}
*os << "\"";
} }
// Prints the given C string to the ostream. // Prints the given C string to the ostream.
@ -322,7 +329,7 @@ void PrintTo(const wchar_t* s, ostream* os) {
*os << "NULL"; *os << "NULL";
} else { } else {
*os << ImplicitCast_<const void*>(s) << " pointing to "; *os << ImplicitCast_<const void*>(s) << " pointing to ";
PrintWideCharsAsStringTo(s, wcslen(s), os); PrintCharsAsStringTo(s, wcslen(s), os);
} }
} }
#endif // wchar_t is native #endif // wchar_t is native
@ -341,13 +348,13 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
// Prints a ::wstring object. // Prints a ::wstring object.
#if GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_GLOBAL_WSTRING
void PrintWideStringTo(const ::wstring& s, ostream* os) { void PrintWideStringTo(const ::wstring& s, ostream* os) {
PrintWideCharsAsStringTo(s.data(), s.size(), os); PrintCharsAsStringTo(s.data(), s.size(), os);
} }
#endif // GTEST_HAS_GLOBAL_WSTRING #endif // GTEST_HAS_GLOBAL_WSTRING
#if GTEST_HAS_STD_WSTRING #if GTEST_HAS_STD_WSTRING
void PrintWideStringTo(const ::std::wstring& s, ostream* os) { void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
PrintWideCharsAsStringTo(s.data(), s.size(), os); PrintCharsAsStringTo(s.data(), s.size(), os);
} }
#endif // GTEST_HAS_STD_WSTRING #endif // GTEST_HAS_STD_WSTRING

View file

@ -48,10 +48,10 @@ using internal::GetUnitTestImpl;
// Gets the summary of the failure message by omitting the stack trace // Gets the summary of the failure message by omitting the stack trace
// in it. // in it.
internal::String TestPartResult::ExtractSummary(const char* message) { std::string TestPartResult::ExtractSummary(const char* message) {
const char* const stack_trace = strstr(message, internal::kStackTraceMarker); const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
return stack_trace == NULL ? internal::String(message) : return stack_trace == NULL ? message :
internal::String(message, stack_trace - message); std::string(message, stack_trace);
} }
// Prints a TestPartResult object. // Prints a TestPartResult object.

View file

@ -58,10 +58,10 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
registered_tests = SkipSpaces(registered_tests); registered_tests = SkipSpaces(registered_tests);
Message errors; Message errors;
::std::set<String> tests; ::std::set<std::string> tests;
for (const char* names = registered_tests; names != NULL; for (const char* names = registered_tests; names != NULL;
names = SkipComma(names)) { names = SkipComma(names)) {
const String name = GetPrefixUntilComma(names); const std::string name = GetPrefixUntilComma(names);
if (tests.count(name) != 0) { if (tests.count(name) != 0) {
errors << "Test " << name << " is listed more than once.\n"; errors << "Test " << name << " is listed more than once.\n";
continue; continue;
@ -93,7 +93,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
} }
} }
const String& errors_str = errors.GetString(); const std::string& errors_str = errors.GetString();
if (errors_str != "") { if (errors_str != "") {
fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
errors_str.c_str()); errors_str.c_str());

File diff suppressed because it is too large Load diff

View file

@ -27,13 +27,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream> #include <stdio.h>
#include "gtest/gtest.h" #include "gtest/gtest.h"
GTEST_API_ int main(int argc, char **argv) { GTEST_API_ int main(int argc, char **argv) {
std::cout << "Running main() from gtest_main.cc\n"; printf("Running main() from gtest_main.cc\n");
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

View file

@ -68,10 +68,6 @@ typedef int ftnlen; // Fortran hidden string length type
// data file search path. // data file search path.
%(DARWIN)s %(DARWIN)s
// Identify whether the operating system is cygwin's overlay of
// windows, with gcc being used as the compiler.
%(CYGWIN)s
// Identify whether the operating system is Solaris // Identify whether the operating system is Solaris
// with a native compiler // with a native compiler
%(SOLARIS)s %(SOLARIS)s

View file

@ -1,7 +1,10 @@
#include "cantera/base/logger.h"
#include "cantera/thermo/ThermoPhase.h" #include "cantera/thermo/ThermoPhase.h"
#include "cantera/transport/TransportBase.h" #include "cantera/transport/TransportBase.h"
#include "cantera/kinetics/Kinetics.h" #include "cantera/kinetics/Kinetics.h"
#include "Python.h"
// Wrappers for preprocessor defines // Wrappers for preprocessor defines
std::string get_cantera_version() std::string get_cantera_version()
{ {
@ -13,6 +16,23 @@ int get_sundials_version()
return SUNDIALS_VERSION; return SUNDIALS_VERSION;
} }
class PythonLogger : public Cantera::Logger
{
public:
virtual void write(const std::string& s) {
// 1000 bytes is the maximum size permitted by PySys_WriteStdout
static const size_t N = 999;
for (size_t i = 0; i < s.size(); i+=N) {
PySys_WriteStdout("%s", s.substr(i, N).c_str());
}
}
virtual void error(const std::string& msg) {
std::string err = "raise Exception('''"+msg+"''')";
PyRun_SimpleString(err.c_str());
}
};
// Function which populates a 1D array // Function which populates a 1D array
#define ARRAY_FUNC(PREFIX, CLASS_NAME, FUNC_NAME) \ #define ARRAY_FUNC(PREFIX, CLASS_NAME, FUNC_NAME) \
void PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object, double* data) \ void PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object, double* data) \

View file

@ -156,7 +156,7 @@ class SpeciesThermo
public: public:
//! Constructor //! Constructor
SpeciesThermo() {} SpeciesThermo() : m_allow_discontinuities(false) {}
//! Destructor //! Destructor
virtual ~SpeciesThermo() {} virtual ~SpeciesThermo() {}
@ -333,6 +333,8 @@ public:
*/ */
virtual void modifyOneHf298(const int k, const doublereal Hf298New) = 0; virtual void modifyOneHf298(const int k, const doublereal Hf298New) = 0;
#endif #endif
bool m_allow_discontinuities;
}; };
//@} //@}
} }

View file

@ -120,6 +120,16 @@ public:
const XML_Node* const phaseNode_ptr); const XML_Node* const phaseNode_ptr);
//@} //@}
//! Initialize the internal shallow pointers in this object
/*!
* There are a bunch of internal shallow pointers that point to the owning
* VPStandardStateTP and SpeciesThermo objects. This function reinitializes
* them. This function is called like an onion.
*
* @param vp_ptr Pointer to the VPStandardStateTP standard state
* @param sp_ptr Pointer to the SpeciesThermo standard state
*/
virtual void initAllPtrs(VPStandardStateTP* vp_ptr, SpeciesThermo* sp_ptr);
private: private:
//! Shallow pointer to the water object //! Shallow pointer to the water object
PDSS_Water* m_waterSS; PDSS_Water* m_waterSS;

View file

@ -128,35 +128,41 @@ public:
//! Specific heat at constant volume [J/kg/K] //! Specific heat at constant volume [J/kg/K]
virtual double cv() { virtual double cv() {
double Tsave = T, dt = 1.e-4*T; double Tsave = T, dt = 1.e-4*T;
set_T(Tsave - dt); double T1 = std::max(Tmin(), Tsave - dt);
double T2 = std::min(Tmax(), Tsave + dt);
set_T(T1);
double s1 = s(); double s1 = s();
set_T(Tsave + dt); set_T(T2);
double s2 = s(); double s2 = s();
set_T(Tsave); set_T(Tsave);
return T*(s2 - s1)/(2.0*dt); return T*(s2 - s1)/(T2-T1);
} }
//! Specific heat at constant pressure [J/kg/K] //! Specific heat at constant pressure [J/kg/K]
virtual double cp() { virtual double cp() {
double Tsave = T, dt = 1.e-4*T; double Tsave = T, dt = 1.e-4*T;
double T1 = std::max(Tmin(), Tsave - dt);
double T2 = std::min(Tmax(), Tsave + dt);
double p0 = P(); double p0 = P();
Set(PropertyPair::TP, Tsave - dt, p0); Set(PropertyPair::TP, T1, p0);
double s1 = s(); double s1 = s();
Set(PropertyPair::TP, Tsave + dt, p0); Set(PropertyPair::TP, T2, p0);
double s2 = s(); double s2 = s();
Set(PropertyPair::TP, Tsave, p0); Set(PropertyPair::TP, Tsave, p0);
return T*(s2 - s1)/(2.0*dt); return T*(s2 - s1)/(T2-T1);
} }
virtual double thermalExpansionCoeff() { virtual double thermalExpansionCoeff() {
double Tsave = T, dt = 1.e-4*T; double Tsave = T, dt = 1.e-4*T;
double T1 = std::max(Tmin(), Tsave - dt);
double T2 = std::min(Tmax(), Tsave + dt);
double p0 = P(); double p0 = P();
Set(PropertyPair::TP, Tsave - dt, p0); Set(PropertyPair::TP, T1, p0);
double v1 = v(); double v1 = v();
Set(PropertyPair::TP, Tsave + dt, p0); Set(PropertyPair::TP, T2, p0);
double v2 = v(); double v2 = v();
Set(PropertyPair::TP, Tsave, p0); Set(PropertyPair::TP, Tsave, p0);
return (v2 - v1)/((v2 + v1)*dt); return (v2 - v1)/((v2 + v1)*(T2-T1));
} }
virtual double isothermalCompressibility() { virtual double isothermalCompressibility() {

View file

@ -6,7 +6,7 @@ Import('env', 'build', 'install')
localenv = env.Clone() localenv = env.Clone()
def configure_numpy(python_command): def configure_numpy(env, python_command):
script = '\n'.join(("from distutils.sysconfig import *", script = '\n'.join(("from distutils.sysconfig import *",
"import numpy", "import numpy",
"print(get_config_var('SO'))", "print(get_config_var('SO'))",
@ -17,7 +17,7 @@ def configure_numpy(python_command):
incDirs = (".", "../../include", numpy_include, incDirs = (".", "../../include", numpy_include,
localenv['sundials_include'], localenv['boost_inc_dir']) localenv['sundials_include'], localenv['boost_inc_dir'])
localenv['py_include_dirs'] = repr([x for x in incDirs if x]) env['py_include_dirs'] = repr([x for x in incDirs if x])
return module_ext, py_version return module_ext, py_version
@ -114,6 +114,7 @@ localenv['py_libdirs'] = repr([x for x in libDirs if x])
# unless otherwise specified # unless otherwise specified
localenv['py_extra_compiler_args'] = repr([]) localenv['py_extra_compiler_args'] = repr([])
localenv['py_extra_link_args'] = repr([]) localenv['py_extra_link_args'] = repr([])
compilerOpt = ''
if localenv['OS'] == 'Windows': if localenv['OS'] == 'Windows':
if env['CC'] == 'cl': if env['CC'] == 'cl':
flags = ['/EHsc'] flags = ['/EHsc']
@ -122,11 +123,9 @@ if localenv['OS'] == 'Windows':
localenv['py_extra_link_args'] = repr(['/DEBUG']) localenv['py_extra_link_args'] = repr(['/DEBUG'])
compilerOpt = ' --compiler=msvc' compilerOpt = ' --compiler=msvc'
localenv['py_extra_compiler_args'] = repr(flags) localenv['py_extra_compiler_args'] = repr(flags)
elif 'gcc' in env['CC']:
elif env['CC'] == 'gcc':
compilerOpt = ' --compiler=mingw32' compilerOpt = ' --compiler=mingw32'
else: else:
compilerOpt = ''
if '-fprofile-arcs' in localenv['CCFLAGS']: if '-fprofile-arcs' in localenv['CCFLAGS']:
localenv['py_extra_compiler_args'] = repr(['-fprofile-arcs', '-ftest-coverage']) localenv['py_extra_compiler_args'] = repr(['-fprofile-arcs', '-ftest-coverage'])
localenv['py_extra_link_args'] = repr(['-fprofile-arcs', '-ftest-coverage']) localenv['py_extra_link_args'] = repr(['-fprofile-arcs', '-ftest-coverage'])
@ -149,9 +148,10 @@ build(testFiles)
# Cython module for Python 3.x # Cython module for Python 3.x
if localenv['python3_package'] == 'y': if localenv['python3_package'] == 'y':
module_ext, py3_version = configure_numpy(localenv['python3_cmd']) py3env = localenv.Clone()
make_setup = localenv.SubstFile('#interfaces/cython/setup3.py', module_ext, py3_version = configure_numpy(py3env, py3env['python3_cmd'])
'#interfaces/cython/setup.py.in') make_setup = py3env.SubstFile('#interfaces/cython/setup3.py',
'#interfaces/cython/setup.py.in')
build(make_setup) build(make_setup)
build_base = ('cd interfaces/cython &&' build_base = ('cd interfaces/cython &&'
@ -161,26 +161,27 @@ if localenv['python3_package'] == 'y':
+ compilerOpt) + compilerOpt)
build_cmd = build_base % 'build' build_cmd = build_base % 'build'
ext = build(localenv.Command('#build/python3/cantera/_cantera%s' % module_ext, ext = build(py3env.Command('#build/python3/cantera/_cantera%s' % module_ext,
'setup3.py', 'setup3.py',
build_base % 'build_ext')) build_base % 'build_ext'))
mod = build(localenv.Command('#build/python3/cantera/__init__.py', mod = build(py3env.Command('#build/python3/cantera/__init__.py',
'setup3.py', 'setup3.py',
build_cmd)) build_cmd))
env['python3_module'] = mod env['python3_module'] = mod
env['python3_extension'] = ext env['python3_extension'] = ext
localenv.AddPreAction(ext, Delete('interfaces/cython/cantera/_cantera.cpp')) py3env.AddPreAction(ext, Delete('interfaces/cython/cantera/_cantera.cpp'))
add_dependencies(mod, ext) add_dependencies(mod, ext)
install_module(localenv['python3_prefix'], py3_version) install_module(py3env['python3_prefix'], py3_version)
# Cython module for Python 2.x # Cython module for Python 2.x
if localenv['python_package'] == 'new': if localenv['python_package'] == 'new':
module_ext, py2_version = configure_numpy(localenv['python_cmd']) py2env = localenv.Clone()
make_setup = localenv.SubstFile('#interfaces/cython/setup2.py', module_ext, py2_version = configure_numpy(py2env, py2env['python_cmd'])
'#interfaces/cython/setup.py.in') make_setup = py2env.SubstFile('#interfaces/cython/setup2.py',
'#interfaces/cython/setup.py.in')
build(make_setup) build(make_setup)
build_base = ('cd interfaces/cython &&' build_base = ('cd interfaces/cython &&'
@ -190,16 +191,16 @@ if localenv['python_package'] == 'new':
+ compilerOpt) + compilerOpt)
build_cmd = build_base % 'build' build_cmd = build_base % 'build'
ext = build(localenv.Command('#build/python2/cantera/_cantera%s' % module_ext, ext = build(py2env.Command('#build/python2/cantera/_cantera%s' % module_ext,
'setup2.py', 'setup2.py',
build_base % 'build_ext')) build_base % 'build_ext'))
mod = build(localenv.Command('#build/python2/cantera/__init__.py', mod = build(py2env.Command('#build/python2/cantera/__init__.py',
'setup2.py', 'setup2.py',
build_cmd)) build_cmd))
env['python2_module'] = mod env['python2_module'] = mod
env['python2_extension'] = ext env['python2_extension'] = ext
localenv.AddPreAction(ext, Delete('interfaces/cython/cantera/_cantera.cpp')) py2env.AddPreAction(ext, Delete('interfaces/cython/cantera/_cantera.cpp'))
# Use 3to2 to convert examples from Python 3 syntax # Use 3to2 to convert examples from Python 3 syntax
if env['python_convert_examples']: if env['python_convert_examples']:
@ -214,10 +215,10 @@ if localenv['python_package'] == 'new':
if not filename.endswith('.py'): if not filename.endswith('.py'):
continue continue
targetdir = '../../build/python2/cantera/examples' targetdir = '../../build/python2/cantera/examples'
a = build(localenv.Command(pjoin(targetdir, subdir, filename), a = build(py2env.Command(pjoin(targetdir, subdir, filename),
pjoin(dirpath, filename), pjoin(dirpath, filename),
convert_example)) convert_example))
localenv.Depends(a, mod) py2env.Depends(a, mod)
add_dependencies(mod, ext) add_dependencies(mod, ext)
install_module(localenv['python_prefix'], py2_version) install_module(py2env['python_prefix'], py2_version)

View file

@ -18,6 +18,7 @@ cdef extern from "cantera/base/ctml.h" namespace "ctml":
cdef extern from "cantera/base/global.h" namespace "Cantera": cdef extern from "cantera/base/global.h" namespace "Cantera":
cdef void CxxAddDirectory "Cantera::addDirectory" (string) cdef void CxxAddDirectory "Cantera::addDirectory" (string)
cdef size_t CxxNpos "Cantera::npos" cdef size_t CxxNpos "Cantera::npos"
cdef void CxxAppdelete "Cantera::appdelete" ()
cdef extern from "cantera/thermo/mix_defs.h": cdef extern from "cantera/thermo/mix_defs.h":
cdef int thermo_type_ideal_gas "Cantera::cIdealGas" cdef int thermo_type_ideal_gas "Cantera::cIdealGas"
@ -69,6 +70,7 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
size_t nElements() size_t nElements()
size_t elementIndex(string) except + size_t elementIndex(string) except +
string elementName(size_t) except + string elementName(size_t) except +
double atomicWeight(size_t) except +
# species properties # species properties
size_t nSpecies() size_t nSpecies()
@ -503,6 +505,11 @@ cdef extern from "cantera/cython/wrappers.h":
cdef string get_cantera_version() cdef string get_cantera_version()
cdef int get_sundials_version() cdef int get_sundials_version()
cdef cppclass CxxPythonLogger "PythonLogger":
pass
cdef void CxxSetLogger "setLogger" (CxxPythonLogger*)
# ThermoPhase composition # ThermoPhase composition
cdef void thermo_getMassFractions(CxxThermoPhase*, double*) except + cdef void thermo_getMassFractions(CxxThermoPhase*, double*) except +
cdef void thermo_setMassFractions(CxxThermoPhase*, double*) except + cdef void thermo_setMassFractions(CxxThermoPhase*, double*) except +
@ -718,7 +725,7 @@ cdef class ReactionPathDiagram:
cdef Kinetics kinetics cdef Kinetics kinetics
cdef str element cdef str element
cdef pybool built cdef pybool built
cdef CxxStringStream _log cdef CxxStringStream* _log
# free functions # free functions
cdef string stringify(x) cdef string stringify(x)

View file

@ -8,7 +8,7 @@ else:
from tkFileDialog import askopenfilename from tkFileDialog import askopenfilename
from cantera import * from cantera import *
import numpy as num import numpy as np
from .GraphFrame import Graph from .GraphFrame import Graph
from .DataGraph import DataGraph, plotLimits from .DataGraph import DataGraph, plotLimits
from .ControlPanel import make_menu from .ControlPanel import make_menu
@ -140,7 +140,7 @@ class DataFrame(Frame):
break break
nv = len(vv) nv = len(vv)
vars = vv vars = vv
fdata = zeros((nv, self.np),'d') fdata = np.zeros((nv, self.np),'d')
for n in range(self.np): for n in range(self.np):
v = string.split(lines[n+1],',') v = string.split(lines[n+1],',')
for j in range(nv): for j in range(nv):
@ -149,16 +149,16 @@ class DataFrame(Frame):
except: except:
fdata[j,n] = 0.0 fdata[j,n] = 0.0
self.nsp = self.g.nSpecies() self.nsp = self.g.n_species
self.y = zeros(self.nsp,'d') self.y = np.zeros(self.nsp,'d')
self.data = zeros((self.nsp+6,self.np),'d') self.data = np.zeros((self.nsp+6,self.np),'d')
self.data[0,:] = fdata[0,:] self.data[0,:] = fdata[0,:]
self.label = ['-']*(self.nsp+6) self.label = ['-']*(self.nsp+6)
self.label[0] = vars[0] self.label[0] = vars[0]
w = [] w = []
for n in range(1,nv-1): for n in range(1,nv-1):
try: try:
k = self.g.speciesIndex(vars[n]) k = self.g.species_index(vars[n])
except: except:
k = -1 k = -1
v2 = vars[n] v2 = vars[n]
@ -184,7 +184,7 @@ class DataFrame(Frame):
w.append((vars[n], self.newplot, 'check', self.loc, k + Y_LOC)) w.append((vars[n], self.newplot, 'check', self.loc, k + Y_LOC))
if self.data[P_LOC,0] == 0.0: if self.data[P_LOC,0] == 0.0:
self.data[P_LOC,:] = ones(self.np,'d')*OneAtm self.data[P_LOC,:] = np.ones(self.np,'d')*one_atm
print('Warning: no pressure data. P set to 1 atm.') print('Warning: no pressure data. P set to 1 atm.')
self.sc.config(cnf={'from':0,'to':self.np-1}) self.sc.config(cnf={'from':0,'to':self.np-1})
@ -214,10 +214,10 @@ class DataFrame(Frame):
if self.plt: if self.plt:
self.plt.destroy() self.plt.destroy()
self.nsp = self.g.nSpecies() self.nsp = self.g.n_species
self.label = ['-']*(self.nsp + 6) self.label = ['-']*(self.nsp + 6)
self.y = zeros(self.nsp,'d') self.y = np.zeros(self.nsp,'d')
gdata = self.soln.child('flowfield/grid_data') gdata = self.soln.child('flowfield/grid_data')
xp = self.soln.child('flowfield').children('float') xp = self.soln.child('flowfield').children('float')
p = 0.0 p = 0.0
@ -227,12 +227,12 @@ class DataFrame(Frame):
fa = gdata.children('floatArray') fa = gdata.children('floatArray')
self.np = int(fa[0]['size']) self.np = int(fa[0]['size'])
self.data = zeros((self.nsp+6,self.np),'d') self.data = np.zeros((self.nsp+6,self.np),'d')
w = [] w = []
for f in fa: for f in fa:
t = f['title'] t = f['title']
try: try:
k = self.g.speciesIndex(t) k = self.g.species_index(t)
except: except:
k = -1 k = -1
v = XML.getFloatArray(f) v = XML.getFloatArray(f)
@ -256,7 +256,7 @@ class DataFrame(Frame):
self.label[V_LOC] = t self.label[V_LOC] = t
w.append((t, self.newplot, 'check', self.loc, V_LOC)) w.append((t, self.newplot, 'check', self.loc, V_LOC))
self.data[P_LOC,:] = ones(self.np,'d')*p self.data[P_LOC,:] = np.ones(self.np,'d')*p
self.label[P_LOC] = 'P (Pa)' self.label[P_LOC] = 'P (Pa)'
self.sc.config(cnf={'from':0,'to':self.np-1}) self.sc.config(cnf={'from':0,'to':self.np-1})
if self.loc.get() <= 0: if self.loc.get() <= 0:
@ -301,7 +301,7 @@ class DataFrame(Frame):
if self.ydata[n] <= 0.0: if self.ydata[n] <= 0.0:
#print n, self.ydata[n] #print n, self.ydata[n]
self.ydata[n] = 1.0e-20 self.ydata[n] = 1.0e-20
self.ydata = num.log10(self.ydata) self.ydata = np.log10(self.ydata)
ylog = 1 ylog = 1
self.gdata = [] self.gdata = []

View file

@ -1,4 +1,10 @@
cdef class ReactionPathDiagram: cdef class ReactionPathDiagram:
def __cinit__(self, *args, **kwargs):
self._log = new CxxStringStream()
def __dealloc__(self):
del self._log
def __init__(self, Kinetics kin, str element): def __init__(self, Kinetics kin, str element):
""" """
Create a reaction path diagram for the fluxes of the element *element* Create a reaction path diagram for the fluxes of the element *element*
@ -6,7 +12,7 @@ cdef class ReactionPathDiagram:
*kin*. *kin*.
""" """
self.kinetics = kin self.kinetics = kin
self.builder.init(self._log, deref(kin.kinetics)) self.builder.init(deref(self._log), deref(kin.kinetics))
self.element = element self.element = element
self.built = False self.built = False
@ -163,7 +169,7 @@ cdef class ReactionPathDiagram:
return representations of the diagram, e.g. write_dot(). return representations of the diagram, e.g. write_dot().
""" """
self.builder.build(deref(self.kinetics.kinetics), self.builder.build(deref(self.kinetics.kinetics),
stringify(self.element), self._log, stringify(self.element), deref(self._log),
self.diagram, True) self.diagram, True)
self.built = True self.built = True
if verbose: if verbose:

View file

@ -18,3 +18,37 @@ class TestPureFluid(utilities.CanteraTest):
self.water.TX = 500, 0.8 self.water.TX = 500, 0.8
self.assertNear(self.water.T, 500) self.assertNear(self.water.T, 500)
self.assertNear(self.water.X, 0.8) self.assertNear(self.water.X, 0.8)
def test_set_minmax(self):
self.water.TP = self.water.min_temp, 101325
self.assertNear(self.water.T, self.water.min_temp)
self.water.TP = self.water.max_temp, 101325
self.assertNear(self.water.T, self.water.max_temp)
def check_fd_properties(self, T1, P1, T2, P2, tol):
# Properties which are computed as finite differences
self.water.TP = T1, P1
cp1 = self.water.cp_mass
cv1 = self.water.cv_mass
k1 = self.water.isothermal_compressibility
alpha1 = self.water.thermal_expansion_coeff
self.water.TP = T2, P2
cp2 = self.water.cp_mass
cv2 = self.water.cv_mass
k2 = self.water.isothermal_compressibility
alpha2 = self.water.thermal_expansion_coeff
self.assertNear(cp1, cp2, tol)
self.assertNear(cv1, cv2, tol)
self.assertNear(k1, k2, tol)
self.assertNear(alpha1, alpha2, tol)
def test_properties_near_min(self):
self.check_fd_properties(self.water.min_temp*(1+1e-5), 101325,
self.water.min_temp*(1+1e-4), 101325, 1e-2)
def test_properties_near_max(self):
self.check_fd_properties(self.water.max_temp*(1-1e-5), 101325,
self.water.max_temp*(1-1e-4), 101325, 1e-2)

View file

@ -175,6 +175,15 @@ cdef class ThermoPhase(_SolutionBase):
def __get__(self): def __get__(self):
return [self.element_name(m) for m in range(self.n_elements)] return [self.element_name(m) for m in range(self.n_elements)]
def atomic_weight(self, m):
"""Atomic weight [kg/kmol] of element *m*"""
return self.thermo.atomicWeight(self.element_index(m))
property atomic_weights:
"""Array of atomic weight [kg/kmol] for each element in the mixture."""
def __get__(self):
return np.array([self.thermo.atomicWeight(m) for m in range(self.n_elements)])
property n_species: property n_species:
"""Number of species.""" """Number of species."""
def __get__(self): def __get__(self):

View file

@ -1,6 +1,9 @@
import sys import sys
cdef int _pythonMajorVersion = sys.version_info[0] cdef int _pythonMajorVersion = sys.version_info[0]
cdef CxxPythonLogger* _logger = new CxxPythonLogger()
CxxSetLogger(_logger)
cdef string stringify(x): cdef string stringify(x):
""" Converts Python strings to std::string. """ """ Converts Python strings to std::string. """
# This method works with both Python 2.x and 3.x. # This method works with both Python 2.x and 3.x.
@ -24,3 +27,7 @@ def _have_sundials():
return bool(get_sundials_version()) return bool(get_sundials_version())
__version__ = pystr(get_cantera_version()) __version__ = pystr(get_cantera_version())
def appdelete():
""" Delete all global Cantera C++ objects """
CxxAppdelete()

View file

@ -58,6 +58,9 @@ nq = 0;
while length(property_argin) >= 2, while length(property_argin) >= 2,
prop = property_argin{1}; prop = property_argin{1};
val = property_argin{2}; val = property_argin{2};
if issparse(val)
val = full(val);
end
property_argin = property_argin(3:end); property_argin = property_argin(3:end);
switch prop switch prop
case 'Temperature' case 'Temperature'

View file

@ -29,7 +29,7 @@ function s = IdealGasMix(a,b,c)
% calls. If the initial call includes a transport database, then % calls. If the initial call includes a transport database, then
% the CTML file will contain transport data. % the CTML file will contain transport data.
% %
% See also: ck2ctml, Solution % See also: ck2cti, Solution
% %
dotloc = findstr(a,'.'); dotloc = findstr(a,'.');
if dotloc(end) > 1 if dotloc(end) > 1

View file

@ -1,45 +0,0 @@
function f = ck2ctml(infile, thermo, transport)
% CK2CTML - Convert a Chemkin-compatible reaction mechanism file to
% CTML.
%
% Cantera uses an XML-based file format (CTML) for specifying input
% parameters of any type, including specifying reaction mechanism
% attributes. This function reads a reaction mechanism file in "CK
% format" - the file format used by the Chemkin software package -
% and writes an equivalent description in CTML.
%
% f = ck2ctml('chem.inp')
% f = ck2ctml('chem.inp', 'therm.dat')
% f = ck2ctml('chem.inp', 'therm.dat', 'tran.dat')
%
% These 3 statements all create a CTML file 'chem.xml.' In the
% first case, the CK-format file contains all required species
% thermo data, while in the second case some or all thermo data is
% read from file 'therm.dat.' In the third form, the CTML file
% created will also contain transport property parameters. The
% function return value is a string containing the output file
% name.
%
if nargin == 0
error('input file name must be supplied')
elseif nargin == 1
thermo = '-';
transport = '-';
elseif nargin == 2
transport = '-';
end
dotloc = findstr(infile,'.');
if dotloc(end) > 1
idtag = infile(1:dotloc(end)-1);
outfile = [idtag '.xml'];
else
idtag = infile;
outfile = [infile '.xml'];
end
iok = ctmethods(0, 1, infile, thermo, transport, outfile, idtag);
if iok
error(geterr);
end
f = outfile;

View file

@ -39,6 +39,9 @@ import numpy as np
import re import re
import itertools import itertools
reFloat = re.compile(r'\+?\d*\.?\d+([eEdD][-+]?\d+)?$')
reInt = re.compile(r'\+?\d+$')
QUANTITY_UNITS = {'MOL': 'mol', QUANTITY_UNITS = {'MOL': 'mol',
'MOLE': 'mol', 'MOLE': 'mol',
'MOLES': 'mol', 'MOLES': 'mol',
@ -997,6 +1000,20 @@ class Parser(object):
return species, thermo, composition, note return species, thermo, composition, note
def setupKinetics(self):
# We look for species including the next permissible character. '\n' is
# appended to the reaction string to identify the last species in the
# reaction string. Checking this character is necessary to correctly
# identify species with names ending in '+' or '='.
self.species_tokens = set()
for next_char in ('<','=','(','+','\n'):
self.species_tokens.update(k + next_char for k in self.speciesDict)
self.other_tokens = {'M': 'third-body', 'm': 'third-body',
'(+M)': 'falloff3b', '(+m)': 'falloff3b',
'<=>': 'equal', '=>': 'equal', '=': 'equal'}
self.other_tokens.update(('(+%s)' % k, 'falloff3b: %s' % k) for k in self.speciesDict)
self.Slen = max(map(len, self.other_tokens))
def readKineticsEntry(self, entry): def readKineticsEntry(self, entry):
""" """
Read a kinetics `entry` for a single reaction as loaded from a Read a kinetics `entry` for a single reaction as loaded from a
@ -1033,20 +1050,58 @@ class Parser(object):
A = float(tokens[-3]) A = float(tokens[-3])
n = float(tokens[-2]) n = float(tokens[-2])
Ea = float(tokens[-1]) Ea = float(tokens[-1])
reaction = ''.join(tokens[:-3]) reaction = ''.join(tokens[:-3]) + '\n'
revReaction = None
# Split the reaction equation into reactants and products # Identify species tokens in the reaction expression in order of
if '<=>' in reaction: # decreasing length
reversible = True locs = {}
reactants, products = reaction.split('<=>') for i in range(self.Slen, 0, -1):
elif '=>' in reaction: for j in range(len(reaction)-i+1):
reversible = False test = reaction[j:j+i]
reactants, products = reaction.split('=>') if test in self.species_tokens:
elif '=' in reaction: reaction = reaction[:j] + ' '*(i-1) + reaction[j+i-1:]
reversible = True locs[j] = test[:-1], 'species'
reactants, products = reaction.split('=')
else: # Identify other tokens in the reaction expression in order of
# descending length
for i in range(self.Slen, 0, -1):
for j in range(len(reaction)-i+1):
test = reaction[j:j+i]
if test in self.other_tokens:
reaction = reaction[:j] + ' '*i + reaction[j+i:]
locs[j] = test, self.other_tokens[test]
# Anything that's left should be a stoichiometric coefficient or a '+'
# between species
for token in reaction.split():
j = reaction.find(token)
i = len(token)
reaction = reaction[:j] + ' '*i + reaction[j+i:]
if reInt.match(token):
locs[j] = int(token), 'coeff'
elif reFloat.match(token):
locs[j] = float(token), 'coeff'
elif token != '+':
raise InputParseError('Unexpected token "{0}" in reaction expression "{1}".'.format(token, reaction))
reactants = []
products = []
stoichiometry = 1
lhs = True
for token,kind in [v for k,v in sorted(locs.items())]:
if kind == 'equal':
reversible = token in ('<=>', '=')
lhs = False
elif kind == 'coeff':
stoichiometry = token
elif lhs:
reactants.append((stoichiometry,token,kind))
stoichiometry = 1
else:
products.append((stoichiometry,token,kind))
stoichiometry = 1
if lhs is True:
raise InputParseError("Failed to find reactant/product delimiter in reaction string.") raise InputParseError("Failed to find reactant/product delimiter in reaction string.")
# Create a new Reaction object for this reaction # Create a new Reaction object for this reaction
@ -1055,39 +1110,13 @@ class Parser(object):
def parseExpression(expression, dest): def parseExpression(expression, dest):
falloff3b = None falloff3b = None
thirdBody = False # simple third body reaction (non-falloff) thirdBody = False # simple third body reaction (non-falloff)
for stoichiometry,species,kind in expression:
# Look for third-body species for falloff reactions if kind == 'third-body':
if re.search(r'\(\+[Mm]\)', expression):
falloff3b = 'M'
expression = re.sub(r'(\(\+[Mm]\))', '', expression)
elif re.search(r'\(\+.*\)', expression):
# See if it matches a known species
for species in self.speciesDict:
if re.search(r'\(\+%s\)' % re.escape(species), expression):
falloff3b = species
expression = re.sub(r'(\(\+%s\))' % re.escape(species),
'', expression)
break
for term in expression.split('+'):
term = term.strip()
if term[0].isdigit() or term[0] == '.':
# This allows for for non-unity stoichiometric coefficients, e.g.
# 2A=B+C or .85A+.15B=>C
j = [i for i in range(len(term)) if isnumberlike(term[:i])][-1]
if term[:j].isdigit():
stoichiometry = int(term[:j])
else:
stoichiometry = float(term[:j])
species = term[j:]
else:
species = term
stoichiometry = 1
if species == 'M' or species == 'm':
thirdBody = True thirdBody = True
elif species not in self.speciesDict: elif kind == 'falloff3b':
raise InputParseError('Unexpected species "{0}" in reaction expression "{1}".'.format(species, expression)) falloff3b = 'M'
elif kind.startswith('falloff3b:'):
falloff3b = kind.split()[1]
else: else:
dest.append((stoichiometry, self.speciesDict[species])) dest.append((stoichiometry, self.speciesDict[species]))
@ -1116,7 +1145,6 @@ class Parser(object):
quantity_dim + 1, quantity_units) quantity_dim + 1, quantity_units)
# The rest of the first line contains Arrhenius parameters # The rest of the first line contains Arrhenius parameters
tokens = lines[0].split()[1:]
arrhenius = Arrhenius( arrhenius = Arrhenius(
A=(A,kunits), A=(A,kunits),
n=n, n=n,
@ -1336,14 +1364,13 @@ class Parser(object):
line, comment = readline() line, comment = readline()
advance = True advance = True
while line is not None: while line is not None:
tokens = line.split() tokens = line.split() or ['']
if contains(line, 'ELEMENTS'): if tokens[0].upper().startswith('ELEM'):
index = get_index(tokens, 'ELEMENTS') tokens = tokens[1:]
tokens = tokens[index+1:]
while line is not None and not contains(line, 'END'): while line is not None and not contains(line, 'END'):
# Grudging support for implicit end of section # Grudging support for implicit end of section
if contains(line, 'SPECIES'): if contains(line, 'SPEC'):
self.warn('"ELEMENTS" section implicitly ended by start of ' self.warn('"ELEMENTS" section implicitly ended by start of '
'next section on line {0}.'.format(self.line_number)) 'next section on line {0}.'.format(self.line_number))
advance = False advance = False
@ -1358,18 +1385,22 @@ class Parser(object):
break break
self.elements.append(token.capitalize()) self.elements.append(token.capitalize())
elif contains(line, 'SPECIES'): elif tokens[0].upper().startswith('SPEC'):
# List of species identifiers # List of species identifiers
index = get_index(tokens, 'SPECIES') tokens = tokens[1:]
tokens = tokens[index+1:]
while line is not None and not contains(line, 'END'): while line is not None and not contains(line, 'END'):
# Grudging support for implicit end of section # Grudging support for implicit end of section
if (contains(line, 'REACTIONS') or contains(line, 'TRAN') or if (contains(line, 'REAC') or contains(line, 'TRAN') or
contains(line, 'THERM')): contains(line, 'THER')):
self.warn('"SPECIES" section implicitly ended by start of ' self.warn('"SPECIES" section implicitly ended by start of '
'next section on line {0}.'.format(self.line_number)) 'next section on line {0}.'.format(self.line_number))
advance = False advance = False
tokens.pop() tokens.pop()
# Fix the case where there THERMO ALL or REAC UNITS
# ends the species section
if (tokens[-1].upper().startswith('THER') or
tokens[-1].upper().startswith('REAC')):
tokens.pop()
break break
line, comment = readline() line, comment = readline()
@ -1380,18 +1411,19 @@ class Parser(object):
break break
if token in self.speciesDict: if token in self.speciesDict:
species = self.speciesDict[token] species = self.speciesDict[token]
self.warn('Found additional declaration of species {0}'.format(species))
else: else:
species = Species(label=token) species = Species(label=token)
self.speciesDict[token] = species self.speciesDict[token] = species
self.speciesList.append(species) self.speciesList.append(species)
elif contains(line, 'THERM') and contains(line, 'NASA9'): elif tokens[0].upper().startswith('THER') and contains(line, 'NASA9'):
entryPosition = 0 entryPosition = 0
entryLength = None entryLength = None
entry = [] entry = []
while line is not None and not get_index(line, 'END') == 0: while line is not None and not get_index(line, 'END') == 0:
# Grudging support for implicit end of section # Grudging support for implicit end of section
if (contains(line, 'REACTIONS') or contains(line, 'TRAN')): if (contains(line, 'REAC') or contains(line, 'TRAN')):
self.warn('"THERMO" section implicitly ended by start of ' self.warn('"THERMO" section implicitly ended by start of '
'next section on line {0}.'.format(self.line_number)) 'next section on line {0}.'.format(self.line_number))
advance = False advance = False
@ -1440,7 +1472,7 @@ class Parser(object):
entryPosition += 1 entryPosition += 1
elif contains(line, 'THERM'): elif tokens[0].upper().startswith('THER'):
# List of thermodynamics (hopefully one per species!) # List of thermodynamics (hopefully one per species!)
line, comment = readline() line, comment = readline()
if line is not None and not contains(line, 'END'): if line is not None and not contains(line, 'END'):
@ -1448,7 +1480,7 @@ class Parser(object):
thermo = [] thermo = []
while line is not None and not contains(line, 'END'): while line is not None and not contains(line, 'END'):
# Grudging support for implicit end of section # Grudging support for implicit end of section
if contains(line, 'REACTIONS') or contains(line, 'TRAN'): if contains(line, 'REAC') or contains(line, 'TRAN'):
self.warn('"THERMO" section implicitly ended by start of ' self.warn('"THERMO" section implicitly ended by start of '
'next section on line {0}.'.format(self.line_number)) 'next section on line {0}.'.format(self.line_number))
advance = False advance = False
@ -1473,7 +1505,7 @@ class Parser(object):
thermo = [] thermo = []
line, comment = readline() line, comment = readline()
elif contains(line, 'REACTIONS'): elif tokens[0].upper().startswith('REAC'):
# Reactions section # Reactions section
for token in tokens[1:]: for token in tokens[1:]:
@ -1556,11 +1588,12 @@ class Parser(object):
if len(kineticsList) != len(commentsList): if len(kineticsList) != len(commentsList):
commentsList = ['' for kinetics in kineticsList] commentsList = ['' for kinetics in kineticsList]
self.setupKinetics()
for kinetics, comments, line_number in zip(kineticsList, commentsList, startLines): for kinetics, comments, line_number in zip(kineticsList, commentsList, startLines):
try: try:
reaction,revReaction = self.readKineticsEntry(kinetics) reaction,revReaction = self.readKineticsEntry(kinetics)
except Exception as e: except Exception as e:
print('Error reading reaction entry starting on line {0}:'.format(line_number)) logging.error('Error reading reaction entry starting on line {0}:'.format(line_number))
raise raise
reaction.line_number = line_number reaction.line_number = line_number
self.reactions.append(reaction) self.reactions.append(reaction)
@ -1568,11 +1601,11 @@ class Parser(object):
revReaction.line_number = line_number revReaction.line_number = line_number
self.reactions.append(revReaction) self.reactions.append(revReaction)
elif contains(line, 'TRAN'): elif tokens[0].upper().startswith('TRAN'):
line, comment = readline() line, comment = readline()
while line is not None and not contains(line, 'END'): while line is not None and not contains(line, 'END'):
# Grudging support for implicit end of section # Grudging support for implicit end of section
if contains(line, 'REACTIONS'): if contains(line, 'REAC'):
self.warn('"TRANSPORT" section implicitly ended by start of ' self.warn('"TRANSPORT" section implicitly ended by start of '
'next section on line {0}.'.format(self.line_number)) 'next section on line {0}.'.format(self.line_number))
advance = False advance = False
@ -1757,6 +1790,8 @@ duplicate transport data) to be ignored.
outName=None, quiet=False, permissive=None): outName=None, quiet=False, permissive=None):
if quiet: if quiet:
logging.basicConfig(level=logging.ERROR) logging.basicConfig(level=logging.ERROR)
else:
logging.basicConfig(level=logging.INFO)
if permissive is not None: if permissive is not None:
self.warning_as_error = not permissive self.warning_as_error = not permissive
@ -1765,16 +1800,16 @@ duplicate transport data) to be ignored.
# Read input mechanism files # Read input mechanism files
self.loadChemkinFile(inputFile) self.loadChemkinFile(inputFile)
except Exception: except Exception:
print("\nERROR: Unable to parse '{0}' near line {1}:\n".format( logging.warning("\nERROR: Unable to parse '{0}' near line {1}:\n".format(
inputFile, self.line_number)) inputFile, self.line_number))
raise raise
if thermoFile: if thermoFile:
try: try:
self.loadChemkinFile(thermoFile) self.loadChemkinFile(thermoFile)
except Exception: except Exception:
print("\nERROR: Unable to parse '{0}' near line {1}:\n".format( logging.warning("\nERROR: Unable to parse '{0}' near line {1}:\n".format(
thermoFile, self.line_number)) thermoFile, self.line_number))
raise raise
if transportFile: if transportFile:

View file

@ -489,6 +489,8 @@ class species(object):
The atomic composition, specified by a string containing The atomic composition, specified by a string containing
space-delimited <element>:<atoms> pairs. The number of atoms may be space-delimited <element>:<atoms> pairs. The number of atoms may be
either an integer or a floating-point number. either an integer or a floating-point number.
:param note:
A user-defined comment. Not evaluated by Cantera itself.
:param thermo: :param thermo:
The parameterization to use to compute the reference-state The parameterization to use to compute the reference-state
thermodynamic properties. This must be one of the entry types thermodynamic properties. This must be one of the entry types
@ -1603,6 +1605,7 @@ class phase(object):
dim = 3, dim = 3,
elements = '', elements = '',
species = '', species = '',
note = '',
reactions = 'none', reactions = 'none',
initial_state = None, initial_state = None,
options = []): options = []):
@ -1615,6 +1618,8 @@ class phase(object):
:param species: :param species:
The species. A string or sequence of strings in the format The species. A string or sequence of strings in the format
described in :ref:`sec-defining-species`. described in :ref:`sec-defining-species`.
:param note:
A user-defined comment. Not evaluated by Cantera itself.
:param reactions: :param reactions:
The homogeneous reactions. If omitted, no reactions will be The homogeneous reactions. If omitted, no reactions will be
included. A string or sequence of strings in the format described included. A string or sequence of strings in the format described
@ -1637,6 +1642,7 @@ class phase(object):
self._el = elements self._el = elements
self._sp = [] self._sp = []
self._rx = [] self._rx = []
self._comment = note
if isinstance(options, str): if isinstance(options, str):
self._options = [options] self._options = [options]
@ -1800,6 +1806,14 @@ class phase(object):
#self._eos.build(ph) #self._eos.build(ph)
if self._initial: if self._initial:
self._initial.build(ph) self._initial.build(ph)
if self._comment:
ph.addChild('note',self._comment)
thermo = ph.addChild('thermo')
if 'allow_discontinuous_thermo' in self._options:
thermo['allow_discontinuities'] = 'true'
return ph return ph
@ -1809,6 +1823,7 @@ class ideal_gas(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
reactions = 'none', reactions = 'none',
kinetics = 'GasKinetics', kinetics = 'GasKinetics',
transport = 'None', transport = 'None',
@ -1827,7 +1842,7 @@ class ideal_gas(phase):
``'multi'``, or ``'mix'``. Default: ``'none'``. ``'multi'``, or ``'mix'``. Default: ``'none'``.
""" """
phase.__init__(self, name, 3, elements, species, reactions, phase.__init__(self, name, 3, elements, species, note, reactions,
initial_state, options) initial_state, options)
self._pure = 0 self._pure = 0
self._kin = kinetics self._kin = kinetics
@ -1843,8 +1858,7 @@ class ideal_gas(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") ph.child('thermo')['model'] = 'IdealGas'
e['model'] = 'IdealGas'
k = ph.addChild("kinetics") k = ph.addChild("kinetics")
k['model'] = self._kin k['model'] = self._kin
t = ph.addChild('transport') t = ph.addChild('transport')
@ -1865,6 +1879,7 @@ class stoichiometric_solid(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
density = None, density = None,
transport = 'None', transport = 'None',
initial_state = None, initial_state = None,
@ -1873,7 +1888,7 @@ class stoichiometric_solid(phase):
See :class:`.phase` for descriptions of the parameters. See :class:`.phase` for descriptions of the parameters.
""" """
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._dens = density self._dens = density
self._pure = 1 self._pure = 1
@ -1888,7 +1903,7 @@ class stoichiometric_solid(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child('thermo')
e['model'] = 'StoichSubstance' e['model'] = 'StoichSubstance'
addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3') addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3')
if self._tr: if self._tr:
@ -1907,6 +1922,7 @@ class stoichiometric_liquid(stoichiometric_solid):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
density = -1.0, density = -1.0,
transport = 'None', transport = 'None',
initial_state = None, initial_state = None,
@ -1915,7 +1931,7 @@ class stoichiometric_liquid(stoichiometric_solid):
See :class:`.phase` for descriptions of the parameters. See :class:`.phase` for descriptions of the parameters.
""" """
stoichiometric_solid.__init__(self, name, elements, stoichiometric_solid.__init__(self, name, elements,
species, density, transport, species, note, density, transport,
initial_state, options) initial_state, options)
@ -1925,12 +1941,13 @@ class metal(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
density = -1.0, density = -1.0,
transport = 'None', transport = 'None',
initial_state = None, initial_state = None,
options = []): options = []):
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._dens = density self._dens = density
self._pure = 0 self._pure = 0
@ -1941,7 +1958,7 @@ class metal(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'Metal' e['model'] = 'Metal'
addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3') addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3')
if self._tr: if self._tr:
@ -1956,6 +1973,7 @@ class semiconductor(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
density = -1.0, density = -1.0,
bandgap = 1.0 * eV, bandgap = 1.0 * eV,
effectiveMass_e = 1.0 * ElectronMass, effectiveMass_e = 1.0 * ElectronMass,
@ -1964,7 +1982,7 @@ class semiconductor(phase):
initial_state = None, initial_state = None,
options = []): options = []):
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._dens = density self._dens = density
self._pure = 0 self._pure = 0
@ -1978,7 +1996,7 @@ class semiconductor(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'Semiconductor' e['model'] = 'Semiconductor'
addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3') addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3')
addFloat(e, 'effectiveMass_e', self._emass, defunits = _umass) addFloat(e, 'effectiveMass_e', self._emass, defunits = _umass)
@ -1997,12 +2015,13 @@ class incompressible_solid(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
density = -1.0, density = -1.0,
transport = 'None', transport = 'None',
initial_state = None, initial_state = None,
options = []): options = []):
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._dens = density self._dens = density
self._pure = 0 self._pure = 0
@ -2015,7 +2034,7 @@ class incompressible_solid(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'Incompressible' e['model'] = 'Incompressible'
addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3') addFloat(e, 'density', self._dens, defunits = _umass+'/'+_ulen+'3')
if self._tr: if self._tr:
@ -2026,16 +2045,18 @@ class incompressible_solid(phase):
class lattice(phase): class lattice(phase):
def __init__(self, name = '', def __init__(self,
name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
reactions = 'none', reactions = 'none',
transport = 'None', transport = 'None',
initial_state = None, initial_state = None,
options = [], options = [],
site_density = -1.0, site_density = -1.0,
vacancy_species = ''): vacancy_species = ''):
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._tr = transport self._tr = transport
self._n = site_density self._n = site_density
@ -2053,7 +2074,7 @@ class lattice(phase):
#if visible == 0: #if visible == 0:
# return # return
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild('thermo') e = ph.child('thermo')
e['model'] = 'Lattice' e['model'] = 'Lattice'
addFloat(e, 'site_density', self._n, defunits = _umol+'/'+_ulen+'3') addFloat(e, 'site_density', self._n, defunits = _umol+'/'+_ulen+'3')
if self._vac: if self._vac:
@ -2070,6 +2091,7 @@ class lattice_solid(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
lattices = [], lattices = [],
transport = 'None', transport = 'None',
initial_state = None, initial_state = None,
@ -2096,7 +2118,7 @@ class lattice_solid(phase):
slist.append(sp) slist.append(sp)
species = ' '.join(slist) species = ' '.join(slist)
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._lattices = lattices self._lattices = lattices
if lattices == []: if lattices == []:
@ -2109,7 +2131,7 @@ class lattice_solid(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'LatticeSolid' e['model'] = 'LatticeSolid'
if self._lattices: if self._lattices:
@ -2136,11 +2158,12 @@ class liquid_vapor(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
substance_flag = 0, substance_flag = 0,
initial_state = None, initial_state = None,
options = []): options = []):
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._subflag = substance_flag self._subflag = substance_flag
self._pure = 1 self._pure = 1
@ -2151,7 +2174,7 @@ class liquid_vapor(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'PureFluid' e['model'] = 'PureFluid'
e['fluid_type'] = repr(self._subflag) e['fluid_type'] = repr(self._subflag)
k = ph.addChild("kinetics") k = ph.addChild("kinetics")
@ -2165,12 +2188,13 @@ class RedlichKwongMFTP(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
initial_state = None, initial_state = None,
activity_coefficients = None, activity_coefficients = None,
transport = 'None', transport = 'None',
options = []): options = []):
phase.__init__(self,name, 3, elements, species, 'none', phase.__init__(self,name, 3, elements, species, note, 'none',
initial_state,options) initial_state,options)
self._pure = 0 self._pure = 0
self._tr = transport self._tr = transport
@ -2181,7 +2205,7 @@ class RedlichKwongMFTP(phase):
def build(self, p): def build(self, p):
ph = phase.build(self,p) ph = phase.build(self,p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'RedlichKwongMFTP' e['model'] = 'RedlichKwongMFTP'
if self._activityCoefficients: if self._activityCoefficients:
a = e.addChild("activityCoefficients") a = e.addChild("activityCoefficients")
@ -2210,13 +2234,14 @@ class redlich_kwong(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
substance_flag = 7, substance_flag = 7,
initial_state = None, initial_state = None,
Tcrit = 1.0, Tcrit = 1.0,
Pcrit = 1.0, Pcrit = 1.0,
options = []): options = []):
phase.__init__(self, name, 3, elements, species, 'none', phase.__init__(self, name, 3, elements, species, note, 'none',
initial_state, options) initial_state, options)
self._subflag = 7 self._subflag = 7
self._pure = 1 self._pure = 1
@ -2228,7 +2253,7 @@ class redlich_kwong(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'PureFluid' e['model'] = 'PureFluid'
e['fluid_type'] = repr(self._subflag) e['fluid_type'] = repr(self._subflag)
addFloat(e, 'Tc', self._tc, defunits = "K") addFloat(e, 'Tc', self._tc, defunits = "K")
@ -2245,6 +2270,7 @@ class ideal_interface(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
reactions = 'none', reactions = 'none',
site_density = 0.0, site_density = 0.0,
phases = [], phases = [],
@ -2267,7 +2293,7 @@ class ideal_interface(phase):
at this interface. at this interface.
""" """
self._type = 'surface' self._type = 'surface'
phase.__init__(self, name, 2, elements, species, reactions, phase.__init__(self, name, 2, elements, species, note, reactions,
initial_state, options) initial_state, options)
self._pure = 0 self._pure = 0
self._kin = kinetics self._kin = kinetics
@ -2277,7 +2303,7 @@ class ideal_interface(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'Surface' e['model'] = 'Surface'
addFloat(e, 'site_density', self._sitedens, defunits = _umol+'/'+_ulen+'2') addFloat(e, 'site_density', self._sitedens, defunits = _umol+'/'+_ulen+'2')
k = ph.addChild("kinetics") k = ph.addChild("kinetics")
@ -2297,6 +2323,7 @@ class edge(phase):
name = '', name = '',
elements = '', elements = '',
species = '', species = '',
note = '',
reactions = 'none', reactions = 'none',
site_density = 0.0, site_density = 0.0,
phases = [], phases = [],
@ -2306,7 +2333,7 @@ class edge(phase):
options = []): options = []):
self._type = 'edge' self._type = 'edge'
phase.__init__(self, name, 1, elements, species, reactions, phase.__init__(self, name, 1, elements, species, note, reactions,
initial_state, options) initial_state, options)
self._pure = 0 self._pure = 0
self._kin = kinetics self._kin = kinetics
@ -2316,7 +2343,7 @@ class edge(phase):
def build(self, p): def build(self, p):
ph = phase.build(self, p) ph = phase.build(self, p)
e = ph.addChild("thermo") e = ph.child("thermo")
e['model'] = 'Edge' e['model'] = 'Edge'
addFloat(e, 'site_density', self._sitedens, defunits = _umol+'/'+_ulen) addFloat(e, 'site_density', self._sitedens, defunits = _umol+'/'+_ulen)
k = ph.addChild("kinetics") k = ph.addChild("kinetics")
@ -2433,6 +2460,7 @@ class edge(phase):
## name = '', ## name = '',
## elements = '', ## elements = '',
## species = '', ## species = '',
## note = '',
## transport = 'None', ## transport = 'None',
## initial_state = None, ## initial_state = None,
## solvent = '', ## solvent = '',
@ -2440,7 +2468,7 @@ class edge(phase):
## activity_coefficients = None, ## activity_coefficients = None,
## options = []): ## options = []):
## phase.__init__(self, name, 3, elements, species, 'none', ## phase.__init__(self, name, 3, elements, species, note, 'none',
## initial_state, options) ## initial_state, options)
## self._pure = 0 ## self._pure = 0
## self._solvent = solvent ## self._solvent = solvent
@ -2451,7 +2479,7 @@ class edge(phase):
## def build(self, p): ## def build(self, p):
## ph = phase.build(self, p) ## ph = phase.build(self, p)
## e = ph.addChild("thermo") ## e = ph.child("thermo")
## sc = e.addChild("standardConc") ## sc = e.addChild("standardConc")
## sc['model'] = self._stdconc ## sc['model'] = self._stdconc
## e['model'] = 'HMW' ## e['model'] = 'HMW'

View file

@ -20,9 +20,9 @@ comp2 = 'C2H6:1'; % fuel composition
initial_grid = 0.02*[0.0 0.2 0.4 0.6 0.8 1.0]; % m initial_grid = 0.02*[0.0 0.2 0.4 0.6 0.8 1.0]; % m
tol_ss = [1.0e-5 1.0e-12]; % [rtol atol] for steady-state tol_ss = [1.0e-5 1.0e-13]; % [rtol atol] for steady-state
% problem % problem
tol_ts = [1.0e-3 1.0e-4]; % [rtol atol] for time stepping tol_ts = [1.0e-4 1.0e-13]; % [rtol atol] for time stepping
loglevel = 1; % amount of diagnostic output (0 loglevel = 1; % amount of diagnostic output (0
% to 5) % to 5)

View file

@ -76,7 +76,7 @@ class WxsGenerator(object):
UpgradeCode='2340BEE1-279D-11E1-A4AA-001FBC085391', UpgradeCode='2340BEE1-279D-11E1-A4AA-001FBC085391',
Language='1033', Language='1033',
Codepage='1252', Codepage='1252',
Version='2.1.0', Version='2.1.1',
Manufacturer='Cantera Developers')) Manufacturer='Cantera Developers'))
fields = {'Platform': 'x64'} if self.x64 else {} fields = {'Platform': 'x64'} if self.x64 else {}

View file

@ -56,7 +56,7 @@ install('$inst_libdir', lib)
env['cantera_staticlib'] = lib env['cantera_staticlib'] = lib
# Windows and OS X require shared libraries at link time # Windows and OS X require shared libraries at link time
if localenv['OS'] in ('Darwin', 'Windows'): if localenv['OS'] in ('Darwin', 'Windows', 'Cygwin'):
localenv.Append(LIBS=localenv['FORTRANSYSLIBS']) localenv.Append(LIBS=localenv['FORTRANSYSLIBS'])
if (localenv['use_sundials'] == 'y'): if (localenv['use_sundials'] == 'y'):
localenv.Append(LIBS=localenv['sundials_libs'], localenv.Append(LIBS=localenv['sundials_libs'],
@ -64,9 +64,9 @@ if localenv['OS'] in ('Darwin', 'Windows'):
if localenv['blas_lapack_libs']: if localenv['blas_lapack_libs']:
localenv.Append(LIBS=localenv['blas_lapack_libs'], localenv.Append(LIBS=localenv['blas_lapack_libs'],
LIBPATH=localenv['blas_lapack_dir']) LIBPATH=localenv['blas_lapack_dir'])
if localenv['boost_libs']:
if localenv['toolchain'] == 'mingw': localenv.Append(LIBS=localenv['boost_libs'],
localenv.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++']) LIBPATH=localenv['boost_lib_dir'])
# Build the Cantera shared library using the correct name # Build the Cantera shared library using the correct name
if localenv['layout'] != 'debian': if localenv['layout'] != 'debian':

View file

@ -23,6 +23,7 @@
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include "cantera/base/config.h" #include "cantera/base/config.h"
#ifndef _MSC_VER #ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>

View file

@ -32,7 +32,7 @@ namespace Cantera {
void checkFinite(const double tmp) void checkFinite(const double tmp)
{ {
#ifdef _WIN32 #if defined _WIN32
if (_finite(tmp)) { if (_finite(tmp)) {
if (_isnan(tmp)) { if (_isnan(tmp)) {
printf("checkFinite() ERROR: we have encountered a nan!\n"); printf("checkFinite() ERROR: we have encountered a nan!\n");
@ -43,6 +43,17 @@ void checkFinite(const double tmp)
} }
throw std::range_error("checkFinite()"); throw std::range_error("checkFinite()");
} }
#elif defined __CYGWIN__
if (!finite(tmp)) {
if (isnan(tmp)) {
printf("checkFinite() ERROR: we have encountered a nan!\n");
} else if (isinf(tmp) == 1) {
printf("checkFinite() ERROR: we have encountered a pos inf!\n");
} else {
printf("checkFinite() ERROR: we have encountered a neg inf!\n");
}
throw std::range_error("checkFinite()");
}
#else #else
if (!::finite(tmp)) { if (!::finite(tmp)) {
if (::isnan(tmp)) { if (::isnan(tmp)) {

View file

@ -11,6 +11,7 @@ artifacts = localenv.Object(f90_src,
F90PATH=['#build/src/fortran']) F90PATH=['#build/src/fortran'])
mods = [o for o in artifacts if o.path.endswith('.mod')] mods = [o for o in artifacts if o.path.endswith('.mod')]
objects = [o for o in artifacts if not o.path.endswith('.mod')] objects = [o for o in artifacts if not o.path.endswith('.mod')]
localenv.Depends(objects, localenv['config_h_target'])
lib = build(localenv.Library(target=pjoin('..','..','lib','cantera_fortran'), lib = build(localenv.Library(target=pjoin('..','..','lib','cantera_fortran'),
source=objects)) source=objects))

View file

@ -311,17 +311,16 @@ void ReactionPathDiagram::exportToDot(ostream& s)
node(kend)->visible = true; node(kend)->visible = true;
s << "s" << kbegin << " -> s" << kend; s << "s" << kbegin << " -> s" << kend;
s << "[fontname=\""+m_font+"\", style=\"setlinewidth(";
if (arrow_width < 0) { if (arrow_width < 0) {
lwidth = 1.0 - 4.0 lwidth = 1.0 - 4.0
* log10(flxratio/threshold)/log10(threshold) + 1.0; * log10(flxratio/threshold)/log10(threshold) + 1.0;
s << "[fontname=\""+m_font+"\", style=\"setlinewidth(" s << lwidth << ")\"";
<< lwidth << ")\"";
s << ", arrowsize=" s << ", arrowsize="
<< std::min(6.0, 0.5*lwidth); << std::min(6.0, 0.5*lwidth);
} else { } else {
s << ", style=\"setlinewidth(" s << arrow_width << ")\"";
<< arrow_width << ")\"";
s << ", arrowsize=" << flxratio + 1; s << ", arrowsize=" << flxratio + 1;
} }

View file

@ -25,7 +25,6 @@ if localenv['OS'] == 'Windows':
linkflags.append('/MACHINE:' + machtype) linkflags.append('/MACHINE:' + machtype)
elif localenv['CC'] == 'gcc': elif localenv['CC'] == 'gcc':
linkflags.append('-Wl,--export-all-symbols') linkflags.append('-Wl,--export-all-symbols')
linkflags.extend(['-static-libgcc', '-static-libstdc++'])
elif localenv['OS'] == 'Darwin': elif localenv['OS'] == 'Darwin':
linklibs = list(env['cantera_libs']) linklibs = list(env['cantera_libs'])

View file

@ -24,7 +24,7 @@ void kineticsmethods(int nlhs, mxArray* plhs[],
int in2 = getInt(prhs[5]); int in2 = getInt(prhs[5]);
int in3 = getInt(prhs[6]); int in3 = getInt(prhs[6]);
int in4 = getInt(prhs[7]); int in4 = getInt(prhs[7]);
vv = (double) newKineticsFromXML(root, iph, in1, in2, in3, in4); vv = static_cast<int>(newKineticsFromXML(root, iph, in1, in2, in3, in4));
plhs[0] = mxCreateNumericMatrix(1,1,mxDOUBLE_CLASS,mxREAL); plhs[0] = mxCreateNumericMatrix(1,1,mxDOUBLE_CLASS,mxREAL);
double* h = mxGetPr(plhs[0]); double* h = mxGetPr(plhs[0]);
*h = vv; *h = vv;

View file

@ -43,6 +43,7 @@ void transportmethods(int nlhs, mxArray* plhs[],
break; break;
case 2: case 2:
vv = trans_thermalConductivity(n); vv = trans_thermalConductivity(n);
break;
case 3: case 3:
vv = trans_electricalConductivity(n); vv = trans_electricalConductivity(n);
break; break;

View file

@ -81,7 +81,8 @@ MetalSHEelectrons::MetalSHEelectrons(XML_Node& xmlphase, const std::string& id_)
} }
MetalSHEelectrons::MetalSHEelectrons(const MetalSHEelectrons& right) : MetalSHEelectrons::MetalSHEelectrons(const MetalSHEelectrons& right) :
SingleSpeciesTP() SingleSpeciesTP(),
xdef_(0)
{ {
operator=(right); operator=(right);
} }
@ -99,7 +100,10 @@ MetalSHEelectrons::operator=(const MetalSHEelectrons& right)
} }
delete xdef_; delete xdef_;
xdef_ = new XML_Node(*right.xdef_); if(right.xdef_)
{
xdef_ = new XML_Node(*right.xdef_);
}
return *this; return *this;
} }

View file

@ -82,11 +82,13 @@ void NasaThermo::install(const std::string& name, size_t index, int type,
vector_fp chigh(c+8, c+15); vector_fp chigh(c+8, c+15);
vector_fp clow(c+1, c+8); vector_fp clow(c+1, c+8);
doublereal maxError = checkContinuity(name, tmid, &clow[0], &chigh[0]); if (!m_allow_discontinuities) {
if (maxError > 1e-6) { doublereal maxError = checkContinuity(name, tmid, &clow[0], &chigh[0]);
fixDiscontinuities(tlow, tmid, thigh, &clow[0], &chigh[0]); if (maxError > 1e-6) {
AssertThrowMsg(checkContinuity(name, tmid, &clow[0], &chigh[0]) < 1e-12, fixDiscontinuities(tlow, tmid, thigh, &clow[0], &chigh[0]);
"NasaThermo::install", "Polynomials still not continuous"); AssertThrowMsg(checkContinuity(name, tmid, &clow[0], &chigh[0]) < 1e-12,
"NasaThermo::install", "Polynomials still not continuous");
}
} }
m_high[igrp-1].push_back(NasaPoly1(index, tmid, thigh, m_high[igrp-1].push_back(NasaPoly1(index, tmid, thigh,

View file

@ -434,8 +434,8 @@ bool importPhase(XML_Node& phase, ThermoPhase* th,
// Set equation of state parameters. The parameters are // Set equation of state parameters. The parameters are
// specific to each subclass of ThermoPhase, so this is done // specific to each subclass of ThermoPhase, so this is done
// by method setParametersFromXML in each subclass. // by method setParametersFromXML in each subclass.
const XML_Node& eos = phase.child("thermo");
if (phase.hasChild("thermo")) { if (phase.hasChild("thermo")) {
const XML_Node& eos = phase.child("thermo");
th->setParametersFromXML(eos); th->setParametersFromXML(eos);
} else { } else {
throw CanteraError("importPhase", throw CanteraError("importPhase",
@ -561,6 +561,10 @@ bool importPhase(XML_Node& phase, ThermoPhase* th,
// used, and selects a class that can handle the // used, and selects a class that can handle the
// parameterizations found. // parameterizations found.
spth = newSpeciesThermoMgr(spDataNodeList); spth = newSpeciesThermoMgr(spDataNodeList);
if (eos["allow_discontinuities"] == "true") {
std::cout << "ALLOWING DISCONTINUOUS THERMO!" << std::endl;
spth->m_allow_discontinuities = true;
}
// install it in the phase object // install it in the phase object
th->setSpeciesThermo(spth); th->setSpeciesThermo(spth);

View file

@ -966,8 +966,8 @@ std::string ThermoPhase::report(bool show_thermo) const
s += p; s += p;
} }
} else { } else {
sprintf(p, " \n X" sprintf(p, " \n X "
"Y\n"); " Y\n");
s += p; s += p;
sprintf(p, " -------------" sprintf(p, " -------------"
" ------------\n"); " ------------\n");

View file

@ -299,6 +299,18 @@ VPSSMgr_Water_HKFT::createInstallPDSS(size_t k, const XML_Node& speciesNode,
return kPDSS; return kPDSS;
} }
void
VPSSMgr_Water_HKFT::initAllPtrs(VPStandardStateTP* vp_ptr,
SpeciesThermo* sp_ptr)
{
VPSSMgr::initAllPtrs(vp_ptr, sp_ptr);
m_waterSS = dynamic_cast<PDSS_Water*>(m_vptp_ptr->providePDSS(0));
if (!m_waterSS) {
throw CanteraError("VPSSMgr_Water_ConstVol::initAllPtrs",
"bad dynamic cast");
}
}
PDSS_enumType VPSSMgr_Water_HKFT::reportPDSSType(int k) const PDSS_enumType VPSSMgr_Water_HKFT::reportPDSSType(int k) const
{ {
return cPDSS_UNDEF; return cPDSS_UNDEF;

View file

@ -5,6 +5,7 @@
*/ */
#include "cantera/tpx/Sub.h" #include "cantera/tpx/Sub.h"
#include "cantera/base/stringUtils.h" #include "cantera/base/stringUtils.h"
#include "cantera/base/global.h"
using std::string; using std::string;
using namespace Cantera; using namespace Cantera;
@ -35,9 +36,9 @@ double Substance::dPsdT()
{ {
double tsave = T; double tsave = T;
double ps1 = Ps(); double ps1 = Ps();
set_T(T + DeltaT); T = T + DeltaT;
double dpdt = (Ps() - ps1)/DeltaT; double dpdt = (Ps() - ps1)/DeltaT;
set_T(tsave); T = tsave;
return dpdt; return dpdt;
} }
@ -387,7 +388,7 @@ int Substance::Lever(int itp, double sat, double val, propertyFlag::type ifunc)
if (sat >= Tcrit()) { if (sat >= Tcrit()) {
return 0; return 0;
} }
set_T(sat); T = sat;
psat = Ps(); psat = Ps();
} else if (itp == Pgiven) { } else if (itp == Pgiven) {
if (sat >= Pcrit()) { if (sat >= Pcrit()) {
@ -506,11 +507,7 @@ void Substance::set_xy(propertyFlag::type ifx, propertyFlag::type ify,
} }
v_here += dv; v_here += dv;
t_here += dt; t_here += dt;
if (t_here >= Tmax()) { t_here = clip(t_here, Tmin(), Tmax());
t_here = Tmax() - 0.001;
} else if (t_here <= Tmin()) {
t_here = Tmin() + 0.001;
}
if (v_here <= 0.0) { if (v_here <= 0.0) {
v_here = 0.0001; v_here = 0.0001;
} }
@ -580,7 +577,7 @@ void Substance::set_TPp(double Temp, double Pressure)
int LoopCount = 0; int LoopCount = 0;
double v_save = 1.0/Rho; double v_save = 1.0/Rho;
set_T(Temp); T = Temp;
v_here = vp(); v_here = vp();
// loop // loop

View file

@ -9,7 +9,7 @@
namespace Cantera namespace Cantera
{ {
Wall::Wall() : m_left(0), m_right(0), Wall::Wall() : m_left(0), m_right(0),
m_area(0.0), m_k(0.0), m_rrth(0.0), m_emiss(0.0), m_area(1.0), m_k(0.0), m_rrth(0.0), m_emiss(0.0),
m_vf(0), m_qf(0) m_vf(0), m_qf(0)
{ {
for (int n = 0; n < 2; n++) { for (int n = 0; n < 2; n++) {

View file

@ -86,7 +86,8 @@ def addTestScript(testname, subdir, script, interpreter, dependencies=(), env_va
passedFile = File(pjoin(subdir, '%s.passed' % testname)) passedFile = File(pjoin(subdir, '%s.passed' % testname))
PASSED_FILES[testname] = str(passedFile) PASSED_FILES[testname] = str(passedFile)
testResults.tests[passedFile.name] = True testResults.tests[passedFile.name] = True
run_program = testenv.Command(passedFile, pjoin(subdir, script), scriptRunner) run_program = testenv.Command(passedFile, pjoin('#test', subdir, script), scriptRunner)
for dep in dependencies: for dep in dependencies:
if isinstance(dep, str): if isinstance(dep, str):
dep = File(pjoin(subdir, dep)) dep = File(pjoin(subdir, dep))

View file

@ -9,6 +9,7 @@ ideal_gas(name = "air",
ideal_gas(name = "notair", ideal_gas(name = "notair",
elements = " O N ", elements = " O N ",
note = "This phase contains no Argon.",
species = """ O O2 N NO NO2 N2O N2 """, species = """ O O2 N NO NO2 N2O N2 """,
initial_state = state(temperature = 900.0, initial_state = state(temperature = 900.0,
pressure = 5*OneAtm, pressure = 5*OneAtm,

View file

@ -25,6 +25,7 @@
<pressure units="Pa">506625.0</pressure> <pressure units="Pa">506625.0</pressure>
<massFractions>O2:0.5, N2:0.5</massFractions> <massFractions>O2:0.5, N2:0.5</massFractions>
</state> </state>
<note>This phase contains no Argon.</note>
<thermo model="IdealGas"/> <thermo model="IdealGas"/>
<kinetics model="GasKinetics"/> <kinetics model="GasKinetics"/>
<transport model="None"/> <transport model="None"/>

View file

@ -0,0 +1,28 @@
Elements
H C
END
SPECIES
foo bar baz bar
bar bar
bar
END
thermo
300.000 1000.000 5000.000
foo C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
bar C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
baz C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
end
reactions
foo + bar = 2 baz 1.2345e12 1.0 200.0
2foo + baz = 3bar 5.4321e10 1.0 500.0
end

View file

@ -1,4 +1,4 @@
thermo NASA9 therm NASA9
200.00 1000.00 6000.00 20000. 3/19/02 200.00 1000.00 6000.00 20000. 3/19/02
e- Ref-Species. Chase, 1998 3/82. e- Ref-Species. Chase, 1998 3/82.
3 912/98 E 1.00 0.00 0.00 0.00 0.00 0.000548579903 0.000 3 912/98 E 1.00 0.00 0.00 0.00 0.00 0.000548579903 0.000

View file

@ -1,8 +1,8 @@
Elements Elements
H C H C
End End
SPECIES SPEC
(Parens) @#$%^-2 [xy2]*{.} (Parens) @#$%^-2 [xy2]*{.} plus+ eq=uals plus
end end
thermo thermo
@ -19,9 +19,26 @@ thermo
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2 7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3 -9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4 -4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
plus+ C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
plus C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
eq=uals C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
end end
reactions reaction
(Parens) + @#$%^-2 = 2 [xy2]*{.} 1.2345e12 1.0 200.0 (Parens) + @#$%^-2 = 2 [xy2]*{.} 1.2345e12 1.0 200.0
2(Parens) + [xy2]*{.} = 3@#$%^-2 5.4321e10 1.0 500.0 2(Parens) + [xy2]*{.} = 3@#$%^-2 5.4321e10 1.0 500.0
plus+ + (Parens) = 2plus+ 9.999e9 9.9 999.9
2 plus+ + eq=uals = 3(Parens) 9.999e9 9.9 999.9
plus + plus+ = 2 (Parens) 9.999e9 9.9 999.9
plus+ eq=uals = plus++(Parens) 9.999e9 9.9 999.9
end end

View file

@ -1,6 +1,4 @@
ELEMENTS ELEM H C AR END
H C AR
END
SPECIES SPECIES
H H
@ -22,4 +20,4 @@ H+R2(+M) = P2A+P2B(+M) 4.0E18 -0.5 100
LOW/7.0E26 -1.0 0/ LOW/7.0E26 -1.0 0/
SRI/1.1 700.0 1234.0 56 0.7/ SRI/1.1 700.0 1234.0 56 0.7/
R3/3/ P1/0.4/ R1A/0.0/ R3/3/ P1/0.4/ R1A/0.0/
END END

View file

@ -0,0 +1,31 @@
Elements
H C
SPECIES
foo bar baz
thermo All
300.000 1000.000 5000.000
foo C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
bar C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
baz C 1H 4 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
reactions cal/mol
foo + bar = 2 baz 1.2345e12 1.0 200.0
2foo + baz = 3bar 5.4321e10 1.0 500.0
transport
foo 2 357.000 5.180 0.000 0.000 1.000
bar 2 266.800 4.982 0.000 0.000 1.000
baz 2 266.800 4.982 0.000 0.000 1.000
! some comment

View file

@ -22,7 +22,7 @@ if __name__ == '__main__':
loader = unittest.TestLoader() loader = unittest.TestLoader()
runner = unittest.TextTestRunner(verbosity=2) runner = unittest.TextTestRunner(verbosity=2)
suite = loader.loadTestsFromName('testSolution') suite = loader.loadTestsFromName('testSolution')
suite = loader.loadTestsFromName('testKinetics') suite.addTests(loader.loadTestsFromName('testKinetics'))
suite.addTests(loader.loadTestsFromName('testPureFluid')) suite.addTests(loader.loadTestsFromName('testPureFluid'))
suite.addTests(loader.loadTestsFromName('testEquilibrium')) suite.addTests(loader.loadTestsFromName('testEquilibrium'))
suite.addTests(loader.loadTestsFromName('testReactors')) suite.addTests(loader.loadTestsFromName('testReactors'))

View file

@ -114,20 +114,40 @@ class chemkinConverterTest(utilities.CanteraTest):
self.assertTrue(gas.nSpecies(), 3) self.assertTrue(gas.nSpecies(), 3)
self.assertTrue(gas.nReactions(), 2) self.assertTrue(gas.nReactions(), 2)
def test_duplicate_species(self):
self.assertRaises(ck2cti.InputParseError,
lambda: convertMech('../data/duplicate-species.inp',
outName='duplicate-species.cti',
quiet=True))
convertMech('../data/duplicate-species.inp',
outName='duplicate-species.cti',
quiet=True, permissive=True)
gas = ct.IdealGasMix('duplicate-species.cti')
self.assertEqual(gas.speciesNames(), ['foo','bar','baz'])
def test_pathologicalSpeciesNames(self): def test_pathologicalSpeciesNames(self):
convertMech('../data/species-names.inp', convertMech('../data/species-names.inp',
outName='species-names.cti', quiet=True) outName='species-names.cti', quiet=True)
gas = ct.IdealGasMix('species-names.cti') gas = ct.IdealGasMix('species-names.cti')
self.assertEqual(gas.nSpecies(), 3) self.assertEqual(gas.nSpecies(), 6)
self.assertEqual(gas.speciesName(0), '(Parens)') self.assertEqual(gas.speciesName(0), '(Parens)')
self.assertEqual(gas.speciesName(1), '@#$%^-2') self.assertEqual(gas.speciesName(1), '@#$%^-2')
self.assertEqual(gas.speciesName(2), '[xy2]*{.}') self.assertEqual(gas.speciesName(2), '[xy2]*{.}')
self.assertEqual(gas.speciesName(3), 'plus+')
self.assertEqual(gas.speciesName(4), 'eq=uals')
self.assertEqual(gas.speciesName(5), 'plus')
self.assertEqual(gas.nReactions(), 2) self.assertEqual(gas.nReactions(), 6)
nu = gas.productStoichCoeffs() - gas.reactantStoichCoeffs() nu = gas.productStoichCoeffs() - gas.reactantStoichCoeffs()
self.assertEqual(list(nu[:,0]), [-1, -1, 2]) self.assertEqual(list(nu[:,0]), [-1, -1, 2, 0, 0, 0])
self.assertEqual(list(nu[:,1]), [-2, 3, -1]) self.assertEqual(list(nu[:,1]), [-2, 3, -1, 0, 0, 0])
self.assertEqual(list(nu[:,2]), [-1, 0, 0, 1, 0, 0])
self.assertEqual(list(nu[:,3]), [3, 0, 0, -2, -1, 0])
self.assertEqual(list(nu[:,4]), [2, 0, 0, -1, 0, -1])
self.assertEqual(list(nu[:,5]), [1, 0, 0, 1, -1, -1])
def test_unterminatedSections(self): def test_unterminatedSections(self):
self.assertRaises(ck2cti.InputParseError, self.assertRaises(ck2cti.InputParseError,
@ -143,6 +163,20 @@ class chemkinConverterTest(utilities.CanteraTest):
self.assertEqual(gas.nSpecies(), 3) self.assertEqual(gas.nSpecies(), 3)
self.assertEqual(gas.nReactions(), 2) self.assertEqual(gas.nReactions(), 2)
def test_unterminatedSections2(self):
self.assertRaises(ck2cti.InputParseError,
lambda: convertMech('../data/unterminated-sections2.inp',
outName='unterminated-sections2.cti',
quiet=True))
convertMech('../data/unterminated-sections2.inp',
outName='unterminated-sections2.cti',
quiet=True, permissive=True)
gas = ct.IdealGasMix('unterminated-sections2.cti')
self.assertEqual(gas.nSpecies(), 3)
self.assertEqual(gas.nReactions(), 2)
def test_nasa9(self): def test_nasa9(self):
convertMech('../data/nasa9-test.inp', convertMech('../data/nasa9-test.inp',
thermoFile='../data/nasa9-test-therm.dat', thermoFile='../data/nasa9-test-therm.dat',