diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index aa9bb1d8..80bfa6f7 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -23,7 +23,8 @@ set(XLNT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(XLNT_INCLUDE_DIR ${XLNT_ROOT_DIR}/include)
set(XLNT_SOURCE_DIR ${XLNT_ROOT_DIR}/source)
set(THIRD_PARTY_DIR ${XLNT_ROOT_DIR}/third-party)
-add_subdirectory(${THIRD_PARTY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/third-party)
+
+add_subdirectory(${THIRD_PARTY_DIR}/libstudxml ${CMAKE_CURRENT_BINARY_DIR}/third-party/libstudxml)
if(COVERAGE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
@@ -127,12 +128,10 @@ else()
endif()
endif()
-add_dependencies(xlnt xlnt.third-party)
-
target_link_libraries(xlnt PRIVATE libstudxml)
target_include_directories(xlnt PUBLIC ${XLNT_INCLUDE_DIR})
target_include_directories(xlnt PRIVATE ${XLNT_SOURCE_DIR})
-target_link_libraries(xlnt PRIVATE ${ZLIB_LIBRARIRES})
+target_link_libraries(xlnt PRIVATE ${ZLIB_LIBRARIES})
target_include_directories(xlnt PRIVATE ${ZLIB_INCLUDE_DIR})
target_link_libraries(xlnt PRIVATE ${CRYPTOPP_LIBRARIES})
target_include_directories(xlnt PRIVATE ${CRYPTOPP_INCLUDE_DIR})
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index c5ded567..5b0d34eb 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -40,6 +40,10 @@ if(COVERAGE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov --coverage")
endif()
+set(CXXTEST_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../third-party/cxxtest)
+set(CXXTEST_INCLUDE_DIR ${CXXTEST_ROOT_DIR})
+set(CXXTEST_PYTHON_TESTGEN_EXECUTABLE ${CXXTEST_ROOT_DIR}/bin/cxxtestgen)
+
add_executable(xlnt.test ${TEST_HELPERS} ${TESTS} ${RUNNER})
target_link_libraries(xlnt.test
PRIVATE xlnt
@@ -76,7 +80,6 @@ else()
endif()
find_package(PythonInterp REQUIRED)
-set(CXXTEST_PYTHON_TESTGEN_EXECUTABLE ${CMAKE_BINARY_DIR}/source/third-party/cxxtest/cxxtest-download-prefix/src/cxxtest-download/bin/cxxtestgen)
add_custom_command(OUTPUT ${RUNNER}
COMMAND ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE} --runner=ErrorPrinter -o ${RUNNER} ${TESTS}
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
deleted file mode 100644
index 464c7362..00000000
--- a/third-party/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-cmake_minimum_required(VERSION 3.2)
-project(xlnt.third-party)
-
-add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libstudxml)
-add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/cxxtest)
-
-add_custom_target(xlnt.third-party
- DEPENDS libstudxml cxxtest-download)
diff --git a/third-party/cxxtest/CMakeLists.txt b/third-party/cxxtest/CMakeLists.txt
index 6f50bdf1..71102442 100644
--- a/third-party/cxxtest/CMakeLists.txt
+++ b/third-party/cxxtest/CMakeLists.txt
@@ -3,13 +3,3 @@ project(cxxtest)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-include(ExternalProject)
-ExternalProject_Add(cxxtest-download
- GIT_REPOSITORY https://github.com/CxxTest/cxxtest
- CONFIGURE_COMMAND ""
- BUILD_COMMAND ""
- INSTALL_COMMAND "")
-
-set(CXXTEST_ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/cxxtest-download-prefix/src/cxxtest-download)
-set(CXXTEST_INCLUDE_DIR ${CXXTEST_ROOT_DIR})
diff --git a/third-party/cxxtest/COPYING b/third-party/cxxtest/COPYING
new file mode 100644
index 00000000..65c5ca88
--- /dev/null
+++ b/third-party/cxxtest/COPYING
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/third-party/cxxtest/README b/third-party/cxxtest/README
new file mode 100644
index 00000000..87aea1bf
--- /dev/null
+++ b/third-party/cxxtest/README
@@ -0,0 +1,44 @@
+Overview
+--------
+
+CxxTest is a unit testing framework for C++ that is similar in
+spirit to JUnit, CppUnit, and xUnit. CxxTest is easy to use because
+it does not require precompiling a CxxTest testing library, it
+employs no advanced features of C++ (e.g. RTTI) and it supports a
+very flexible form of test discovery.
+
+CxxTest is available under the GNU Lesser General Public Licence (LGPL).
+
+A user guide can be downloaded from http://cxxtest.com.
+
+
+A Simple Example
+----------------
+
+1. Create a test suite header file:
+
+MyTestSuite.h:
+
+ #include
+
+ class MyTestSuite : public CxxTest::TestSuite
+ {
+ public:
+ void testAddition( void )
+ {
+ TS_ASSERT( 1 + 1 > 1 );
+ TS_ASSERT_EQUALS( 1 + 1, 2 );
+ }
+ };
+
+
+2. Generate the tests file:
+
+ # cxxtestgen --error-printer -o tests.cpp MyTestSuite.h
+
+3. Compile and run!
+
+ # g++ -o main tests.cpp
+ # ./main
+ Running cxxtest tests (1 test).OK!
+
diff --git a/third-party/cxxtest/Versions b/third-party/cxxtest/Versions
new file mode 100644
index 00000000..89fe0761
--- /dev/null
+++ b/third-party/cxxtest/Versions
@@ -0,0 +1,192 @@
+
+CxxTest Releases
+----------------
+
+* Version 4.4 (2014-06-03)
+ - Fixed compilation error on Windows (MSVC) in XmlFormatter.h (#86)
+ - Fix to ensure that tearDown() is called (#89)
+ - Add option run test with a user defined command in scons (#91)
+ - Use a Python path relative to the cxxtestgen script (#88)
+ - Add defensive guard in ErrorFormatter.h (#96)
+ - Fixed bug with "None" appearing in CXXTEST_CPPATH (#99)
+ - Added CXXTEST_LIBPATH to properly use shared libraries (#100)
+ - Added guards when XmlFormatter.h data is not initialize (#87)
+
+* Version 4.3 (2013-07-05)
+ - Changes to assess code coverage of the cxxtestgen command
+ - Standardizing C++ file formats (using astyle)
+ - Bug fixes that led to the test runner hanging
+ - Adding special assertions for floating point values
+ - Added date to XML output
+ - Added support for comparison of C strings
+
+* Version 4.2.1 (2013-03-22)
+ - Fixing documentation of LGPL version
+
+* Version 4.2 (2013-03-16)
+ - Changes to support test fixtures in namespaces
+ - Adding logic to support test skipping
+ - Change to create self-contained HTML documentation
+ - Fixed inheritance issue in GlobalFixture (#69)
+ - Update LGPL version
+ - Changes to try/catch to avoid ambiguities withn catching std::exception (#53)
+ - Fixed TS_ASSERT_DELTA to work on integer types (#65)
+ - Changed output format to print world-name (#70)
+
+* Version 4.1 (2012-11-30)
+ - Added absolute paths to resolve bug when relative path links are provided.
+ - Bug fix when files contain unicode characters
+ - Fix for --no-static-init: Changed how non-static tests are created
+ - Updated user guide to include SCons build system
+ - Closing out Tigris and SourceForge tickets
+ - Added valgrind tests.
+
+* Version 4.0.3 (2012-01-07)
+ - Adding support for Python 2.4 - 3.2
+ - Various cleanup of CxxTest root directory
+ - Adding patch that allows the cxxtestgen script to be used when symlinked.
+
+* Version 4.0.2 (2012-01-02)
+ - Bug fix to enable installation of cxxtestgen without the 'setuptools' package
+
+* Version 4.0.1 (2012-01-01)
+ - Documentation updates
+ - Bug fix for installation of cxxtestgen script
+
+* Version 4.0 (2011-12-28)
+ - Perl is no longer used to support CxxTest scripts. Python is now the only scripting language used by CxxTest.
+ - The testing scripts have been rewritten using the PyUnit framework.
+ - The installation process for CxxTest now leverages and integrates with the system Python installation.
+ - A more comprehensive C++ parser is now available, which supports testing of templates.
+ - The CxxTest GUI is no longer supported.
+ - The <> and <> macros have the same behavior now.
+ - CxxTest runners now have a command-line interface that facilitates interactive use of the test runner.
+ - A new user guide is now available in PDF, HTML and Ebook formats.
+
+* Version 3.10.1 (2004-12-01)
+ - Improved support for VC7
+ - Fixed clash with some versions of STL
+
+* Version 3.10.0 (2004-11-20)
+ - Added mock framework for global functions
+ - Added TS_ASSERT_THROWS_ASSERT and TS_ASSERT_THROWS_EQUALS
+ - Added CXXTEST_ENUM_TRAITS
+ - Improved support for STL classes (vector, map etc.)
+ - Added support for Digital Mars compiler
+ - Reduced root/part compilation time and binary size
+ - Support C++-style commenting of tests
+
+* Version 3.9.1 (2004-01-19)
+ - Fixed small bug with runner exit code
+ - Embedded test suites are now deprecated
+
+* Version 3.9.0 (2004-01-17)
+ - Added TS_TRACE
+ - Added --no-static-init
+ - CxxTest::setAbortTestOnFail() works even without --abort-on-fail
+
+* Version 3.8.5 (2004-01-08)
+ - Added --no-eh
+ - Added CxxTest::setAbortTestOnFail() and CXXTEST_DEFAULT_ABORT
+ - Added CxxTest::setMaxDumpSize()
+ - Added StdioFilePrinter
+
+* Version 3.8.4 (2003-12-31)
+ - Split distribution into cxxtest and cxxtest-selftest
+ - Added `sample/msvc/FixFiles.bat'
+
+* Version 3.8.3 (2003-12-24)
+ - Added TS_ASSERT_PREDICATE
+ - Template files can now specify where to insert the preamble
+ - Added a sample Visual Studio workspace in `sample/msvc'
+ - Can compile in MSVC with warning level 4
+ - Changed output format slightly
+
+* Version 3.8.1 (2003-12-21)
+ - Fixed small bug when using multiple --part files.
+ - Fixed X11 GUI crash when there's no X server.
+ - Added GlobalFixture::setUpWorld()/tearDownWorld()
+ - Added leaveOnly(), activateAllTests() and `sample/only.tpl'
+ - Should now run without warnings on Sun compiler.
+
+* Version 3.8.0 (2003-12-13)
+ - Fixed bug where `Root.cpp' needed exception handling
+ - Added TS_ASSERT_RELATION
+ - TSM_ macros now also tell you what went wrong
+ - Renamed Win32Gui::free() to avoid clashes
+ - Now compatible with more versions of Borland compiler
+ - Improved the documentation
+
+* Version 3.7.1 (2003-09-29)
+ - Added --version
+ - Compiles with even more exotic g++ warnings
+ - Win32 Gui compiles with UNICODE
+ - Should compile on some more platforms (Sun Forte, HP aCC)
+
+* Version 3.7.0 (2003-09-20)
+ - Added TS_ASSERT_LESS_THAN_EQUALS
+ - Minor cleanups
+
+* Version 3.6.1 (2003-09-15)
+ - Improved QT GUI
+ - Improved portability some more
+
+* Version 3.6.0 (2003-09-04)
+ - Added --longlong
+ - Some portability improvements
+
+* Version 3.5.1 (2003-09-03)
+ - Major internal rewrite of macros
+ - Added TS_ASSERT_SAME_DATA
+ - Added --include option
+ - Added --part and --root to enable splitting the test runner
+ - Added global fixtures
+ - Enhanced Win32 GUI with timers, -keep and -title
+ - Now compiles with strict warnings
+
+* Version 3.1.1 (2003-08-27)
+ - Fixed small bug in TS_ASSERT_THROWS_*()
+
+* Version 3.1.0 (2003-08-23)
+ - Default ValueTraits now dumps value as hex bytes
+ - Fixed double invocation bug (e.g. TS_FAIL(functionWithSideEffects()))
+ - TS_ASSERT_THROWS*() are now "abort on fail"-friendly
+ - Win32 GUI now supports Windows 98 and doesn't need comctl32.lib
+
+* Version 3.0.1 (2003-08-07)
+ - Added simple GUI for X11, Win32 and Qt
+ - Added TS_WARN() macro
+ - Removed --exit-code
+ - Improved samples
+ - Improved support for older (pre-std::) compilers
+ - Made a PDF version of the User's Guide
+
+* Version 2.8.4 (2003-07-21)
+ - Now supports g++-3.3
+ - Added --have-eh
+ - Fixed bug in numberToString()
+
+* Version 2.8.3 (2003-06-30)
+ - Fixed bugs in cxxtestgen.pl
+ - Fixed warning for some compilers in ErrorPrinter/StdioPrinter
+ - Thanks Martin Jost for pointing out these problems!
+
+* Version 2.8.2 (2003-06-10)
+ - Fixed bug when using CXXTEST_ABORT_TEST_ON_FAIL without standard library
+ - Added CXXTEST_USER_TRAITS
+ - Added --abort-on-fail
+
+* Version 2.8.1 (2003-01-16)
+ - Fixed charToString() for negative chars
+
+* Version 2.8.0 (2003-01-13)
+ - Added CXXTEST_ABORT_TEST_ON_FAIL for xUnit-like behaviour
+ - Added `sample/winddk'
+ - Improved ValueTraits
+ - Improved output formatter
+ - Started version history
+
+* Version 2.7.0 (2002-09-29)
+ - Added embedded test suites
+ - Major internal improvements
+
diff --git a/third-party/cxxtest/admin/announcement b/third-party/cxxtest/admin/announcement
new file mode 100644
index 00000000..65b4d039
--- /dev/null
+++ b/third-party/cxxtest/admin/announcement
@@ -0,0 +1,19 @@
+We are pleased to announce the updated release of CxxTest 4.4. CxxTest is a unit testing framework for C++ that is similar in spirit to JUnit, CppUnit, and xUnit. CxxTest is easy to use because it does not require precompiling a CxxTest testing library, it employs no advanced features of C++ (e.g. RTTI) and it supports a very flexible form of test discovery.
+
+This release includes a variety of bug fixes:
+
+ - Fixed compilation error on Windows (MSVC) in XmlFormatter.h (#86)
+ - Fix to ensure that tearDown() is called (#89)
+ - Add option run test with a user defined command in scons (#91)
+ - Use a Python path relative to the cxxtestgen script (#88)
+ - Add defensive guard in ErrorFormatter.h (#96)
+ - Fixed bug with "None" appearing in CXXTEST_CPPATH (#99)
+ - Added CXXTEST_LIBPATH to properly use shared libraries (#100)
+ - Added guards when XmlFormatter.h data is not initialize (#87)
+
+See the CxxTest Home Page (http://cxxtest.com) for documentation and download instructions.
+
+Enjoy!
+
+ CxxTest Developer Team
+ cxxtest-developers@googlegroups.com
diff --git a/third-party/cxxtest/admin/cloudbees_cxxtest b/third-party/cxxtest/admin/cloudbees_cxxtest
new file mode 100644
index 00000000..49a21499
--- /dev/null
+++ b/third-party/cxxtest/admin/cloudbees_cxxtest
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+export PATH=$WORKSPACE/vpython/bin:$PATH
+g++ --version
+
+# Setup virtual Python environment
+\rm -Rf vpython
+python cxxtest/admin/virtualenv.py vpython
+#vpy/scripts/vpy_install
+vpython/bin/easy_install nose
+vpython/bin/easy_install unittest2
+vpython/bin/easy_install ply
+vpython/bin/easy_install ordereddict
+vpython/bin/easy_install gcovr
+vpython/bin/easy_install pyutilib.th
+cd cxxtest/python
+../../vpython/bin/python setup.py install
+
+# Cleanup test directory
+cd ../test
+make clean
+cd ../..
+
+# Run tests
+#export CXXTEST_GCOV_FLAGS='-fprofile-arcs -ftest-coverage'
+vpython/bin/nosetests --verbosity=2 --with-xunit --xunit-file=$WORKSPACE/TEST-cxxtest.xml -w $WORKSPACE/cxxtest/test
+
+# Generate code coverage
+#cd cxxtest
+#../vpython/bin/gcovr -v -r $WORKSPACE/cxxtest -x -o $WORKSPACE/cxxtest/test/coverage.xml --gcov-filter '.*#test#(\.\.|\^)#cxxtest#.*gcov'
+
+echo "DONE"
+
+# Cleanup old gcov files
+cd $WORKSPACE
+#\rm -f *.gcov cxxtest/*.gcov doc/*.gcov doc/examples/*.gcov
+#\rm -f *.gcno cxxtest/*.gcno doc/*.gcno doc/examples/*.gcno
+#\rm -f *.gcda cxxtest/*.gcda doc/*.gcda doc/examples/*.gcda
+cd $WORKSPACE/cxxtest/test
+make clean
+
diff --git a/third-party/cxxtest/admin/cxxtest.spec b/third-party/cxxtest/admin/cxxtest.spec
new file mode 100644
index 00000000..b25f135a
--- /dev/null
+++ b/third-party/cxxtest/admin/cxxtest.spec
@@ -0,0 +1,37 @@
+Name: cxxtest
+Summary: CxxTest Testing Framework for C++
+Version: %{version}
+Release: 1
+Copyright: LGPL
+Group: Development/C++
+Source: cxxtest-%{version}.tar.gz
+BuildRoot: /tmp/cxxtest-build
+BuildArch: noarch
+Prefix: /usr
+
+%description
+CxxTest is a unit testing framework for C++ that is similar in
+spirit to JUnit, CppUnit, and xUnit. CxxTest is easy to use because
+it does not require precompiling a CxxTest testing library, it
+employs no advanced features of C++ (e.g. RTTI) and it supports a
+very flexible form of test discovery.
+
+%prep
+%setup -n cxxtest
+
+%build
+
+%install
+install -m 755 -d $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/include/cxxtest
+install -m 755 bin/cxxtestgen $RPM_BUILD_ROOT/usr/bin/
+install -m 644 cxxtest/* $RPM_BUILD_ROOT/usr/include/cxxtest/
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%attr(-, root, root) %doc README
+%attr(-, root, root) %doc sample
+%attr(-, root, root) /usr/include/cxxtest
+%attr(-, root, root) /usr/bin/cxxtestgen
+
diff --git a/third-party/cxxtest/admin/jenkins_cxxtest b/third-party/cxxtest/admin/jenkins_cxxtest
new file mode 100755
index 00000000..552924cf
--- /dev/null
+++ b/third-party/cxxtest/admin/jenkins_cxxtest
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+if test -z "$WORKSPACE"; then
+ echo "ERROR: \$WORKSPACE not defined"
+ exit 1
+fi
+export PATH="$WORKSPACE/vpython/bin:$PATH"
+
+if test -n "$1"; then
+ PYTHON="$1"
+else
+ PYTHON=python
+fi
+
+echo
+echo "Building on `hostname`:"
+echo
+echo " Workspace: ${WORKSPACE}"
+echo
+echo " Package: ${PACKAGE}"
+echo
+echo " Environment:"
+/usr/bin/env 2>&1 | sort | sed 's/^/ /'
+echo
+echo " Python:"
+${PYTHON} -c 'import sys; sys.stdout.write(sys.version+"\n")' 2>&1 \
+ | sed 's/^/ /'
+PYTHON_VER=`${PYTHON} -c 'import sys; sys.stdout.write(str(sys.version_info[0]))'`
+echo
+# The following executables are required (missing app yields build failure)
+for app in gcc; do
+which $app || exit 1
+echo " $app:"
+$app --version 2>&1 | grep -v '^$' | sed 's/^/ /' || exit 1
+echo
+done
+
+
+# Setup virtual Python environment
+\rm -Rf vpython
+tmp=2.6
+if [ "yes" = "$(echo | awk "($PYTHON_VER < $tmp) { print \"yes\"; }")" ]; then
+ "$PYTHON" "$WORKSPACE"/cxxtest/admin/virtualenv_1.7.py "$WORKSPACE"/vpython || exit 1
+else
+ "$PYTHON" "$WORKSPACE"/cxxtest/admin/virtualenv.py "$WORKSPACE"/vpython || exit 1
+fi
+vpython/bin/easy_install nose
+if test "$PYTHON_VER" -gt 2; then
+ vpython/bin/easy_install unittest2py3k
+ #vpython/bin/pip install unittest2py3k
+else
+ vpython/bin/easy_install unittest2
+fi
+vpython/bin/easy_install ply
+vpython/bin/easy_install ordereddict
+vpython/bin/easy_install gcovr
+vpython/bin/easy_install coverage
+vpython/bin/easy_install pyutilib.th
+cd "$WORKSPACE"/cxxtest/python
+"$WORKSPACE"/vpython/bin/python setup.py develop
+
+# Cleanup test directories
+cd "$WORKSPACE"/cxxtest/test
+make clean
+cd "$WORKSPACE"/cxxtest/doc
+make clean
+cd "$WORKSPACE"
+
+# Run tests
+export CXXTEST_GCOV_FLAGS='-fprofile-arcs -ftest-coverage'
+vpython/bin/nosetests --verbosity=2 -w "$WORKSPACE"/cxxtest \
+ --with-coverage --with-xunit --xunit-file="$WORKSPACE"/TEST-cxxtest.xml \
+ || echo "(INFO) nosetests returned non-zero return code"
+
+# Generate Python code coverage
+vpython/bin/coverage xml --omit="$WORKSPACE/vpython/lib/*,$WORKSPACE/cxxtest/test/*,$WORKSPACE/cxxtest/doc/examples/*" -o $WORKSPACE/cxxtest/test/coverage.xml
+
+# Generate C++ code coverage
+cd "$WORKSPACE"/cxxtest
+"$WORKSPACE"/vpython/bin/gcovr -v -d -r "$WORKSPACE"/cxxtest \
+ -x -o "$WORKSPACE"/cxxtest/coverage.xml \
+ --gcov-filter '.*#test#(\.\.|\^)#cxxtest#.*gcov'
+
+echo "DONE"
+
diff --git a/third-party/cxxtest/admin/virtualenv.py b/third-party/cxxtest/admin/virtualenv.py
new file mode 100755
index 00000000..ccb6eec9
--- /dev/null
+++ b/third-party/cxxtest/admin/virtualenv.py
@@ -0,0 +1,2581 @@
+#!/usr/bin/env python
+"""Create a "virtual" Python installation
+"""
+
+# If you change the version here, change it in setup.py
+# and docs/conf.py as well.
+__version__ = "1.9.1" # following best practices
+virtualenv_version = __version__ # legacy, again
+
+import base64
+import sys
+import os
+import codecs
+import optparse
+import re
+import shutil
+import logging
+import tempfile
+import zlib
+import errno
+import glob
+import distutils.sysconfig
+from distutils.util import strtobool
+import struct
+import subprocess
+
+if sys.version_info < (2, 5):
+ print('ERROR: %s' % sys.exc_info()[1])
+ print('ERROR: this script requires Python 2.5 or greater.')
+ sys.exit(101)
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+try:
+ basestring
+except NameError:
+ basestring = str
+
+try:
+ import ConfigParser
+except ImportError:
+ import configparser as ConfigParser
+
+join = os.path.join
+py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
+
+is_jython = sys.platform.startswith('java')
+is_pypy = hasattr(sys, 'pypy_version_info')
+is_win = (sys.platform == 'win32')
+is_cygwin = (sys.platform == 'cygwin')
+is_darwin = (sys.platform == 'darwin')
+abiflags = getattr(sys, 'abiflags', '')
+
+user_dir = os.path.expanduser('~')
+if is_win:
+ default_storage_dir = os.path.join(user_dir, 'virtualenv')
+else:
+ default_storage_dir = os.path.join(user_dir, '.virtualenv')
+default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini')
+
+if is_pypy:
+ expected_exe = 'pypy'
+elif is_jython:
+ expected_exe = 'jython'
+else:
+ expected_exe = 'python'
+
+
+REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
+ 'fnmatch', 'locale', 'encodings', 'codecs',
+ 'stat', 'UserDict', 'readline', 'copy_reg', 'types',
+ 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
+ 'zlib']
+
+REQUIRED_FILES = ['lib-dynload', 'config']
+
+majver, minver = sys.version_info[:2]
+if majver == 2:
+ if minver >= 6:
+ REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
+ if minver >= 7:
+ REQUIRED_MODULES.extend(['_weakrefset'])
+ if minver <= 3:
+ REQUIRED_MODULES.extend(['sets', '__future__'])
+elif majver == 3:
+ # Some extra modules are needed for Python 3, but different ones
+ # for different versions.
+ REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io',
+ '_weakrefset', 'copyreg', 'tempfile', 'random',
+ '__future__', 'collections', 'keyword', 'tarfile',
+ 'shutil', 'struct', 'copy', 'tokenize', 'token',
+ 'functools', 'heapq', 'bisect', 'weakref',
+ 'reprlib'])
+ if minver >= 2:
+ REQUIRED_FILES[-1] = 'config-%s' % majver
+ if minver == 3:
+ import sysconfig
+ platdir = sysconfig.get_config_var('PLATDIR')
+ REQUIRED_FILES.append(platdir)
+ # The whole list of 3.3 modules is reproduced below - the current
+ # uncommented ones are required for 3.3 as of now, but more may be
+ # added as 3.3 development continues.
+ REQUIRED_MODULES.extend([
+ #"aifc",
+ #"antigravity",
+ #"argparse",
+ #"ast",
+ #"asynchat",
+ #"asyncore",
+ "base64",
+ #"bdb",
+ #"binhex",
+ #"bisect",
+ #"calendar",
+ #"cgi",
+ #"cgitb",
+ #"chunk",
+ #"cmd",
+ #"codeop",
+ #"code",
+ #"colorsys",
+ #"_compat_pickle",
+ #"compileall",
+ #"concurrent",
+ #"configparser",
+ #"contextlib",
+ #"cProfile",
+ #"crypt",
+ #"csv",
+ #"ctypes",
+ #"curses",
+ #"datetime",
+ #"dbm",
+ #"decimal",
+ #"difflib",
+ #"dis",
+ #"doctest",
+ #"dummy_threading",
+ "_dummy_thread",
+ #"email",
+ #"filecmp",
+ #"fileinput",
+ #"formatter",
+ #"fractions",
+ #"ftplib",
+ #"functools",
+ #"getopt",
+ #"getpass",
+ #"gettext",
+ #"glob",
+ #"gzip",
+ "hashlib",
+ #"heapq",
+ "hmac",
+ #"html",
+ #"http",
+ #"idlelib",
+ #"imaplib",
+ #"imghdr",
+ "imp",
+ "importlib",
+ #"inspect",
+ #"json",
+ #"lib2to3",
+ #"logging",
+ #"macpath",
+ #"macurl2path",
+ #"mailbox",
+ #"mailcap",
+ #"_markupbase",
+ #"mimetypes",
+ #"modulefinder",
+ #"multiprocessing",
+ #"netrc",
+ #"nntplib",
+ #"nturl2path",
+ #"numbers",
+ #"opcode",
+ #"optparse",
+ #"os2emxpath",
+ #"pdb",
+ #"pickle",
+ #"pickletools",
+ #"pipes",
+ #"pkgutil",
+ #"platform",
+ #"plat-linux2",
+ #"plistlib",
+ #"poplib",
+ #"pprint",
+ #"profile",
+ #"pstats",
+ #"pty",
+ #"pyclbr",
+ #"py_compile",
+ #"pydoc_data",
+ #"pydoc",
+ #"_pyio",
+ #"queue",
+ #"quopri",
+ #"reprlib",
+ "rlcompleter",
+ #"runpy",
+ #"sched",
+ #"shelve",
+ #"shlex",
+ #"smtpd",
+ #"smtplib",
+ #"sndhdr",
+ #"socket",
+ #"socketserver",
+ #"sqlite3",
+ #"ssl",
+ #"stringprep",
+ #"string",
+ #"_strptime",
+ #"subprocess",
+ #"sunau",
+ #"symbol",
+ #"symtable",
+ #"sysconfig",
+ #"tabnanny",
+ #"telnetlib",
+ #"test",
+ #"textwrap",
+ #"this",
+ #"_threading_local",
+ #"threading",
+ #"timeit",
+ #"tkinter",
+ #"tokenize",
+ #"token",
+ #"traceback",
+ #"trace",
+ #"tty",
+ #"turtledemo",
+ #"turtle",
+ #"unittest",
+ #"urllib",
+ #"uuid",
+ #"uu",
+ #"wave",
+ #"weakref",
+ #"webbrowser",
+ #"wsgiref",
+ #"xdrlib",
+ #"xml",
+ #"xmlrpc",
+ #"zipfile",
+ ])
+
+if is_pypy:
+ # these are needed to correctly display the exceptions that may happen
+ # during the bootstrap
+ REQUIRED_MODULES.extend(['traceback', 'linecache'])
+
+class Logger(object):
+
+ """
+ Logging object for use in command-line script. Allows ranges of
+ levels, to avoid some redundancy of displayed information.
+ """
+
+ DEBUG = logging.DEBUG
+ INFO = logging.INFO
+ NOTIFY = (logging.INFO+logging.WARN)/2
+ WARN = WARNING = logging.WARN
+ ERROR = logging.ERROR
+ FATAL = logging.FATAL
+
+ LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
+
+ def __init__(self, consumers):
+ self.consumers = consumers
+ self.indent = 0
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def debug(self, msg, *args, **kw):
+ self.log(self.DEBUG, msg, *args, **kw)
+ def info(self, msg, *args, **kw):
+ self.log(self.INFO, msg, *args, **kw)
+ def notify(self, msg, *args, **kw):
+ self.log(self.NOTIFY, msg, *args, **kw)
+ def warn(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def error(self, msg, *args, **kw):
+ self.log(self.ERROR, msg, *args, **kw)
+ def fatal(self, msg, *args, **kw):
+ self.log(self.FATAL, msg, *args, **kw)
+ def log(self, level, msg, *args, **kw):
+ if args:
+ if kw:
+ raise TypeError(
+ "You may give positional or keyword arguments, not both")
+ args = args or kw
+ rendered = None
+ for consumer_level, consumer in self.consumers:
+ if self.level_matches(level, consumer_level):
+ if (self.in_progress_hanging
+ and consumer in (sys.stdout, sys.stderr)):
+ self.in_progress_hanging = False
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ if rendered is None:
+ if args:
+ rendered = msg % args
+ else:
+ rendered = msg
+ rendered = ' '*self.indent + rendered
+ if hasattr(consumer, 'write'):
+ consumer.write(rendered+'\n')
+ else:
+ consumer(rendered)
+
+ def start_progress(self, msg):
+ assert not self.in_progress, (
+ "Tried to start_progress(%r) while in_progress %r"
+ % (msg, self.in_progress))
+ if self.level_matches(self.NOTIFY, self._stdout_level()):
+ sys.stdout.write(msg)
+ sys.stdout.flush()
+ self.in_progress_hanging = True
+ else:
+ self.in_progress_hanging = False
+ self.in_progress = msg
+
+ def end_progress(self, msg='done.'):
+ assert self.in_progress, (
+ "Tried to end_progress without start_progress")
+ if self.stdout_level_matches(self.NOTIFY):
+ if not self.in_progress_hanging:
+ # Some message has been printed out since start_progress
+ sys.stdout.write('...' + self.in_progress + msg + '\n')
+ sys.stdout.flush()
+ else:
+ sys.stdout.write(msg + '\n')
+ sys.stdout.flush()
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def show_progress(self):
+ """If we are in a progress scope, and no log messages have been
+ shown, write out another '.'"""
+ if self.in_progress_hanging:
+ sys.stdout.write('.')
+ sys.stdout.flush()
+
+ def stdout_level_matches(self, level):
+ """Returns true if a message at this level will go to stdout"""
+ return self.level_matches(level, self._stdout_level())
+
+ def _stdout_level(self):
+ """Returns the level that stdout runs at"""
+ for level, consumer in self.consumers:
+ if consumer is sys.stdout:
+ return level
+ return self.FATAL
+
+ def level_matches(self, level, consumer_level):
+ """
+ >>> l = Logger([])
+ >>> l.level_matches(3, 4)
+ False
+ >>> l.level_matches(3, 2)
+ True
+ >>> l.level_matches(slice(None, 3), 3)
+ False
+ >>> l.level_matches(slice(None, 3), 2)
+ True
+ >>> l.level_matches(slice(1, 3), 1)
+ True
+ >>> l.level_matches(slice(2, 3), 1)
+ False
+ """
+ if isinstance(level, slice):
+ start, stop = level.start, level.stop
+ if start is not None and start > consumer_level:
+ return False
+ if stop is not None and stop <= consumer_level:
+ return False
+ return True
+ else:
+ return level >= consumer_level
+
+ #@classmethod
+ def level_for_integer(cls, level):
+ levels = cls.LEVELS
+ if level < 0:
+ return levels[0]
+ if level >= len(levels):
+ return levels[-1]
+ return levels[level]
+
+ level_for_integer = classmethod(level_for_integer)
+
+# create a silent logger just to prevent this from being undefined
+# will be overridden with requested verbosity main() is called.
+logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
+
+def mkdir(path):
+ if not os.path.exists(path):
+ logger.info('Creating %s', path)
+ os.makedirs(path)
+ else:
+ logger.info('Directory %s already exists', path)
+
+def copyfileordir(src, dest):
+ if os.path.isdir(src):
+ shutil.copytree(src, dest, True)
+ else:
+ shutil.copy2(src, dest)
+
+def copyfile(src, dest, symlink=True):
+ if not os.path.exists(src):
+ # Some bad symlink in the src
+ logger.warn('Cannot find file %s (bad symlink)', src)
+ return
+ if os.path.exists(dest):
+ logger.debug('File %s already exists', dest)
+ return
+ if not os.path.exists(os.path.dirname(dest)):
+ logger.info('Creating parent directories for %s' % os.path.dirname(dest))
+ os.makedirs(os.path.dirname(dest))
+ if not os.path.islink(src):
+ srcpath = os.path.abspath(src)
+ else:
+ srcpath = os.readlink(src)
+ if symlink and hasattr(os, 'symlink') and not is_win:
+ logger.info('Symlinking %s', dest)
+ try:
+ os.symlink(srcpath, dest)
+ except (OSError, NotImplementedError):
+ logger.info('Symlinking failed, copying to %s', dest)
+ copyfileordir(src, dest)
+ else:
+ logger.info('Copying to %s', dest)
+ copyfileordir(src, dest)
+
+def writefile(dest, content, overwrite=True):
+ if not os.path.exists(dest):
+ logger.info('Writing %s', dest)
+ f = open(dest, 'wb')
+ f.write(content.encode('utf-8'))
+ f.close()
+ return
+ else:
+ f = open(dest, 'rb')
+ c = f.read()
+ f.close()
+ if c != content.encode("utf-8"):
+ if not overwrite:
+ logger.notify('File %s exists with different content; not overwriting', dest)
+ return
+ logger.notify('Overwriting %s with new content', dest)
+ f = open(dest, 'wb')
+ f.write(content.encode('utf-8'))
+ f.close()
+ else:
+ logger.info('Content %s already in place', dest)
+
+def rmtree(dir):
+ if os.path.exists(dir):
+ logger.notify('Deleting tree %s', dir)
+ shutil.rmtree(dir)
+ else:
+ logger.info('Do not need to delete %s; already gone', dir)
+
+def make_exe(fn):
+ if hasattr(os, 'chmod'):
+ oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
+ newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
+ os.chmod(fn, newmode)
+ logger.info('Changed mode of %s to %s', fn, oct(newmode))
+
+def _find_file(filename, dirs):
+ for dir in reversed(dirs):
+ files = glob.glob(os.path.join(dir, filename))
+ if files and os.path.isfile(files[0]):
+ return True, files[0]
+ return False, filename
+
+def _install_req(py_executable, unzip=False, distribute=False,
+ search_dirs=None, never_download=False):
+
+ if search_dirs is None:
+ search_dirs = file_search_dirs()
+
+ if not distribute:
+ egg_path = 'setuptools-*-py%s.egg' % sys.version[:3]
+ found, egg_path = _find_file(egg_path, search_dirs)
+ project_name = 'setuptools'
+ bootstrap_script = EZ_SETUP_PY
+ tgz_path = None
+ else:
+ # Look for a distribute egg (these are not distributed by default,
+ # but can be made available by the user)
+ egg_path = 'distribute-*-py%s.egg' % sys.version[:3]
+ found, egg_path = _find_file(egg_path, search_dirs)
+ project_name = 'distribute'
+ if found:
+ tgz_path = None
+ bootstrap_script = DISTRIBUTE_FROM_EGG_PY
+ else:
+ # Fall back to sdist
+ # NB: egg_path is not None iff tgz_path is None
+ # iff bootstrap_script is a generic setup script accepting
+ # the standard arguments.
+ egg_path = None
+ tgz_path = 'distribute-*.tar.gz'
+ found, tgz_path = _find_file(tgz_path, search_dirs)
+ bootstrap_script = DISTRIBUTE_SETUP_PY
+
+ if is_jython and os._name == 'nt':
+ # Jython's .bat sys.executable can't handle a command line
+ # argument with newlines
+ fd, ez_setup = tempfile.mkstemp('.py')
+ os.write(fd, bootstrap_script)
+ os.close(fd)
+ cmd = [py_executable, ez_setup]
+ else:
+ cmd = [py_executable, '-c', bootstrap_script]
+ if unzip and egg_path:
+ cmd.append('--always-unzip')
+ env = {}
+ remove_from_env = ['__PYVENV_LAUNCHER__']
+ if logger.stdout_level_matches(logger.DEBUG) and egg_path:
+ cmd.append('-v')
+
+ old_chdir = os.getcwd()
+ if egg_path is not None and os.path.exists(egg_path):
+ logger.info('Using existing %s egg: %s' % (project_name, egg_path))
+ cmd.append(egg_path)
+ if os.environ.get('PYTHONPATH'):
+ env['PYTHONPATH'] = egg_path + os.path.pathsep + os.environ['PYTHONPATH']
+ else:
+ env['PYTHONPATH'] = egg_path
+ elif tgz_path is not None and os.path.exists(tgz_path):
+ # Found a tgz source dist, let's chdir
+ logger.info('Using existing %s egg: %s' % (project_name, tgz_path))
+ os.chdir(os.path.dirname(tgz_path))
+ # in this case, we want to be sure that PYTHONPATH is unset (not
+ # just empty, really unset), else CPython tries to import the
+ # site.py that it's in virtualenv_support
+ remove_from_env.append('PYTHONPATH')
+ elif never_download:
+ logger.fatal("Can't find any local distributions of %s to install "
+ "and --never-download is set. Either re-run virtualenv "
+ "without the --never-download option, or place a %s "
+ "distribution (%s) in one of these "
+ "locations: %r" % (project_name, project_name,
+ egg_path or tgz_path,
+ search_dirs))
+ sys.exit(1)
+ elif egg_path:
+ logger.info('No %s egg found; downloading' % project_name)
+ cmd.extend(['--always-copy', '-U', project_name])
+ else:
+ logger.info('No %s tgz found; downloading' % project_name)
+ logger.start_progress('Installing %s...' % project_name)
+ logger.indent += 2
+ cwd = None
+ if project_name == 'distribute':
+ env['DONT_PATCH_SETUPTOOLS'] = 'true'
+
+ def _filter_ez_setup(line):
+ return filter_ez_setup(line, project_name)
+
+ if not os.access(os.getcwd(), os.W_OK):
+ cwd = tempfile.mkdtemp()
+ if tgz_path is not None and os.path.exists(tgz_path):
+ # the current working dir is hostile, let's copy the
+ # tarball to a temp dir
+ target = os.path.join(cwd, os.path.split(tgz_path)[-1])
+ shutil.copy(tgz_path, target)
+ try:
+ call_subprocess(cmd, show_stdout=False,
+ filter_stdout=_filter_ez_setup,
+ extra_env=env,
+ remove_from_env=remove_from_env,
+ cwd=cwd)
+ finally:
+ logger.indent -= 2
+ logger.end_progress()
+ if cwd is not None:
+ shutil.rmtree(cwd)
+ if os.getcwd() != old_chdir:
+ os.chdir(old_chdir)
+ if is_jython and os._name == 'nt':
+ os.remove(ez_setup)
+
+def file_search_dirs():
+ here = os.path.dirname(os.path.abspath(__file__))
+ dirs = ['.', here,
+ join(here, 'virtualenv_support')]
+ if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
+ # Probably some boot script; just in case virtualenv is installed...
+ try:
+ import virtualenv
+ except ImportError:
+ pass
+ else:
+ dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
+ return [d for d in dirs if os.path.isdir(d)]
+
+def install_setuptools(py_executable, unzip=False,
+ search_dirs=None, never_download=False):
+ _install_req(py_executable, unzip,
+ search_dirs=search_dirs, never_download=never_download)
+
+def install_distribute(py_executable, unzip=False,
+ search_dirs=None, never_download=False):
+ _install_req(py_executable, unzip, distribute=True,
+ search_dirs=search_dirs, never_download=never_download)
+
+_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
+def install_pip(py_executable, search_dirs=None, never_download=False):
+ if search_dirs is None:
+ search_dirs = file_search_dirs()
+
+ filenames = []
+ for dir in search_dirs:
+ filenames.extend([join(dir, fn) for fn in os.listdir(dir)
+ if _pip_re.search(fn)])
+ filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
+ filenames.sort()
+ filenames = [filename for basename, i, filename in filenames]
+ if not filenames:
+ filename = 'pip'
+ else:
+ filename = filenames[-1]
+ easy_install_script = 'easy_install'
+ if is_win:
+ easy_install_script = 'easy_install-script.py'
+ # There's two subtle issues here when invoking easy_install.
+ # 1. On unix-like systems the easy_install script can *only* be executed
+ # directly if its full filesystem path is no longer than 78 characters.
+ # 2. A work around to [1] is to use the `python path/to/easy_install foo`
+ # pattern, but that breaks if the path contains non-ASCII characters, as
+ # you can't put the file encoding declaration before the shebang line.
+ # The solution is to use Python's -x flag to skip the first line of the
+ # script (and any ASCII decoding errors that may have occurred in that line)
+ cmd = [py_executable, '-x', join(os.path.dirname(py_executable), easy_install_script), filename]
+ # jython and pypy don't yet support -x
+ if is_jython or is_pypy:
+ cmd.remove('-x')
+ if filename == 'pip':
+ if never_download:
+ logger.fatal("Can't find any local distributions of pip to install "
+ "and --never-download is set. Either re-run virtualenv "
+ "without the --never-download option, or place a pip "
+ "source distribution (zip/tar.gz/tar.bz2) in one of these "
+ "locations: %r" % search_dirs)
+ sys.exit(1)
+ logger.info('Installing pip from network...')
+ else:
+ logger.info('Installing existing %s distribution: %s' % (
+ os.path.basename(filename), filename))
+ logger.start_progress('Installing pip...')
+ logger.indent += 2
+ def _filter_setup(line):
+ return filter_ez_setup(line, 'pip')
+ try:
+ call_subprocess(cmd, show_stdout=False,
+ filter_stdout=_filter_setup)
+ finally:
+ logger.indent -= 2
+ logger.end_progress()
+
+def filter_ez_setup(line, project_name='setuptools'):
+ if not line.strip():
+ return Logger.DEBUG
+ if project_name == 'distribute':
+ for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
+ 'Scanning', 'Setuptools', 'Egg', 'Already',
+ 'running', 'writing', 'reading', 'installing',
+ 'creating', 'copying', 'byte-compiling', 'removing',
+ 'Processing'):
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.DEBUG
+ for prefix in ['Reading ', 'Best match', 'Processing setuptools',
+ 'Copying setuptools', 'Adding setuptools',
+ 'Installing ', 'Installed ']:
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.INFO
+
+
+class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
+ """
+ Custom help formatter for use in ConfigOptionParser that updates
+ the defaults before expanding them, allowing them to show up correctly
+ in the help listing
+ """
+ def expand_default(self, option):
+ if self.parser is not None:
+ self.parser.update_defaults(self.parser.defaults)
+ return optparse.IndentedHelpFormatter.expand_default(self, option)
+
+
+class ConfigOptionParser(optparse.OptionParser):
+ """
+ Custom option parser which updates its defaults by by checking the
+ configuration files and environmental variables
+ """
+ def __init__(self, *args, **kwargs):
+ self.config = ConfigParser.RawConfigParser()
+ self.files = self.get_config_files()
+ self.config.read(self.files)
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+
+ def get_config_files(self):
+ config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False)
+ if config_file and os.path.exists(config_file):
+ return [config_file]
+ return [default_config_file]
+
+ def update_defaults(self, defaults):
+ """
+ Updates the given defaults with values from the config files and
+ the environ. Does a little special handling for certain types of
+ options (lists).
+ """
+ # Then go and look for the other sources of configuration:
+ config = {}
+ # 1. config files
+ config.update(dict(self.get_config_section('virtualenv')))
+ # 2. environmental variables
+ config.update(dict(self.get_environ_vars()))
+ # Then set the options with those values
+ for key, val in config.items():
+ key = key.replace('_', '-')
+ if not key.startswith('--'):
+ key = '--%s' % key # only prefer long opts
+ option = self.get_option(key)
+ if option is not None:
+ # ignore empty values
+ if not val:
+ continue
+ # handle multiline configs
+ if option.action == 'append':
+ val = val.split()
+ else:
+ option.nargs = 1
+ if option.action == 'store_false':
+ val = not strtobool(val)
+ elif option.action in ('store_true', 'count'):
+ val = strtobool(val)
+ try:
+ val = option.convert_value(key, val)
+ except optparse.OptionValueError:
+ e = sys.exc_info()[1]
+ print("An error occured during configuration: %s" % e)
+ sys.exit(3)
+ defaults[option.dest] = val
+ return defaults
+
+ def get_config_section(self, name):
+ """
+ Get a section of a configuration
+ """
+ if self.config.has_section(name):
+ return self.config.items(name)
+ return []
+
+ def get_environ_vars(self, prefix='VIRTUALENV_'):
+ """
+ Returns a generator with all environmental vars with prefix VIRTUALENV
+ """
+ for key, val in os.environ.items():
+ if key.startswith(prefix):
+ yield (key.replace(prefix, '').lower(), val)
+
+ def get_default_values(self):
+ """
+ Overridding to make updating the defaults after instantiation of
+ the option parser possible, update_defaults() does the dirty work.
+ """
+ if not self.process_default_values:
+ # Old, pre-Optik 1.5 behaviour.
+ return optparse.Values(self.defaults)
+
+ defaults = self.update_defaults(self.defaults.copy()) # ours
+ for option in self._get_all_options():
+ default = defaults.get(option.dest)
+ if isinstance(default, basestring):
+ opt_str = option.get_opt_string()
+ defaults[option.dest] = option.check_value(opt_str, default)
+ return optparse.Values(defaults)
+
+
+def main():
+ parser = ConfigOptionParser(
+ version=virtualenv_version,
+ usage="%prog [OPTIONS] DEST_DIR",
+ formatter=UpdatingDefaultsHelpFormatter())
+
+ parser.add_option(
+ '-v', '--verbose',
+ action='count',
+ dest='verbose',
+ default=0,
+ help="Increase verbosity")
+
+ parser.add_option(
+ '-q', '--quiet',
+ action='count',
+ dest='quiet',
+ default=0,
+ help='Decrease verbosity')
+
+ parser.add_option(
+ '-p', '--python',
+ dest='python',
+ metavar='PYTHON_EXE',
+ help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
+ 'interpreter to create the new environment. The default is the interpreter that '
+ 'virtualenv was installed with (%s)' % sys.executable)
+
+ parser.add_option(
+ '--clear',
+ dest='clear',
+ action='store_true',
+ help="Clear out the non-root install and start from scratch")
+
+ parser.set_defaults(system_site_packages=False)
+ parser.add_option(
+ '--no-site-packages',
+ dest='system_site_packages',
+ action='store_false',
+ help="Don't give access to the global site-packages dir to the "
+ "virtual environment (default)")
+
+ parser.add_option(
+ '--system-site-packages',
+ dest='system_site_packages',
+ action='store_true',
+ help="Give access to the global site-packages dir to the "
+ "virtual environment")
+
+ parser.add_option(
+ '--unzip-setuptools',
+ dest='unzip_setuptools',
+ action='store_true',
+ help="Unzip Setuptools or Distribute when installing it")
+
+ parser.add_option(
+ '--relocatable',
+ dest='relocatable',
+ action='store_true',
+ help='Make an EXISTING virtualenv environment relocatable. '
+ 'This fixes up scripts and makes all .pth files relative')
+
+ parser.add_option(
+ '--distribute', '--use-distribute', # the second option is for legacy reasons here. Hi Kenneth!
+ dest='use_distribute',
+ action='store_true',
+ help='Use Distribute instead of Setuptools. Set environ variable '
+ 'VIRTUALENV_DISTRIBUTE to make it the default ')
+
+ parser.add_option(
+ '--no-setuptools',
+ dest='no_setuptools',
+ action='store_true',
+ help='Do not install distribute/setuptools (or pip) '
+ 'in the new virtualenv.')
+
+ parser.add_option(
+ '--no-pip',
+ dest='no_pip',
+ action='store_true',
+ help='Do not install pip in the new virtualenv.')
+
+ parser.add_option(
+ '--setuptools',
+ dest='use_distribute',
+ action='store_false',
+ help='Use Setuptools instead of Distribute. Set environ variable '
+ 'VIRTUALENV_SETUPTOOLS to make it the default ')
+
+ # Set this to True to use distribute by default, even in Python 2.
+ parser.set_defaults(use_distribute=False)
+
+ default_search_dirs = file_search_dirs()
+ parser.add_option(
+ '--extra-search-dir',
+ dest="search_dirs",
+ action="append",
+ default=default_search_dirs,
+ help="Directory to look for setuptools/distribute/pip distributions in. "
+ "You can add any number of additional --extra-search-dir paths.")
+
+ parser.add_option(
+ '--never-download',
+ dest="never_download",
+ action="store_true",
+ help="Never download anything from the network. Instead, virtualenv will fail "
+ "if local distributions of setuptools/distribute/pip are not present.")
+
+ parser.add_option(
+ '--prompt',
+ dest='prompt',
+ help='Provides an alternative prompt prefix for this environment')
+
+ if 'extend_parser' in globals():
+ extend_parser(parser)
+
+ options, args = parser.parse_args()
+
+ global logger
+
+ if 'adjust_options' in globals():
+ adjust_options(options, args)
+
+ verbosity = options.verbose - options.quiet
+ logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])
+
+ if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
+ env = os.environ.copy()
+ interpreter = resolve_interpreter(options.python)
+ if interpreter == sys.executable:
+ logger.warn('Already using interpreter %s' % interpreter)
+ else:
+ logger.notify('Running virtualenv with interpreter %s' % interpreter)
+ env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
+ file = __file__
+ if file.endswith('.pyc'):
+ file = file[:-1]
+ popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
+ raise SystemExit(popen.wait())
+
+ # Force --distribute on Python 3, since setuptools is not available.
+ if majver > 2:
+ options.use_distribute = True
+
+ if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute:
+ print(
+ "The PYTHONDONTWRITEBYTECODE environment variable is "
+ "not compatible with setuptools. Either use --distribute "
+ "or unset PYTHONDONTWRITEBYTECODE.")
+ sys.exit(2)
+ if not args:
+ print('You must provide a DEST_DIR')
+ parser.print_help()
+ sys.exit(2)
+ if len(args) > 1:
+ print('There must be only one argument: DEST_DIR (you gave %s)' % (
+ ' '.join(args)))
+ parser.print_help()
+ sys.exit(2)
+
+ home_dir = args[0]
+
+ if os.environ.get('WORKING_ENV'):
+ logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
+ logger.fatal('Please deactivate your workingenv, then re-run this script')
+ sys.exit(3)
+
+ if 'PYTHONHOME' in os.environ:
+ logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
+ del os.environ['PYTHONHOME']
+
+ if options.relocatable:
+ make_environment_relocatable(home_dir)
+ return
+
+ create_environment(home_dir,
+ site_packages=options.system_site_packages,
+ clear=options.clear,
+ unzip_setuptools=options.unzip_setuptools,
+ use_distribute=options.use_distribute,
+ prompt=options.prompt,
+ search_dirs=options.search_dirs,
+ never_download=options.never_download,
+ no_setuptools=options.no_setuptools,
+ no_pip=options.no_pip)
+ if 'after_install' in globals():
+ after_install(options, home_dir)
+
+def call_subprocess(cmd, show_stdout=True,
+ filter_stdout=None, cwd=None,
+ raise_on_returncode=True, extra_env=None,
+ remove_from_env=None):
+ cmd_parts = []
+ for part in cmd:
+ if len(part) > 45:
+ part = part[:20]+"..."+part[-20:]
+ if ' ' in part or '\n' in part or '"' in part or "'" in part:
+ part = '"%s"' % part.replace('"', '\\"')
+ if hasattr(part, 'decode'):
+ try:
+ part = part.decode(sys.getdefaultencoding())
+ except UnicodeDecodeError:
+ part = part.decode(sys.getfilesystemencoding())
+ cmd_parts.append(part)
+ cmd_desc = ' '.join(cmd_parts)
+ if show_stdout:
+ stdout = None
+ else:
+ stdout = subprocess.PIPE
+ logger.debug("Running command %s" % cmd_desc)
+ if extra_env or remove_from_env:
+ env = os.environ.copy()
+ if extra_env:
+ env.update(extra_env)
+ if remove_from_env:
+ for varname in remove_from_env:
+ env.pop(varname, None)
+ else:
+ env = None
+ try:
+ proc = subprocess.Popen(
+ cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
+ cwd=cwd, env=env)
+ except Exception:
+ e = sys.exc_info()[1]
+ logger.fatal(
+ "Error %s while executing command %s" % (e, cmd_desc))
+ raise
+ all_output = []
+ if stdout is not None:
+ stdout = proc.stdout
+ encoding = sys.getdefaultencoding()
+ fs_encoding = sys.getfilesystemencoding()
+ while 1:
+ line = stdout.readline()
+ try:
+ line = line.decode(encoding)
+ except UnicodeDecodeError:
+ line = line.decode(fs_encoding)
+ if not line:
+ break
+ line = line.rstrip()
+ all_output.append(line)
+ if filter_stdout:
+ level = filter_stdout(line)
+ if isinstance(level, tuple):
+ level, line = level
+ logger.log(level, line)
+ if not logger.stdout_level_matches(level):
+ logger.show_progress()
+ else:
+ logger.info(line)
+ else:
+ proc.communicate()
+ proc.wait()
+ if proc.returncode:
+ if raise_on_returncode:
+ if all_output:
+ logger.notify('Complete output from command %s:' % cmd_desc)
+ logger.notify('\n'.join(all_output) + '\n----------------------------------------')
+ raise OSError(
+ "Command %s failed with error code %s"
+ % (cmd_desc, proc.returncode))
+ else:
+ logger.warn(
+ "Command %s had error code %s"
+ % (cmd_desc, proc.returncode))
+
+
+def create_environment(home_dir, site_packages=False, clear=False,
+ unzip_setuptools=False, use_distribute=False,
+ prompt=None, search_dirs=None, never_download=False,
+ no_setuptools=False, no_pip=False):
+ """
+ Creates a new environment in ``home_dir``.
+
+ If ``site_packages`` is true, then the global ``site-packages/``
+ directory will be on the path.
+
+ If ``clear`` is true (default False) then the environment will
+ first be cleared.
+ """
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+
+ py_executable = os.path.abspath(install_python(
+ home_dir, lib_dir, inc_dir, bin_dir,
+ site_packages=site_packages, clear=clear))
+
+ install_distutils(home_dir)
+
+ if not no_setuptools:
+ if use_distribute:
+ install_distribute(py_executable, unzip=unzip_setuptools,
+ search_dirs=search_dirs, never_download=never_download)
+ else:
+ install_setuptools(py_executable, unzip=unzip_setuptools,
+ search_dirs=search_dirs, never_download=never_download)
+
+ if not no_pip:
+ install_pip(py_executable, search_dirs=search_dirs, never_download=never_download)
+
+ install_activate(home_dir, bin_dir, prompt)
+
+def is_executable_file(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+def path_locations(home_dir):
+ """Return the path locations for the environment (where libraries are,
+ where scripts go, etc)"""
+ # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
+ # prefix arg is broken: http://bugs.python.org/issue3386
+ if is_win:
+ # Windows has lots of problems with executables with spaces in
+ # the name; this function will remove them (using the ~1
+ # format):
+ mkdir(home_dir)
+ if ' ' in home_dir:
+ import ctypes
+ GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW
+ size = max(len(home_dir)+1, 256)
+ buf = ctypes.create_unicode_buffer(size)
+ try:
+ u = unicode
+ except NameError:
+ u = str
+ ret = GetShortPathName(u(home_dir), buf, size)
+ if not ret:
+ print('Error: the path "%s" has a space in it' % home_dir)
+ print('We could not determine the short pathname for it.')
+ print('Exiting.')
+ sys.exit(3)
+ home_dir = str(buf.value)
+ lib_dir = join(home_dir, 'Lib')
+ inc_dir = join(home_dir, 'Include')
+ bin_dir = join(home_dir, 'Scripts')
+ if is_jython:
+ lib_dir = join(home_dir, 'Lib')
+ inc_dir = join(home_dir, 'Include')
+ bin_dir = join(home_dir, 'bin')
+ elif is_pypy:
+ lib_dir = home_dir
+ inc_dir = join(home_dir, 'include')
+ bin_dir = join(home_dir, 'bin')
+ elif not is_win:
+ lib_dir = join(home_dir, 'lib', py_version)
+ multiarch_exec = '/usr/bin/multiarch-platform'
+ if is_executable_file(multiarch_exec):
+ # In Mageia (2) and Mandriva distros the include dir must be like:
+ # virtualenv/include/multiarch-x86_64-linux/python2.7
+ # instead of being virtualenv/include/python2.7
+ p = subprocess.Popen(multiarch_exec, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ # stdout.strip is needed to remove newline character
+ inc_dir = join(home_dir, 'include', stdout.strip(), py_version + abiflags)
+ else:
+ inc_dir = join(home_dir, 'include', py_version + abiflags)
+ bin_dir = join(home_dir, 'bin')
+ return home_dir, lib_dir, inc_dir, bin_dir
+
+
+def change_prefix(filename, dst_prefix):
+ prefixes = [sys.prefix]
+
+ if is_darwin:
+ prefixes.extend((
+ os.path.join("/Library/Python", sys.version[:3], "site-packages"),
+ os.path.join(sys.prefix, "Extras", "lib", "python"),
+ os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"),
+ # Python 2.6 no-frameworks
+ os.path.join("~", ".local", "lib","python", sys.version[:3], "site-packages"),
+ # System Python 2.7 on OSX Mountain Lion
+ os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages")))
+
+ if hasattr(sys, 'real_prefix'):
+ prefixes.append(sys.real_prefix)
+ if hasattr(sys, 'base_prefix'):
+ prefixes.append(sys.base_prefix)
+ prefixes = list(map(os.path.expanduser, prefixes))
+ prefixes = list(map(os.path.abspath, prefixes))
+ # Check longer prefixes first so we don't split in the middle of a filename
+ prefixes = sorted(prefixes, key=len, reverse=True)
+ filename = os.path.abspath(filename)
+ for src_prefix in prefixes:
+ if filename.startswith(src_prefix):
+ _, relpath = filename.split(src_prefix, 1)
+ if src_prefix != os.sep: # sys.prefix == "/"
+ assert relpath[0] == os.sep
+ relpath = relpath[1:]
+ return join(dst_prefix, relpath)
+ assert False, "Filename %s does not start with any of these prefixes: %s" % \
+ (filename, prefixes)
+
+def copy_required_modules(dst_prefix):
+ import imp
+ # If we are running under -p, we need to remove the current
+ # directory from sys.path temporarily here, so that we
+ # definitely get the modules from the site directory of
+ # the interpreter we are running under, not the one
+ # virtualenv.py is installed under (which might lead to py2/py3
+ # incompatibility issues)
+ _prev_sys_path = sys.path
+ if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
+ sys.path = sys.path[1:]
+ try:
+ for modname in REQUIRED_MODULES:
+ if modname in sys.builtin_module_names:
+ logger.info("Ignoring built-in bootstrap module: %s" % modname)
+ continue
+ try:
+ f, filename, _ = imp.find_module(modname)
+ except ImportError:
+ logger.info("Cannot import bootstrap module: %s" % modname)
+ else:
+ if f is not None:
+ f.close()
+ # special-case custom readline.so on OS X, but not for pypy:
+ if modname == 'readline' and sys.platform == 'darwin' and not (
+ is_pypy or filename.endswith(join('lib-dynload', 'readline.so'))):
+ dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so')
+ else:
+ dst_filename = change_prefix(filename, dst_prefix)
+ copyfile(filename, dst_filename)
+ if filename.endswith('.pyc'):
+ pyfile = filename[:-1]
+ if os.path.exists(pyfile):
+ copyfile(pyfile, dst_filename[:-1])
+ finally:
+ sys.path = _prev_sys_path
+
+
+def subst_path(prefix_path, prefix, home_dir):
+ prefix_path = os.path.normpath(prefix_path)
+ prefix = os.path.normpath(prefix)
+ home_dir = os.path.normpath(home_dir)
+ if not prefix_path.startswith(prefix):
+ logger.warn('Path not in prefix %r %r', prefix_path, prefix)
+ return
+ return prefix_path.replace(prefix, home_dir, 1)
+
+
+def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
+ """Install just the base environment, no distutils patches etc"""
+ if sys.executable.startswith(bin_dir):
+ print('Please use the *system* python to run this script')
+ return
+
+ if clear:
+ rmtree(lib_dir)
+ ## FIXME: why not delete it?
+ ## Maybe it should delete everything with #!/path/to/venv/python in it
+ logger.notify('Not deleting %s', bin_dir)
+
+ if hasattr(sys, 'real_prefix'):
+ logger.notify('Using real prefix %r' % sys.real_prefix)
+ prefix = sys.real_prefix
+ elif hasattr(sys, 'base_prefix'):
+ logger.notify('Using base prefix %r' % sys.base_prefix)
+ prefix = sys.base_prefix
+ else:
+ prefix = sys.prefix
+ mkdir(lib_dir)
+ fix_lib64(lib_dir)
+ stdlib_dirs = [os.path.dirname(os.__file__)]
+ if is_win:
+ stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
+ elif is_darwin:
+ stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
+ if hasattr(os, 'symlink'):
+ logger.info('Symlinking Python bootstrap modules')
+ else:
+ logger.info('Copying Python bootstrap modules')
+ logger.indent += 2
+ try:
+ # copy required files...
+ for stdlib_dir in stdlib_dirs:
+ if not os.path.isdir(stdlib_dir):
+ continue
+ for fn in os.listdir(stdlib_dir):
+ bn = os.path.splitext(fn)[0]
+ if fn != 'site-packages' and bn in REQUIRED_FILES:
+ copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
+ # ...and modules
+ copy_required_modules(home_dir)
+ finally:
+ logger.indent -= 2
+ mkdir(join(lib_dir, 'site-packages'))
+ import site
+ site_filename = site.__file__
+ if site_filename.endswith('.pyc'):
+ site_filename = site_filename[:-1]
+ elif site_filename.endswith('$py.class'):
+ site_filename = site_filename.replace('$py.class', '.py')
+ site_filename_dst = change_prefix(site_filename, home_dir)
+ site_dir = os.path.dirname(site_filename_dst)
+ writefile(site_filename_dst, SITE_PY)
+ writefile(join(site_dir, 'orig-prefix.txt'), prefix)
+ site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
+ if not site_packages:
+ writefile(site_packages_filename, '')
+
+ if is_pypy or is_win:
+ stdinc_dir = join(prefix, 'include')
+ else:
+ stdinc_dir = join(prefix, 'include', py_version + abiflags)
+ if os.path.exists(stdinc_dir):
+ copyfile(stdinc_dir, inc_dir)
+ else:
+ logger.debug('No include dir %s' % stdinc_dir)
+
+ platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1)
+ if platinc_dir != stdinc_dir:
+ platinc_dest = distutils.sysconfig.get_python_inc(
+ plat_specific=1, prefix=home_dir)
+ if platinc_dir == platinc_dest:
+ # Do platinc_dest manually due to a CPython bug;
+ # not http://bugs.python.org/issue3386 but a close cousin
+ platinc_dest = subst_path(platinc_dir, prefix, home_dir)
+ if platinc_dest:
+ # PyPy's stdinc_dir and prefix are relative to the original binary
+ # (traversing virtualenvs), whereas the platinc_dir is relative to
+ # the inner virtualenv and ignores the prefix argument.
+ # This seems more evolved than designed.
+ copyfile(platinc_dir, platinc_dest)
+
+ # pypy never uses exec_prefix, just ignore it
+ if sys.exec_prefix != prefix and not is_pypy:
+ if is_win:
+ exec_dir = join(sys.exec_prefix, 'lib')
+ elif is_jython:
+ exec_dir = join(sys.exec_prefix, 'Lib')
+ else:
+ exec_dir = join(sys.exec_prefix, 'lib', py_version)
+ for fn in os.listdir(exec_dir):
+ copyfile(join(exec_dir, fn), join(lib_dir, fn))
+
+ if is_jython:
+ # Jython has either jython-dev.jar and javalib/ dir, or just
+ # jython.jar
+ for name in 'jython-dev.jar', 'javalib', 'jython.jar':
+ src = join(prefix, name)
+ if os.path.exists(src):
+ copyfile(src, join(home_dir, name))
+ # XXX: registry should always exist after Jython 2.5rc1
+ src = join(prefix, 'registry')
+ if os.path.exists(src):
+ copyfile(src, join(home_dir, 'registry'), symlink=False)
+ copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
+ symlink=False)
+
+ mkdir(bin_dir)
+ py_executable = join(bin_dir, os.path.basename(sys.executable))
+ if 'Python.framework' in prefix:
+ # OS X framework builds cause validation to break
+ # https://github.com/pypa/virtualenv/issues/322
+ if os.environ.get('__PYVENV_LAUNCHER__'):
+ os.unsetenv('__PYVENV_LAUNCHER__')
+ if re.search(r'/Python(?:-32|-64)*$', py_executable):
+ # The name of the python executable is not quite what
+ # we want, rename it.
+ py_executable = os.path.join(
+ os.path.dirname(py_executable), 'python')
+
+ logger.notify('New %s executable in %s', expected_exe, py_executable)
+ pcbuild_dir = os.path.dirname(sys.executable)
+ pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth')
+ if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')):
+ logger.notify('Detected python running from build directory %s', pcbuild_dir)
+ logger.notify('Writing .pth file linking to build directory for *.pyd files')
+ writefile(pyd_pth, pcbuild_dir)
+ else:
+ pcbuild_dir = None
+ if os.path.exists(pyd_pth):
+ logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth)
+ os.unlink(pyd_pth)
+
+ if sys.executable != py_executable:
+ ## FIXME: could I just hard link?
+ executable = sys.executable
+ shutil.copyfile(executable, py_executable)
+ make_exe(py_executable)
+ if is_win or is_cygwin:
+ pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
+ if os.path.exists(pythonw):
+ logger.info('Also created pythonw.exe')
+ shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
+ python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe')
+ python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe')
+ if os.path.exists(python_d):
+ logger.info('Also created python_d.exe')
+ shutil.copyfile(python_d, python_d_dest)
+ elif os.path.exists(python_d_dest):
+ logger.info('Removed python_d.exe as it is no longer at the source')
+ os.unlink(python_d_dest)
+ # we need to copy the DLL to enforce that windows will load the correct one.
+ # may not exist if we are cygwin.
+ py_executable_dll = 'python%s%s.dll' % (
+ sys.version_info[0], sys.version_info[1])
+ py_executable_dll_d = 'python%s%s_d.dll' % (
+ sys.version_info[0], sys.version_info[1])
+ pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
+ pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
+ pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)
+ if os.path.exists(pythondll):
+ logger.info('Also created %s' % py_executable_dll)
+ shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll))
+ if os.path.exists(pythondll_d):
+ logger.info('Also created %s' % py_executable_dll_d)
+ shutil.copyfile(pythondll_d, pythondll_d_dest)
+ elif os.path.exists(pythondll_d_dest):
+ logger.info('Removed %s as the source does not exist' % pythondll_d_dest)
+ os.unlink(pythondll_d_dest)
+ if is_pypy:
+ # make a symlink python --> pypy-c
+ python_executable = os.path.join(os.path.dirname(py_executable), 'python')
+ if sys.platform in ('win32', 'cygwin'):
+ python_executable += '.exe'
+ logger.info('Also created executable %s' % python_executable)
+ copyfile(py_executable, python_executable)
+
+ if is_win:
+ for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll':
+ src = join(prefix, name)
+ if os.path.exists(src):
+ copyfile(src, join(bin_dir, name))
+
+ if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
+ secondary_exe = os.path.join(os.path.dirname(py_executable),
+ expected_exe)
+ py_executable_ext = os.path.splitext(py_executable)[1]
+ if py_executable_ext == '.exe':
+ # python2.4 gives an extension of '.4' :P
+ secondary_exe += py_executable_ext
+ if os.path.exists(secondary_exe):
+ logger.warn('Not overwriting existing %s script %s (you must use %s)'
+ % (expected_exe, secondary_exe, py_executable))
+ else:
+ logger.notify('Also creating executable in %s' % secondary_exe)
+ shutil.copyfile(sys.executable, secondary_exe)
+ make_exe(secondary_exe)
+
+ if '.framework' in prefix:
+ if 'Python.framework' in prefix:
+ logger.debug('MacOSX Python framework detected')
+ # Make sure we use the the embedded interpreter inside
+ # the framework, even if sys.executable points to
+ # the stub executable in ${sys.prefix}/bin
+ # See http://groups.google.com/group/python-virtualenv/
+ # browse_thread/thread/17cab2f85da75951
+ original_python = os.path.join(
+ prefix, 'Resources/Python.app/Contents/MacOS/Python')
+ if 'EPD' in prefix:
+ logger.debug('EPD framework detected')
+ original_python = os.path.join(prefix, 'bin/python')
+ shutil.copy(original_python, py_executable)
+
+ # Copy the framework's dylib into the virtual
+ # environment
+ virtual_lib = os.path.join(home_dir, '.Python')
+
+ if os.path.exists(virtual_lib):
+ os.unlink(virtual_lib)
+ copyfile(
+ os.path.join(prefix, 'Python'),
+ virtual_lib)
+
+ # And then change the install_name of the copied python executable
+ try:
+ mach_o_change(py_executable,
+ os.path.join(prefix, 'Python'),
+ '@executable_path/../.Python')
+ except:
+ e = sys.exc_info()[1]
+ logger.warn("Could not call mach_o_change: %s. "
+ "Trying to call install_name_tool instead." % e)
+ try:
+ call_subprocess(
+ ["install_name_tool", "-change",
+ os.path.join(prefix, 'Python'),
+ '@executable_path/../.Python',
+ py_executable])
+ except:
+ logger.fatal("Could not call install_name_tool -- you must "
+ "have Apple's development tools installed")
+ raise
+
+ if not is_win:
+ # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
+ py_exe_version_major = 'python%s' % sys.version_info[0]
+ py_exe_version_major_minor = 'python%s.%s' % (
+ sys.version_info[0], sys.version_info[1])
+ py_exe_no_version = 'python'
+ required_symlinks = [ py_exe_no_version, py_exe_version_major,
+ py_exe_version_major_minor ]
+
+ py_executable_base = os.path.basename(py_executable)
+
+ if py_executable_base in required_symlinks:
+ # Don't try to symlink to yourself.
+ required_symlinks.remove(py_executable_base)
+
+ for pth in required_symlinks:
+ full_pth = join(bin_dir, pth)
+ if os.path.exists(full_pth):
+ os.unlink(full_pth)
+ os.symlink(py_executable_base, full_pth)
+
+ if is_win and ' ' in py_executable:
+ # There's a bug with subprocess on Windows when using a first
+ # argument that has a space in it. Instead we have to quote
+ # the value:
+ py_executable = '"%s"' % py_executable
+ # NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks
+ cmd = [py_executable, '-c', 'import sys;out=sys.stdout;'
+ 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))']
+ logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
+ try:
+ proc = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE)
+ proc_stdout, proc_stderr = proc.communicate()
+ except OSError:
+ e = sys.exc_info()[1]
+ if e.errno == errno.EACCES:
+ logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
+ sys.exit(100)
+ else:
+ raise e
+
+ proc_stdout = proc_stdout.strip().decode("utf-8")
+ proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
+ norm_home_dir = os.path.normcase(os.path.abspath(home_dir))
+ if hasattr(norm_home_dir, 'decode'):
+ norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
+ if proc_stdout != norm_home_dir:
+ logger.fatal(
+ 'ERROR: The executable %s is not functioning' % py_executable)
+ logger.fatal(
+ 'ERROR: It thinks sys.prefix is %r (should be %r)'
+ % (proc_stdout, norm_home_dir))
+ logger.fatal(
+ 'ERROR: virtualenv is not compatible with this system or executable')
+ if is_win:
+ logger.fatal(
+ 'Note: some Windows users have reported this error when they '
+ 'installed Python for "Only this user" or have multiple '
+ 'versions of Python installed. Copying the appropriate '
+ 'PythonXX.dll to the virtualenv Scripts/ directory may fix '
+ 'this problem.')
+ sys.exit(100)
+ else:
+ logger.info('Got sys.prefix result: %r' % proc_stdout)
+
+ pydistutils = os.path.expanduser('~/.pydistutils.cfg')
+ if os.path.exists(pydistutils):
+ logger.notify('Please make sure you remove any previous custom paths from '
+ 'your %s file.' % pydistutils)
+ ## FIXME: really this should be calculated earlier
+
+ fix_local_scheme(home_dir)
+
+ if site_packages:
+ if os.path.exists(site_packages_filename):
+ logger.info('Deleting %s' % site_packages_filename)
+ os.unlink(site_packages_filename)
+
+ return py_executable
+
+
+def install_activate(home_dir, bin_dir, prompt=None):
+ home_dir = os.path.abspath(home_dir)
+ if is_win or is_jython and os._name == 'nt':
+ files = {
+ 'activate.bat': ACTIVATE_BAT,
+ 'deactivate.bat': DEACTIVATE_BAT,
+ 'activate.ps1': ACTIVATE_PS,
+ }
+
+ # MSYS needs paths of the form /c/path/to/file
+ drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/'))
+ home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail)
+
+ # Run-time conditional enables (basic) Cygwin compatibility
+ home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" %
+ (home_dir, home_dir_msys))
+ files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh)
+
+ else:
+ files = {'activate': ACTIVATE_SH}
+
+ # suppling activate.fish in addition to, not instead of, the
+ # bash script support.
+ files['activate.fish'] = ACTIVATE_FISH
+
+ # same for csh/tcsh support...
+ files['activate.csh'] = ACTIVATE_CSH
+
+ files['activate_this.py'] = ACTIVATE_THIS
+ if hasattr(home_dir, 'decode'):
+ home_dir = home_dir.decode(sys.getfilesystemencoding())
+ vname = os.path.basename(home_dir)
+ for name, content in files.items():
+ content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
+ content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
+ content = content.replace('__VIRTUAL_ENV__', home_dir)
+ content = content.replace('__VIRTUAL_NAME__', vname)
+ content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
+ writefile(os.path.join(bin_dir, name), content)
+
+def install_distutils(home_dir):
+ distutils_path = change_prefix(distutils.__path__[0], home_dir)
+ mkdir(distutils_path)
+ ## FIXME: maybe this prefix setting should only be put in place if
+ ## there's a local distutils.cfg with a prefix setting?
+ home_dir = os.path.abspath(home_dir)
+ ## FIXME: this is breaking things, removing for now:
+ #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
+ writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
+ writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
+
+def fix_local_scheme(home_dir):
+ """
+ Platforms that use the "posix_local" install scheme (like Ubuntu with
+ Python 2.7) need to be given an additional "local" location, sigh.
+ """
+ try:
+ import sysconfig
+ except ImportError:
+ pass
+ else:
+ if sysconfig._get_default_scheme() == 'posix_local':
+ local_path = os.path.join(home_dir, 'local')
+ if not os.path.exists(local_path):
+ os.mkdir(local_path)
+ for subdir_name in os.listdir(home_dir):
+ if subdir_name == 'local':
+ continue
+ os.symlink(os.path.abspath(os.path.join(home_dir, subdir_name)), \
+ os.path.join(local_path, subdir_name))
+
+def fix_lib64(lib_dir):
+ """
+ Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
+ instead of lib/pythonX.Y. If this is such a platform we'll just create a
+ symlink so lib64 points to lib
+ """
+ if [p for p in distutils.sysconfig.get_config_vars().values()
+ if isinstance(p, basestring) and 'lib64' in p]:
+ logger.debug('This system uses lib64; symlinking lib64 to lib')
+ assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
+ "Unexpected python lib dir: %r" % lib_dir)
+ lib_parent = os.path.dirname(lib_dir)
+ top_level = os.path.dirname(lib_parent)
+ lib_dir = os.path.join(top_level, 'lib')
+ lib64_link = os.path.join(top_level, 'lib64')
+ assert os.path.basename(lib_parent) == 'lib', (
+ "Unexpected parent dir: %r" % lib_parent)
+ if os.path.lexists(lib64_link):
+ return
+ os.symlink('lib', lib64_link)
+
+def resolve_interpreter(exe):
+ """
+ If the executable given isn't an absolute path, search $PATH for the interpreter
+ """
+ if os.path.abspath(exe) != exe:
+ paths = os.environ.get('PATH', '').split(os.pathsep)
+ for path in paths:
+ if os.path.exists(os.path.join(path, exe)):
+ exe = os.path.join(path, exe)
+ break
+ if not os.path.exists(exe):
+ logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
+ raise SystemExit(3)
+ if not is_executable(exe):
+ logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
+ raise SystemExit(3)
+ return exe
+
+def is_executable(exe):
+ """Checks a file is executable"""
+ return os.access(exe, os.X_OK)
+
+############################################################
+## Relocating the environment:
+
+def make_environment_relocatable(home_dir):
+ """
+ Makes the already-existing environment use relative paths, and takes out
+ the #!-based environment selection in scripts.
+ """
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ activate_this = os.path.join(bin_dir, 'activate_this.py')
+ if not os.path.exists(activate_this):
+ logger.fatal(
+ 'The environment doesn\'t have a file %s -- please re-run virtualenv '
+ 'on this environment to update it' % activate_this)
+ fixup_scripts(home_dir)
+ fixup_pth_and_egg_link(home_dir)
+ ## FIXME: need to fix up distutils.cfg
+
+OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
+ 'activate', 'activate.bat', 'activate_this.py']
+
+def fixup_scripts(home_dir):
+ # This is what we expect at the top of scripts:
+ shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
+ # This is what we'll put:
+ new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
+ if is_win:
+ bin_suffix = 'Scripts'
+ else:
+ bin_suffix = 'bin'
+ bin_dir = os.path.join(home_dir, bin_suffix)
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ for filename in os.listdir(bin_dir):
+ filename = os.path.join(bin_dir, filename)
+ if not os.path.isfile(filename):
+ # ignore subdirs, e.g. .svn ones.
+ continue
+ f = open(filename, 'rb')
+ try:
+ try:
+ lines = f.read().decode('utf-8').splitlines()
+ except UnicodeDecodeError:
+ # This is probably a binary program instead
+ # of a script, so just ignore it.
+ continue
+ finally:
+ f.close()
+ if not lines:
+ logger.warn('Script %s is an empty file' % filename)
+ continue
+ if not lines[0].strip().startswith(shebang):
+ if os.path.basename(filename) in OK_ABS_SCRIPTS:
+ logger.debug('Cannot make script %s relative' % filename)
+ elif lines[0].strip() == new_shebang:
+ logger.info('Script %s has already been made relative' % filename)
+ else:
+ logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
+ % (filename, shebang))
+ continue
+ logger.notify('Making script %s relative' % filename)
+ script = relative_script([new_shebang] + lines[1:])
+ f = open(filename, 'wb')
+ f.write('\n'.join(script).encode('utf-8'))
+ f.close()
+
+def relative_script(lines):
+ "Return a script that'll work in a relocatable environment."
+ activate = "import os; activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
+ # Find the last future statement in the script. If we insert the activation
+ # line before a future statement, Python will raise a SyntaxError.
+ activate_at = None
+ for idx, line in reversed(list(enumerate(lines))):
+ if line.split()[:3] == ['from', '__future__', 'import']:
+ activate_at = idx + 1
+ break
+ if activate_at is None:
+ # Activate after the shebang.
+ activate_at = 1
+ return lines[:activate_at] + ['', activate, ''] + lines[activate_at:]
+
+def fixup_pth_and_egg_link(home_dir, sys_path=None):
+ """Makes .pth and .egg-link files use relative paths"""
+ home_dir = os.path.normcase(os.path.abspath(home_dir))
+ if sys_path is None:
+ sys_path = sys.path
+ for path in sys_path:
+ if not path:
+ path = '.'
+ if not os.path.isdir(path):
+ continue
+ path = os.path.normcase(os.path.abspath(path))
+ if not path.startswith(home_dir):
+ logger.debug('Skipping system (non-environment) directory %s' % path)
+ continue
+ for filename in os.listdir(path):
+ filename = os.path.join(path, filename)
+ if filename.endswith('.pth'):
+ if not os.access(filename, os.W_OK):
+ logger.warn('Cannot write .pth file %s, skipping' % filename)
+ else:
+ fixup_pth_file(filename)
+ if filename.endswith('.egg-link'):
+ if not os.access(filename, os.W_OK):
+ logger.warn('Cannot write .egg-link file %s, skipping' % filename)
+ else:
+ fixup_egg_link(filename)
+
+def fixup_pth_file(filename):
+ lines = []
+ prev_lines = []
+ f = open(filename)
+ prev_lines = f.readlines()
+ f.close()
+ for line in prev_lines:
+ line = line.strip()
+ if (not line or line.startswith('#') or line.startswith('import ')
+ or os.path.abspath(line) != line):
+ lines.append(line)
+ else:
+ new_value = make_relative_path(filename, line)
+ if line != new_value:
+ logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
+ lines.append(new_value)
+ if lines == prev_lines:
+ logger.info('No changes to .pth file %s' % filename)
+ return
+ logger.notify('Making paths in .pth file %s relative' % filename)
+ f = open(filename, 'w')
+ f.write('\n'.join(lines) + '\n')
+ f.close()
+
+def fixup_egg_link(filename):
+ f = open(filename)
+ link = f.readline().strip()
+ f.close()
+ if os.path.abspath(link) != link:
+ logger.debug('Link in %s already relative' % filename)
+ return
+ new_link = make_relative_path(filename, link)
+ logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
+ f = open(filename, 'w')
+ f.write(new_link)
+ f.close()
+
+def make_relative_path(source, dest, dest_is_directory=True):
+ """
+ Make a filename relative, where the filename is dest, and it is
+ being referred to from the filename source.
+
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/usr/share/another-place/src/Directory')
+ '../another-place/src/Directory'
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/home/user/src/Directory')
+ '../../../home/user/src/Directory'
+ >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
+ './'
+ """
+ source = os.path.dirname(source)
+ if not dest_is_directory:
+ dest_filename = os.path.basename(dest)
+ dest = os.path.dirname(dest)
+ dest = os.path.normpath(os.path.abspath(dest))
+ source = os.path.normpath(os.path.abspath(source))
+ dest_parts = dest.strip(os.path.sep).split(os.path.sep)
+ source_parts = source.strip(os.path.sep).split(os.path.sep)
+ while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
+ dest_parts.pop(0)
+ source_parts.pop(0)
+ full_parts = ['..']*len(source_parts) + dest_parts
+ if not dest_is_directory:
+ full_parts.append(dest_filename)
+ if not full_parts:
+ # Special case for the current directory (otherwise it'd be '')
+ return './'
+ return os.path.sep.join(full_parts)
+
+
+
+############################################################
+## Bootstrap script creation:
+
+def create_bootstrap_script(extra_text, python_version=''):
+ """
+ Creates a bootstrap script, which is like this script but with
+ extend_parser, adjust_options, and after_install hooks.
+
+ This returns a string that (written to disk of course) can be used
+ as a bootstrap script with your own customizations. The script
+ will be the standard virtualenv.py script, with your extra text
+ added (your extra text should be Python code).
+
+ If you include these functions, they will be called:
+
+ ``extend_parser(optparse_parser)``:
+ You can add or remove options from the parser here.
+
+ ``adjust_options(options, args)``:
+ You can change options here, or change the args (if you accept
+ different kinds of arguments, be sure you modify ``args`` so it is
+ only ``[DEST_DIR]``).
+
+ ``after_install(options, home_dir)``:
+
+ After everything is installed, this function is called. This
+ is probably the function you are most likely to use. An
+ example would be::
+
+ def after_install(options, home_dir):
+ subprocess.call([join(home_dir, 'bin', 'easy_install'),
+ 'MyPackage'])
+ subprocess.call([join(home_dir, 'bin', 'my-package-script'),
+ 'setup', home_dir])
+
+ This example immediately installs a package, and runs a setup
+ script from that package.
+
+ If you provide something like ``python_version='2.5'`` then the
+ script will start with ``#!/usr/bin/env python2.5`` instead of
+ ``#!/usr/bin/env python``. You can use this when the script must
+ be run with a particular Python version.
+ """
+ filename = __file__
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ f = codecs.open(filename, 'r', encoding='utf-8')
+ content = f.read()
+ f.close()
+ py_exe = 'python%s' % python_version
+ content = (('#!/usr/bin/env %s\n' % py_exe)
+ + '## WARNING: This file is generated\n'
+ + content)
+ return content.replace('##EXT' 'END##', extra_text)
+
+##EXTEND##
+
+def convert(s):
+ b = base64.b64decode(s.encode('ascii'))
+ return zlib.decompress(b).decode('utf-8')
+
+##file site.py
+SITE_PY = convert("""
+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
+""")
+
+##file ez_setup.py
+EZ_SETUP_PY = convert("""
+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
+qL7+C1AkCcw=
+""")
+
+##file distribute_from_egg.py
+DISTRIBUTE_FROM_EGG_PY = convert("""
+eJw9j8tqAzEMRfcG/4MgmxQyptkGusonZBmGoGTUGYFfWPKE6dfXTkM3gqt7rh47OKP3NMF3SQFW
+LlrRU1zhybpAxoKBlIqcrNnBdRjQP3GTocYfzmNrrCPQPN9iwzpxSQfQhWBi0cL3qtRtYIG/4Mv0
+KApY5hooqrOGQ05FQTaxptF9Fnx16Rq0XofjaE1XGXVxHIWK7j8P8EY/rHndLqQ1a0pe3COFgHFy
+hLLdWkDbi/DeEpCjNb3u/zccT2Ob8gtnwVyI
+""")
+
+##file distribute_setup.py
+DISTRIBUTE_SETUP_PY = convert("""
+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
+""")
+
+##file activate.sh
+ACTIVATE_SH = convert("""
+eJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+
+nfl25pvZDswCnoDPQ4QoTRQsENIEPci4CsBMZBq7CAsuLOYqvmYKTTj3YxnBgiXBudGBjUzBZUJI
+BXEqgCvweIyuCjeG4eF2F5x14bcB9KQiQQWrjSddI1/oQIx6SYYeoFjzWIoIhYI1izlbhJjkKO7D
+M/QEmKfO9O7WeRo/zr4P7pyHwWxkwitcgwpQ5Ej96OX+PmiFwLeVjFUOrNYKaq1Nud3nR2n8nI2m
+k9H0friPTGVsUdptaxGrTEfpNVFEskxpXtUkkCkl1UNF9cgLBkx48J4EXyALuBtAwNYIjF5kcmUU
+abMKmMq1ULoiRbgsDEkTSsKSGFCJ6Z8vY/2xYiSacmtyAfCDdCNTVZoVF8vSTQOoEwSnOrngBkws
+MYGMBMg8/bMBLSYKS7pYEXP0PqT+ZmBT0Xuy+Pplj5yn4aM9nk72JD8/Wi+Gr98sD9eWSMOwkapD
+BbUv91XSvmyVkICt2tmXR4tWmrcUCsjWOpw87YidEC8i0gdTSOFhouJUNxR+4NYBG0MftoCTD9F7
+2rTtxG3oPwY1b2HncYwhrlmj6Wq924xtGDWqfdNxap+OYxplEurnMVo9RWks+rH8qKEtx7kZT5zJ
+4H7oOFclrN6uFe+d+nW2aIUsSgs/42EIPuOhXq+jEo3S6tX6w2ilNkDnIpHCWdEQhFgwj9pkk7FN
+l/y5eQvRSIQ5+TrL05lewxWpt/Lbhes5cJF3mLET1MGhcKCF+40tNWnUulxrpojwDo2sObdje3Bz
+N3QeHqf3D7OjEXMVV8LN3ZlvuzoWHqiUcNKHtwNd0IbvPGKYYM31nPKCgkUILw3KL+Y8l7aO1ArS
+Ad37nIU0fCj5NE5gQCuC5sOSu+UdI2NeXg/lFkQIlFpdWVaWZRfvqGiirC9o6liJ9FXGYrSY9mI1
+D/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG
++n8O9H8f5vsGOWXsL1+1k3g=
+""")
+
+##file activate.fish
+ACTIVATE_FISH = convert("""
+eJyVVWFv2jAQ/c6vuBoqQVWC9nVSNVGVCaS2VC2rNLWVZZILWAs2s52wVvvxsyEJDrjbmgpK7PP5
+3bt3d22YLbmGlGcIq1wbmCPkGhPYcLMEEsGciwGLDS+YwSjlekngLFVyBe73GXSXxqw/DwbuTS8x
+yyKpFr1WG15lDjETQhpQuQBuIOEKY5O9tlppLqxHKSDByjVAPwEy+mXtCq5MzjIUBTCRgEKTKwFG
+gpBqxTLYXgN2myspVigMaYF92tZSowGZJf4mFExxNs9Qb614CgZtmH0BpEOn11f0cXI/+za8pnfD
+2ZjA1sg9zlV/8QvcMhxbNu0QwgYokn/d+n02nt6Opzcjcnx1vXcIoN74O4ymWQXmHURfJw9jenc/
+vbmb0enj6P5+cuVhqlKm3S0u2XRtRbA2QQAhV7VhBF0rsgUX9Ur1rBUXJgVSy8O751k8mzY5OrKH
+RW3eaQhYGTr8hrXO59ALhxQ83mCsDLAid3T72CCSdJhaFE+fXgicXAARUiR2WeVO37gH3oYHzFKo
+9k7CaPZ1UeNwH1tWuXA4uFKYYcEa8vaKqXl7q1UpygMPhFLvlVKyNzsSM3S2km7UBOl4xweUXk5u
+6e3wZmQ9leY1XE/Ili670tr9g/5POBBpGIJXCCF79L1siarl/dbESa8mD8PL61GpzqpzuMS7tqeB
+1YkALrRBloBMbR9yLcVx7frQAgUqR7NZIuzkEu110gbNit1enNs82Rx5utq7Z3prU78HFRgulqNC
+OTwbqJa9vkJFclQgZSjbKeBgSsUtCtt9D8OwAbIVJuewQdfvQRaoFE9wd1TmCuRG7OgJ1bVXGHc7
+z5WDL/WW36v2oi37CyVBak61+yPBA9C1qqGxzKQqZ0oPuocU9hpud0PIp8sDHkXR1HKkNlzjuUWA
+a0enFUyzOWZA4yXGP+ZMI3Tdt2OuqU/SO4q64526cPE0A7ZyW2PMbWZiZ5HamIZ2RcCKLXhcDl2b
+vXL+eccQoRzem80mekPDEiyiWK4GWqZmwxQOmPM0eIfgp1P9cqrBsewR2p/DPMtt+pfcYM+Ls2uh
+hALufTAdmGl8B1H3VPd2af8fQAc4PgqjlIBL9cGQqNpXaAwe3LrtVn8AkZTUxg==
+""")
+
+##file activate.csh
+ACTIVATE_CSH = convert("""
+eJx9VG1P2zAQ/u5fcYQKNgTNPtN1WxlIQ4KCUEGaxuQ6yYVYSuzKdhqVX7+zk3bpy5YPUXL3PPfc
+ne98DLNCWshliVDV1kGCUFvMoJGugMjq2qQIiVSxSJ1cCofD1BYRnOVGV0CfZ0N2DD91DalQSjsw
+tQLpIJMGU1euvPe7QeJlkKzgWixlhnAt4aoUVsLnLBiy5NtbJWQ5THX1ZciYKKWwkOFaE04dUm6D
+r/zh7pq/3D7Nnid3/HEy+wFHY/gEJydg0aFaQrBFgz1c5DG1IhTs+UZgsBC2GMFBlaeH+8dZXwcW
+VPvCjXdlAvCfQsE7al0+07XjZvrSCUevR5dnkVeKlFYZmUztG4BdzL2u9KyLVabTU0bdfg7a0hgs
+cSmUg6UwUiQl2iHrcbcVGNvPCiLOe7+cRwG13z9qRGgx2z6DHjfm/Op2yqeT+xvOLzs0PTKHDz2V
+tkckFHoQfQRXoGJAj9el0FyJCmEMhzgMS4sB7KPOE2ExoLcSieYwDvR+cP8cg11gKkVJc2wRcm1g
+QhYFlXiTaTfO2ki0fQoiFM4tLuO4aZrhOzqR4dIPcWx17hphMBY+Srwh7RTyN83XOWkcSPh1Pg/k
+TXX/jbJTbMtUmcxZ+/bbqOsy82suFQg/BhdSOTRhMNBHlUarCpU7JzBhmkKmRejKOQzayQe6MWoa
+n1wqWmuh6LZAaHxcdeqIlVLhIBJdO9/kbl0It2oEXQj+eGjJOuvOIR/YGRqvFhttUB2XTvLXYN2H
+37CBdbW2W7j2r2+VsCn0doVWcFG1/4y1VwBjfwAyoZhD
+""")
+
+##file activate.bat
+ACTIVATE_BAT = convert("""
+eJx9UdEKgjAUfW6wfxjiIH+hEDKUFHSKLCMI7kNOEkIf9P9pTJ3OLJ/03HPPPed4Es9XS9qqwqgT
+PbGKKOdXL4aAFS7A4gvAwgijuiKlqOpGlATS2NeMLE+TjJM9RkQ+SmqAXLrBo1LLIeLdiWlD6jZt
+r7VNubWkndkXaxg5GO3UaOOKS6drO3luDDiO5my3iA0YAKGzPRV1ack8cOdhysI0CYzIPzjSiH5X
+0QcvC8Lfaj0emsVKYF2rhL5L3fCkVjV76kShi59NHwDniAHzkgDgqBcwOgTMx+gDQQqXCw==
+""")
+
+##file deactivate.bat
+DEACTIVATE_BAT = convert("""
+eJxzSE3OyFfIT0vj4ipOLVEI8wwKCXX0iXf1C7Pl4spMU0hJTcvMS01RiPf3cYmHyQYE+fsGhCho
+cCkAAUibEkTEVhWLMlUlLk6QGixStlyaeCyJDPHw9/Pw93VFsQguim4ZXAJoIUw5DhX47XUM8UCx
+EchHtwsohN1bILUgw61c/Vy4AJYPYm4=
+""")
+
+##file activate.ps1
+ACTIVATE_PS = convert("""
+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
+QastYw==
+""")
+
+##file distutils-init.py
+DISTUTILS_INIT = convert("""
+eJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E
+UXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB
+C4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss
+aG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT
+0n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9
+oh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE
+NFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c
+f/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8
+p7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk
+vUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw
+hUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh
+cbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw
+buHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ
+5bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh
+gGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC
+1vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL
+MlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6
+84zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK
+0/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO
+kMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG
+qgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h
+kzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9
+GBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ=
+""")
+
+##file distutils.cfg
+DISTUTILS_CFG = convert("""
+eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
+xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
+9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
+""")
+
+##file activate_this.py
+ACTIVATE_THIS = convert("""
+eJyNU01v2zAMvetXEB4K21jmDOstQA4dMGCHbeihlyEIDMWmG62yJEiKE//7kXKdpN2KzYBt8euR
+fKSyLPs8wiEo8wh4wqZTGou4V6Hm0wJa1cSiTkJdr8+GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe
+5a3p0cRKiAe2NtLADikftnDco0ko/SFEVgEZ8aRC5GLux7i3BpSJ6J1H+i7A2CjiHq9z7JRZuuQq
+siwTIvpxJYCeuWaBpwZdhB+yxy/eWz+ZvVSU8C4E9FFZkyxFsvCT/ZzL8gcz9aXVE14Yyp2M+2W0
+y7n5mp0qN+avKXvbsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCZN9UzlJr+/e/iab8WfqsmPI6pWeUPd
+FrMsd4H/55poeO9n54COhUs+sZNEzNtg/wanpjpuqHJaxs76HtZryI/K3H7KJ/KDIhqcbJ7kI4ar
+XL+sMgXnX0D+Te2Iy5xdP8yueSlQB/x/ED2BTAtyE3K4SYUN6AMNfbO63f4lBW3bUJPbTL+mjSxS
+PyRfJkZRgj+VbFv+EzHFi5pKwUEepa4JslMnwkowSRCXI+m5XvEOvtuBrxHdhLalG0JofYBok6qj
+YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t
+s3az+sj7eA0jfgPfeoN1
+""")
+
+MH_MAGIC = 0xfeedface
+MH_CIGAM = 0xcefaedfe
+MH_MAGIC_64 = 0xfeedfacf
+MH_CIGAM_64 = 0xcffaedfe
+FAT_MAGIC = 0xcafebabe
+BIG_ENDIAN = '>'
+LITTLE_ENDIAN = '<'
+LC_LOAD_DYLIB = 0xc
+maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')
+
+
+class fileview(object):
+ """
+ A proxy for file-like objects that exposes a given view of a file.
+ Modified from macholib.
+ """
+
+ def __init__(self, fileobj, start=0, size=maxint):
+ if isinstance(fileobj, fileview):
+ self._fileobj = fileobj._fileobj
+ else:
+ self._fileobj = fileobj
+ self._start = start
+ self._end = start + size
+ self._pos = 0
+
+ def __repr__(self):
+ return '' % (
+ self._start, self._end, self._fileobj)
+
+ def tell(self):
+ return self._pos
+
+ def _checkwindow(self, seekto, op):
+ if not (self._start <= seekto <= self._end):
+ raise IOError("%s to offset %d is outside window [%d, %d]" % (
+ op, seekto, self._start, self._end))
+
+ def seek(self, offset, whence=0):
+ seekto = offset
+ if whence == os.SEEK_SET:
+ seekto += self._start
+ elif whence == os.SEEK_CUR:
+ seekto += self._start + self._pos
+ elif whence == os.SEEK_END:
+ seekto += self._end
+ else:
+ raise IOError("Invalid whence argument to seek: %r" % (whence,))
+ self._checkwindow(seekto, 'seek')
+ self._fileobj.seek(seekto)
+ self._pos = seekto - self._start
+
+ def write(self, bytes):
+ here = self._start + self._pos
+ self._checkwindow(here, 'write')
+ self._checkwindow(here + len(bytes), 'write')
+ self._fileobj.seek(here, os.SEEK_SET)
+ self._fileobj.write(bytes)
+ self._pos += len(bytes)
+
+ def read(self, size=maxint):
+ assert size >= 0
+ here = self._start + self._pos
+ self._checkwindow(here, 'read')
+ size = min(size, self._end - here)
+ self._fileobj.seek(here, os.SEEK_SET)
+ bytes = self._fileobj.read(size)
+ self._pos += len(bytes)
+ return bytes
+
+
+def read_data(file, endian, num=1):
+ """
+ Read a given number of 32-bits unsigned integers from the given file
+ with the given endianness.
+ """
+ res = struct.unpack(endian + 'L' * num, file.read(num * 4))
+ if len(res) == 1:
+ return res[0]
+ return res
+
+
+def mach_o_change(path, what, value):
+ """
+ Replace a given name (what) in any LC_LOAD_DYLIB command found in
+ the given binary with a new name (value), provided it's shorter.
+ """
+
+ def do_macho(file, bits, endian):
+ # Read Mach-O header (the magic number is assumed read by the caller)
+ cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)
+ # 64-bits header has one more field.
+ if bits == 64:
+ read_data(file, endian)
+ # The header is followed by ncmds commands
+ for n in range(ncmds):
+ where = file.tell()
+ # Read command header
+ cmd, cmdsize = read_data(file, endian, 2)
+ if cmd == LC_LOAD_DYLIB:
+ # The first data field in LC_LOAD_DYLIB commands is the
+ # offset of the name, starting from the beginning of the
+ # command.
+ name_offset = read_data(file, endian)
+ file.seek(where + name_offset, os.SEEK_SET)
+ # Read the NUL terminated string
+ load = file.read(cmdsize - name_offset).decode()
+ load = load[:load.index('\0')]
+ # If the string is what is being replaced, overwrite it.
+ if load == what:
+ file.seek(where + name_offset, os.SEEK_SET)
+ file.write(value.encode() + '\0'.encode())
+ # Seek to the next command
+ file.seek(where + cmdsize, os.SEEK_SET)
+
+ def do_file(file, offset=0, size=maxint):
+ file = fileview(file, offset, size)
+ # Read magic number
+ magic = read_data(file, BIG_ENDIAN)
+ if magic == FAT_MAGIC:
+ # Fat binaries contain nfat_arch Mach-O binaries
+ nfat_arch = read_data(file, BIG_ENDIAN)
+ for n in range(nfat_arch):
+ # Read arch header
+ cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)
+ do_file(file, offset, size)
+ elif magic == MH_MAGIC:
+ do_macho(file, 32, BIG_ENDIAN)
+ elif magic == MH_CIGAM:
+ do_macho(file, 32, LITTLE_ENDIAN)
+ elif magic == MH_MAGIC_64:
+ do_macho(file, 64, BIG_ENDIAN)
+ elif magic == MH_CIGAM_64:
+ do_macho(file, 64, LITTLE_ENDIAN)
+
+ assert(len(what) >= len(value))
+ do_file(open(path, 'r+b'))
+
+
+if __name__ == '__main__':
+ main()
+
+## TODO:
+## Copy python.exe.manifest
+## Monkeypatch distutils.sysconfig
diff --git a/third-party/cxxtest/admin/virtualenv_1.7.py b/third-party/cxxtest/admin/virtualenv_1.7.py
new file mode 100755
index 00000000..5b4951db
--- /dev/null
+++ b/third-party/cxxtest/admin/virtualenv_1.7.py
@@ -0,0 +1,2102 @@
+#!/usr/bin/env python
+"""Create a "virtual" Python installation
+"""
+
+# If you change the version here, change it in setup.py
+# and docs/conf.py as well.
+virtualenv_version = "1.7"
+
+import base64
+import sys
+import os
+import optparse
+import re
+import shutil
+import logging
+import tempfile
+import zlib
+import errno
+import distutils.sysconfig
+from distutils.util import strtobool
+
+try:
+ import subprocess
+except ImportError:
+ if sys.version_info <= (2, 3):
+ print('ERROR: %s' % sys.exc_info()[1])
+ print('ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.')
+ print('If you copy subprocess.py from a newer version of Python this script will probably work')
+ sys.exit(101)
+ else:
+ raise
+try:
+ set
+except NameError:
+ from sets import Set as set
+try:
+ basestring
+except NameError:
+ basestring = str
+
+try:
+ import ConfigParser
+except ImportError:
+ import configparser as ConfigParser
+
+join = os.path.join
+py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
+
+is_jython = sys.platform.startswith('java')
+is_pypy = hasattr(sys, 'pypy_version_info')
+is_win = (sys.platform == 'win32')
+abiflags = getattr(sys, 'abiflags', '')
+
+user_dir = os.path.expanduser('~')
+if sys.platform == 'win32':
+ user_dir = os.environ.get('APPDATA', user_dir) # Use %APPDATA% for roaming
+ default_storage_dir = os.path.join(user_dir, 'virtualenv')
+else:
+ default_storage_dir = os.path.join(user_dir, '.virtualenv')
+default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini')
+
+if is_pypy:
+ expected_exe = 'pypy'
+elif is_jython:
+ expected_exe = 'jython'
+else:
+ expected_exe = 'python'
+
+
+REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
+ 'fnmatch', 'locale', 'encodings', 'codecs',
+ 'stat', 'UserDict', 'readline', 'copy_reg', 'types',
+ 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
+ 'zlib']
+
+REQUIRED_FILES = ['lib-dynload', 'config']
+
+majver, minver = sys.version_info[:2]
+if majver == 2:
+ if minver >= 6:
+ REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
+ if minver >= 7:
+ REQUIRED_MODULES.extend(['_weakrefset'])
+ if minver <= 3:
+ REQUIRED_MODULES.extend(['sets', '__future__'])
+elif majver == 3:
+ # Some extra modules are needed for Python 3, but different ones
+ # for different versions.
+ REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io',
+ '_weakrefset', 'copyreg', 'tempfile', 'random',
+ '__future__', 'collections', 'keyword', 'tarfile',
+ 'shutil', 'struct', 'copy'])
+ if minver >= 2:
+ REQUIRED_FILES[-1] = 'config-%s' % majver
+ if minver == 3:
+ # The whole list of 3.3 modules is reproduced below - the current
+ # uncommented ones are required for 3.3 as of now, but more may be
+ # added as 3.3 development continues.
+ REQUIRED_MODULES.extend([
+ #"aifc",
+ #"antigravity",
+ #"argparse",
+ #"ast",
+ #"asynchat",
+ #"asyncore",
+ "base64",
+ #"bdb",
+ #"binhex",
+ "bisect",
+ #"calendar",
+ #"cgi",
+ #"cgitb",
+ #"chunk",
+ #"cmd",
+ #"codeop",
+ #"code",
+ #"colorsys",
+ #"_compat_pickle",
+ #"compileall",
+ #"concurrent",
+ #"configparser",
+ #"contextlib",
+ #"cProfile",
+ #"crypt",
+ #"csv",
+ #"ctypes",
+ #"curses",
+ #"datetime",
+ #"dbm",
+ #"decimal",
+ #"difflib",
+ #"dis",
+ #"doctest",
+ #"dummy_threading",
+ "_dummy_thread",
+ #"email",
+ #"filecmp",
+ #"fileinput",
+ #"formatter",
+ #"fractions",
+ #"ftplib",
+ #"functools",
+ #"getopt",
+ #"getpass",
+ #"gettext",
+ #"glob",
+ #"gzip",
+ "hashlib",
+ "heapq",
+ "hmac",
+ #"html",
+ #"http",
+ #"idlelib",
+ #"imaplib",
+ #"imghdr",
+ #"importlib",
+ #"inspect",
+ #"json",
+ #"lib2to3",
+ #"logging",
+ #"macpath",
+ #"macurl2path",
+ #"mailbox",
+ #"mailcap",
+ #"_markupbase",
+ #"mimetypes",
+ #"modulefinder",
+ #"multiprocessing",
+ #"netrc",
+ #"nntplib",
+ #"nturl2path",
+ #"numbers",
+ #"opcode",
+ #"optparse",
+ #"os2emxpath",
+ #"pdb",
+ #"pickle",
+ #"pickletools",
+ #"pipes",
+ #"pkgutil",
+ #"platform",
+ #"plat-linux2",
+ #"plistlib",
+ #"poplib",
+ #"pprint",
+ #"profile",
+ #"pstats",
+ #"pty",
+ #"pyclbr",
+ #"py_compile",
+ #"pydoc_data",
+ #"pydoc",
+ #"_pyio",
+ #"queue",
+ #"quopri",
+ "reprlib",
+ "rlcompleter",
+ #"runpy",
+ #"sched",
+ #"shelve",
+ #"shlex",
+ #"smtpd",
+ #"smtplib",
+ #"sndhdr",
+ #"socket",
+ #"socketserver",
+ #"sqlite3",
+ #"ssl",
+ #"stringprep",
+ #"string",
+ #"_strptime",
+ #"subprocess",
+ #"sunau",
+ #"symbol",
+ #"symtable",
+ #"sysconfig",
+ #"tabnanny",
+ #"telnetlib",
+ #"test",
+ #"textwrap",
+ #"this",
+ #"_threading_local",
+ #"threading",
+ #"timeit",
+ #"tkinter",
+ #"tokenize",
+ #"token",
+ #"traceback",
+ #"trace",
+ #"tty",
+ #"turtledemo",
+ #"turtle",
+ #"unittest",
+ #"urllib",
+ #"uuid",
+ #"uu",
+ #"wave",
+ "weakref",
+ #"webbrowser",
+ #"wsgiref",
+ #"xdrlib",
+ #"xml",
+ #"xmlrpc",
+ #"zipfile",
+ ])
+
+if is_pypy:
+ # these are needed to correctly display the exceptions that may happen
+ # during the bootstrap
+ REQUIRED_MODULES.extend(['traceback', 'linecache'])
+
+class Logger(object):
+
+ """
+ Logging object for use in command-line script. Allows ranges of
+ levels, to avoid some redundancy of displayed information.
+ """
+
+ DEBUG = logging.DEBUG
+ INFO = logging.INFO
+ NOTIFY = (logging.INFO+logging.WARN)/2
+ WARN = WARNING = logging.WARN
+ ERROR = logging.ERROR
+ FATAL = logging.FATAL
+
+ LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
+
+ def __init__(self, consumers):
+ self.consumers = consumers
+ self.indent = 0
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def debug(self, msg, *args, **kw):
+ self.log(self.DEBUG, msg, *args, **kw)
+ def info(self, msg, *args, **kw):
+ self.log(self.INFO, msg, *args, **kw)
+ def notify(self, msg, *args, **kw):
+ self.log(self.NOTIFY, msg, *args, **kw)
+ def warn(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def error(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def fatal(self, msg, *args, **kw):
+ self.log(self.FATAL, msg, *args, **kw)
+ def log(self, level, msg, *args, **kw):
+ if args:
+ if kw:
+ raise TypeError(
+ "You may give positional or keyword arguments, not both")
+ args = args or kw
+ rendered = None
+ for consumer_level, consumer in self.consumers:
+ if self.level_matches(level, consumer_level):
+ if (self.in_progress_hanging
+ and consumer in (sys.stdout, sys.stderr)):
+ self.in_progress_hanging = False
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ if rendered is None:
+ if args:
+ rendered = msg % args
+ else:
+ rendered = msg
+ rendered = ' '*self.indent + rendered
+ if hasattr(consumer, 'write'):
+ consumer.write(rendered+'\n')
+ else:
+ consumer(rendered)
+
+ def start_progress(self, msg):
+ assert not self.in_progress, (
+ "Tried to start_progress(%r) while in_progress %r"
+ % (msg, self.in_progress))
+ if self.level_matches(self.NOTIFY, self._stdout_level()):
+ sys.stdout.write(msg)
+ sys.stdout.flush()
+ self.in_progress_hanging = True
+ else:
+ self.in_progress_hanging = False
+ self.in_progress = msg
+
+ def end_progress(self, msg='done.'):
+ assert self.in_progress, (
+ "Tried to end_progress without start_progress")
+ if self.stdout_level_matches(self.NOTIFY):
+ if not self.in_progress_hanging:
+ # Some message has been printed out since start_progress
+ sys.stdout.write('...' + self.in_progress + msg + '\n')
+ sys.stdout.flush()
+ else:
+ sys.stdout.write(msg + '\n')
+ sys.stdout.flush()
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def show_progress(self):
+ """If we are in a progress scope, and no log messages have been
+ shown, write out another '.'"""
+ if self.in_progress_hanging:
+ sys.stdout.write('.')
+ sys.stdout.flush()
+
+ def stdout_level_matches(self, level):
+ """Returns true if a message at this level will go to stdout"""
+ return self.level_matches(level, self._stdout_level())
+
+ def _stdout_level(self):
+ """Returns the level that stdout runs at"""
+ for level, consumer in self.consumers:
+ if consumer is sys.stdout:
+ return level
+ return self.FATAL
+
+ def level_matches(self, level, consumer_level):
+ """
+ >>> l = Logger([])
+ >>> l.level_matches(3, 4)
+ False
+ >>> l.level_matches(3, 2)
+ True
+ >>> l.level_matches(slice(None, 3), 3)
+ False
+ >>> l.level_matches(slice(None, 3), 2)
+ True
+ >>> l.level_matches(slice(1, 3), 1)
+ True
+ >>> l.level_matches(slice(2, 3), 1)
+ False
+ """
+ if isinstance(level, slice):
+ start, stop = level.start, level.stop
+ if start is not None and start > consumer_level:
+ return False
+ if stop is not None and stop <= consumer_level:
+ return False
+ return True
+ else:
+ return level >= consumer_level
+
+ #@classmethod
+ def level_for_integer(cls, level):
+ levels = cls.LEVELS
+ if level < 0:
+ return levels[0]
+ if level >= len(levels):
+ return levels[-1]
+ return levels[level]
+
+ level_for_integer = classmethod(level_for_integer)
+
+# create a silent logger just to prevent this from being undefined
+# will be overridden with requested verbosity main() is called.
+logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
+
+def mkdir(path):
+ if not os.path.exists(path):
+ logger.info('Creating %s', path)
+ os.makedirs(path)
+ else:
+ logger.info('Directory %s already exists', path)
+
+def copyfileordir(src, dest):
+ if os.path.isdir(src):
+ shutil.copytree(src, dest, True)
+ else:
+ shutil.copy2(src, dest)
+
+def copyfile(src, dest, symlink=True):
+ if not os.path.exists(src):
+ # Some bad symlink in the src
+ logger.warn('Cannot find file %s (bad symlink)', src)
+ return
+ if os.path.exists(dest):
+ logger.debug('File %s already exists', dest)
+ return
+ if not os.path.exists(os.path.dirname(dest)):
+ logger.info('Creating parent directories for %s' % os.path.dirname(dest))
+ os.makedirs(os.path.dirname(dest))
+ if not os.path.islink(src):
+ srcpath = os.path.abspath(src)
+ else:
+ srcpath = os.readlink(src)
+ if symlink and hasattr(os, 'symlink'):
+ logger.info('Symlinking %s', dest)
+ try:
+ os.symlink(srcpath, dest)
+ except (OSError, NotImplementedError):
+ logger.info('Symlinking failed, copying to %s', dest)
+ copyfileordir(src, dest)
+ else:
+ logger.info('Copying to %s', dest)
+ copyfileordir(src, dest)
+
+def writefile(dest, content, overwrite=True):
+ if not os.path.exists(dest):
+ logger.info('Writing %s', dest)
+ f = open(dest, 'wb')
+ f.write(content.encode('utf-8'))
+ f.close()
+ return
+ else:
+ f = open(dest, 'rb')
+ c = f.read()
+ f.close()
+ if c != content:
+ if not overwrite:
+ logger.notify('File %s exists with different content; not overwriting', dest)
+ return
+ logger.notify('Overwriting %s with new content', dest)
+ f = open(dest, 'wb')
+ f.write(content.encode('utf-8'))
+ f.close()
+ else:
+ logger.info('Content %s already in place', dest)
+
+def rmtree(dir):
+ if os.path.exists(dir):
+ logger.notify('Deleting tree %s', dir)
+ shutil.rmtree(dir)
+ else:
+ logger.info('Do not need to delete %s; already gone', dir)
+
+def make_exe(fn):
+ if hasattr(os, 'chmod'):
+ oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
+ newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
+ os.chmod(fn, newmode)
+ logger.info('Changed mode of %s to %s', fn, oct(newmode))
+
+def _find_file(filename, dirs):
+ for dir in dirs:
+ if os.path.exists(join(dir, filename)):
+ return join(dir, filename)
+ return filename
+
+def _install_req(py_executable, unzip=False, distribute=False,
+ search_dirs=None, never_download=False):
+
+ if search_dirs is None:
+ search_dirs = file_search_dirs()
+
+ if not distribute:
+ setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
+ project_name = 'setuptools'
+ bootstrap_script = EZ_SETUP_PY
+ source = None
+ else:
+ setup_fn = None
+ source = 'distribute-0.6.24.tar.gz'
+ project_name = 'distribute'
+ bootstrap_script = DISTRIBUTE_SETUP_PY
+
+ if setup_fn is not None:
+ setup_fn = _find_file(setup_fn, search_dirs)
+
+ if source is not None:
+ source = _find_file(source, search_dirs)
+
+ if is_jython and os._name == 'nt':
+ # Jython's .bat sys.executable can't handle a command line
+ # argument with newlines
+ fd, ez_setup = tempfile.mkstemp('.py')
+ os.write(fd, bootstrap_script)
+ os.close(fd)
+ cmd = [py_executable, ez_setup]
+ else:
+ cmd = [py_executable, '-c', bootstrap_script]
+ if unzip:
+ cmd.append('--always-unzip')
+ env = {}
+ remove_from_env = []
+ if logger.stdout_level_matches(logger.DEBUG):
+ cmd.append('-v')
+
+ old_chdir = os.getcwd()
+ if setup_fn is not None and os.path.exists(setup_fn):
+ logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
+ cmd.append(setup_fn)
+ if os.environ.get('PYTHONPATH'):
+ env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
+ else:
+ env['PYTHONPATH'] = setup_fn
+ else:
+ # the source is found, let's chdir
+ if source is not None and os.path.exists(source):
+ logger.info('Using existing %s egg: %s' % (project_name, source))
+ os.chdir(os.path.dirname(source))
+ # in this case, we want to be sure that PYTHONPATH is unset (not
+ # just empty, really unset), else CPython tries to import the
+ # site.py that it's in virtualenv_support
+ remove_from_env.append('PYTHONPATH')
+ else:
+ if never_download:
+ logger.fatal("Can't find any local distributions of %s to install "
+ "and --never-download is set. Either re-run virtualenv "
+ "without the --never-download option, or place a %s "
+ "distribution (%s) in one of these "
+ "locations: %r" % (project_name, project_name,
+ setup_fn or source,
+ search_dirs))
+ sys.exit(1)
+
+ logger.info('No %s egg found; downloading' % project_name)
+ cmd.extend(['--always-copy', '-U', project_name])
+ logger.start_progress('Installing %s...' % project_name)
+ logger.indent += 2
+ cwd = None
+ if project_name == 'distribute':
+ env['DONT_PATCH_SETUPTOOLS'] = 'true'
+
+ def _filter_ez_setup(line):
+ return filter_ez_setup(line, project_name)
+
+ if not os.access(os.getcwd(), os.W_OK):
+ cwd = tempfile.mkdtemp()
+ if source is not None and os.path.exists(source):
+ # the current working dir is hostile, let's copy the
+ # tarball to a temp dir
+ target = os.path.join(cwd, os.path.split(source)[-1])
+ shutil.copy(source, target)
+ try:
+ call_subprocess(cmd, show_stdout=False,
+ filter_stdout=_filter_ez_setup,
+ extra_env=env,
+ remove_from_env=remove_from_env,
+ cwd=cwd)
+ finally:
+ logger.indent -= 2
+ logger.end_progress()
+ if os.getcwd() != old_chdir:
+ os.chdir(old_chdir)
+ if is_jython and os._name == 'nt':
+ os.remove(ez_setup)
+
+def file_search_dirs():
+ here = os.path.dirname(os.path.abspath(__file__))
+ dirs = ['.', here,
+ join(here, 'virtualenv_support')]
+ if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
+ # Probably some boot script; just in case virtualenv is installed...
+ try:
+ import virtualenv
+ except ImportError:
+ pass
+ else:
+ dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
+ return [d for d in dirs if os.path.isdir(d)]
+
+def install_setuptools(py_executable, unzip=False,
+ search_dirs=None, never_download=False):
+ _install_req(py_executable, unzip,
+ search_dirs=search_dirs, never_download=never_download)
+
+def install_distribute(py_executable, unzip=False,
+ search_dirs=None, never_download=False):
+ _install_req(py_executable, unzip, distribute=True,
+ search_dirs=search_dirs, never_download=never_download)
+
+_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
+def install_pip(py_executable, search_dirs=None, never_download=False):
+ if search_dirs is None:
+ search_dirs = file_search_dirs()
+
+ filenames = []
+ for dir in search_dirs:
+ filenames.extend([join(dir, fn) for fn in os.listdir(dir)
+ if _pip_re.search(fn)])
+ filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
+ filenames.sort()
+ filenames = [filename for basename, i, filename in filenames]
+ if not filenames:
+ filename = 'pip'
+ else:
+ filename = filenames[-1]
+ easy_install_script = 'easy_install'
+ if sys.platform == 'win32':
+ easy_install_script = 'easy_install-script.py'
+ cmd = [join(os.path.dirname(py_executable), easy_install_script), filename]
+ if sys.platform == 'win32':
+ cmd.insert(0, py_executable)
+ if filename == 'pip':
+ if never_download:
+ logger.fatal("Can't find any local distributions of pip to install "
+ "and --never-download is set. Either re-run virtualenv "
+ "without the --never-download option, or place a pip "
+ "source distribution (zip/tar.gz/tar.bz2) in one of these "
+ "locations: %r" % search_dirs)
+ sys.exit(1)
+ logger.info('Installing pip from network...')
+ else:
+ logger.info('Installing existing %s distribution: %s' % (
+ os.path.basename(filename), filename))
+ logger.start_progress('Installing pip...')
+ logger.indent += 2
+ def _filter_setup(line):
+ return filter_ez_setup(line, 'pip')
+ try:
+ call_subprocess(cmd, show_stdout=False,
+ filter_stdout=_filter_setup)
+ finally:
+ logger.indent -= 2
+ logger.end_progress()
+
+def filter_ez_setup(line, project_name='setuptools'):
+ if not line.strip():
+ return Logger.DEBUG
+ if project_name == 'distribute':
+ for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
+ 'Scanning', 'Setuptools', 'Egg', 'Already',
+ 'running', 'writing', 'reading', 'installing',
+ 'creating', 'copying', 'byte-compiling', 'removing',
+ 'Processing'):
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.DEBUG
+ for prefix in ['Reading ', 'Best match', 'Processing setuptools',
+ 'Copying setuptools', 'Adding setuptools',
+ 'Installing ', 'Installed ']:
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.INFO
+
+
+class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
+ """
+ Custom help formatter for use in ConfigOptionParser that updates
+ the defaults before expanding them, allowing them to show up correctly
+ in the help listing
+ """
+ def expand_default(self, option):
+ if self.parser is not None:
+ self.parser.update_defaults(self.parser.defaults)
+ return optparse.IndentedHelpFormatter.expand_default(self, option)
+
+
+class ConfigOptionParser(optparse.OptionParser):
+ """
+ Custom option parser which updates its defaults by by checking the
+ configuration files and environmental variables
+ """
+ def __init__(self, *args, **kwargs):
+ self.config = ConfigParser.RawConfigParser()
+ self.files = self.get_config_files()
+ self.config.read(self.files)
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+
+ def get_config_files(self):
+ config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False)
+ if config_file and os.path.exists(config_file):
+ return [config_file]
+ return [default_config_file]
+
+ def update_defaults(self, defaults):
+ """
+ Updates the given defaults with values from the config files and
+ the environ. Does a little special handling for certain types of
+ options (lists).
+ """
+ # Then go and look for the other sources of configuration:
+ config = {}
+ # 1. config files
+ config.update(dict(self.get_config_section('virtualenv')))
+ # 2. environmental variables
+ config.update(dict(self.get_environ_vars()))
+ # Then set the options with those values
+ for key, val in config.items():
+ key = key.replace('_', '-')
+ if not key.startswith('--'):
+ key = '--%s' % key # only prefer long opts
+ option = self.get_option(key)
+ if option is not None:
+ # ignore empty values
+ if not val:
+ continue
+ # handle multiline configs
+ if option.action == 'append':
+ val = val.split()
+ else:
+ option.nargs = 1
+ if option.action in ('store_true', 'store_false', 'count'):
+ val = strtobool(val)
+ try:
+ val = option.convert_value(key, val)
+ except optparse.OptionValueError:
+ e = sys.exc_info()[1]
+ print("An error occured during configuration: %s" % e)
+ sys.exit(3)
+ defaults[option.dest] = val
+ return defaults
+
+ def get_config_section(self, name):
+ """
+ Get a section of a configuration
+ """
+ if self.config.has_section(name):
+ return self.config.items(name)
+ return []
+
+ def get_environ_vars(self, prefix='VIRTUALENV_'):
+ """
+ Returns a generator with all environmental vars with prefix VIRTUALENV
+ """
+ for key, val in os.environ.items():
+ if key.startswith(prefix):
+ yield (key.replace(prefix, '').lower(), val)
+
+ def get_default_values(self):
+ """
+ Overridding to make updating the defaults after instantiation of
+ the option parser possible, update_defaults() does the dirty work.
+ """
+ if not self.process_default_values:
+ # Old, pre-Optik 1.5 behaviour.
+ return optparse.Values(self.defaults)
+
+ defaults = self.update_defaults(self.defaults.copy()) # ours
+ for option in self._get_all_options():
+ default = defaults.get(option.dest)
+ if isinstance(default, basestring):
+ opt_str = option.get_opt_string()
+ defaults[option.dest] = option.check_value(opt_str, default)
+ return optparse.Values(defaults)
+
+
+def main():
+ parser = ConfigOptionParser(
+ version=virtualenv_version,
+ usage="%prog [OPTIONS] DEST_DIR",
+ formatter=UpdatingDefaultsHelpFormatter())
+
+ parser.add_option(
+ '-v', '--verbose',
+ action='count',
+ dest='verbose',
+ default=0,
+ help="Increase verbosity")
+
+ parser.add_option(
+ '-q', '--quiet',
+ action='count',
+ dest='quiet',
+ default=0,
+ help='Decrease verbosity')
+
+ parser.add_option(
+ '-p', '--python',
+ dest='python',
+ metavar='PYTHON_EXE',
+ help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
+ 'interpreter to create the new environment. The default is the interpreter that '
+ 'virtualenv was installed with (%s)' % sys.executable)
+
+ parser.add_option(
+ '--clear',
+ dest='clear',
+ action='store_true',
+ help="Clear out the non-root install and start from scratch")
+
+ parser.add_option(
+ '--no-site-packages',
+ dest='no_site_packages',
+ action='store_true',
+ help="Don't give access to the global site-packages dir to the "
+ "virtual environment")
+
+ parser.add_option(
+ '--system-site-packages',
+ dest='system_site_packages',
+ action='store_true',
+ help="Give access to the global site-packages dir to the "
+ "virtual environment")
+
+ parser.add_option(
+ '--unzip-setuptools',
+ dest='unzip_setuptools',
+ action='store_true',
+ help="Unzip Setuptools or Distribute when installing it")
+
+ parser.add_option(
+ '--relocatable',
+ dest='relocatable',
+ action='store_true',
+ help='Make an EXISTING virtualenv environment relocatable. '
+ 'This fixes up scripts and makes all .pth files relative')
+
+ parser.add_option(
+ '--distribute',
+ dest='use_distribute',
+ action='store_true',
+ help='Use Distribute instead of Setuptools. Set environ variable '
+ 'VIRTUALENV_DISTRIBUTE to make it the default ')
+
+ default_search_dirs = file_search_dirs()
+ parser.add_option(
+ '--extra-search-dir',
+ dest="search_dirs",
+ action="append",
+ default=default_search_dirs,
+ help="Directory to look for setuptools/distribute/pip distributions in. "
+ "You can add any number of additional --extra-search-dir paths.")
+
+ parser.add_option(
+ '--never-download',
+ dest="never_download",
+ action="store_true",
+ help="Never download anything from the network. Instead, virtualenv will fail "
+ "if local distributions of setuptools/distribute/pip are not present.")
+
+ parser.add_option(
+ '--prompt=',
+ dest='prompt',
+ help='Provides an alternative prompt prefix for this environment')
+
+ if 'extend_parser' in globals():
+ extend_parser(parser)
+
+ options, args = parser.parse_args()
+
+ global logger
+
+ if 'adjust_options' in globals():
+ adjust_options(options, args)
+
+ verbosity = options.verbose - options.quiet
+ logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
+
+ if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
+ env = os.environ.copy()
+ interpreter = resolve_interpreter(options.python)
+ if interpreter == sys.executable:
+ logger.warn('Already using interpreter %s' % interpreter)
+ else:
+ logger.notify('Running virtualenv with interpreter %s' % interpreter)
+ env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
+ file = __file__
+ if file.endswith('.pyc'):
+ file = file[:-1]
+ popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
+ raise SystemExit(popen.wait())
+
+ # Force --use-distribute on Python 3, since setuptools is not available.
+ if majver > 2:
+ options.use_distribute = True
+
+ if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute:
+ print(
+ "The PYTHONDONTWRITEBYTECODE environment variable is "
+ "not compatible with setuptools. Either use --distribute "
+ "or unset PYTHONDONTWRITEBYTECODE.")
+ sys.exit(2)
+ if not args:
+ print('You must provide a DEST_DIR')
+ parser.print_help()
+ sys.exit(2)
+ if len(args) > 1:
+ print('There must be only one argument: DEST_DIR (you gave %s)' % (
+ ' '.join(args)))
+ parser.print_help()
+ sys.exit(2)
+
+ home_dir = args[0]
+
+ if os.environ.get('WORKING_ENV'):
+ logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
+ logger.fatal('Please deactivate your workingenv, then re-run this script')
+ sys.exit(3)
+
+ if 'PYTHONHOME' in os.environ:
+ logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
+ del os.environ['PYTHONHOME']
+
+ if options.relocatable:
+ make_environment_relocatable(home_dir)
+ return
+
+ if options.no_site_packages:
+ logger.warn('The --no-site-packages flag is deprecated; it is now '
+ 'the default behavior.')
+
+ create_environment(home_dir,
+ site_packages=options.system_site_packages,
+ clear=options.clear,
+ unzip_setuptools=options.unzip_setuptools,
+ use_distribute=options.use_distribute,
+ prompt=options.prompt,
+ search_dirs=options.search_dirs,
+ never_download=options.never_download)
+ if 'after_install' in globals():
+ after_install(options, home_dir)
+
+def call_subprocess(cmd, show_stdout=True,
+ filter_stdout=None, cwd=None,
+ raise_on_returncode=True, extra_env=None,
+ remove_from_env=None):
+ cmd_parts = []
+ for part in cmd:
+ if len(part) > 45:
+ part = part[:20]+"..."+part[-20:]
+ if ' ' in part or '\n' in part or '"' in part or "'" in part:
+ part = '"%s"' % part.replace('"', '\\"')
+ if hasattr(part, 'decode'):
+ try:
+ part = part.decode(sys.getdefaultencoding())
+ except UnicodeDecodeError:
+ part = part.decode(sys.getfilesystemencoding())
+ cmd_parts.append(part)
+ cmd_desc = ' '.join(cmd_parts)
+ if show_stdout:
+ stdout = None
+ else:
+ stdout = subprocess.PIPE
+ logger.debug("Running command %s" % cmd_desc)
+ if extra_env or remove_from_env:
+ env = os.environ.copy()
+ if extra_env:
+ env.update(extra_env)
+ if remove_from_env:
+ for varname in remove_from_env:
+ env.pop(varname, None)
+ else:
+ env = None
+ try:
+ proc = subprocess.Popen(
+ cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
+ cwd=cwd, env=env)
+ except Exception:
+ e = sys.exc_info()[1]
+ logger.fatal(
+ "Error %s while executing command %s" % (e, cmd_desc))
+ raise
+ all_output = []
+ if stdout is not None:
+ stdout = proc.stdout
+ encoding = sys.getdefaultencoding()
+ fs_encoding = sys.getfilesystemencoding()
+ while 1:
+ line = stdout.readline()
+ try:
+ line = line.decode(encoding)
+ except UnicodeDecodeError:
+ line = line.decode(fs_encoding)
+ if not line:
+ break
+ line = line.rstrip()
+ all_output.append(line)
+ if filter_stdout:
+ level = filter_stdout(line)
+ if isinstance(level, tuple):
+ level, line = level
+ logger.log(level, line)
+ if not logger.stdout_level_matches(level):
+ logger.show_progress()
+ else:
+ logger.info(line)
+ else:
+ proc.communicate()
+ proc.wait()
+ if proc.returncode:
+ if raise_on_returncode:
+ if all_output:
+ logger.notify('Complete output from command %s:' % cmd_desc)
+ logger.notify('\n'.join(all_output) + '\n----------------------------------------')
+ raise OSError(
+ "Command %s failed with error code %s"
+ % (cmd_desc, proc.returncode))
+ else:
+ logger.warn(
+ "Command %s had error code %s"
+ % (cmd_desc, proc.returncode))
+
+
+def create_environment(home_dir, site_packages=False, clear=False,
+ unzip_setuptools=False, use_distribute=False,
+ prompt=None, search_dirs=None, never_download=False):
+ """
+ Creates a new environment in ``home_dir``.
+
+ If ``site_packages`` is true, then the global ``site-packages/``
+ directory will be on the path.
+
+ If ``clear`` is true (default False) then the environment will
+ first be cleared.
+ """
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+
+ py_executable = os.path.abspath(install_python(
+ home_dir, lib_dir, inc_dir, bin_dir,
+ site_packages=site_packages, clear=clear))
+
+ install_distutils(home_dir)
+
+ # use_distribute also is True if VIRTUALENV_DISTRIBUTE env var is set
+ # we also check VIRTUALENV_USE_DISTRIBUTE for backwards compatibility
+ if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
+ install_distribute(py_executable, unzip=unzip_setuptools,
+ search_dirs=search_dirs, never_download=never_download)
+ else:
+ install_setuptools(py_executable, unzip=unzip_setuptools,
+ search_dirs=search_dirs, never_download=never_download)
+
+ install_pip(py_executable, search_dirs=search_dirs, never_download=never_download)
+
+ install_activate(home_dir, bin_dir, prompt)
+
+def path_locations(home_dir):
+ """Return the path locations for the environment (where libraries are,
+ where scripts go, etc)"""
+ # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
+ # prefix arg is broken: http://bugs.python.org/issue3386
+ if sys.platform == 'win32':
+ # Windows has lots of problems with executables with spaces in
+ # the name; this function will remove them (using the ~1
+ # format):
+ mkdir(home_dir)
+ if ' ' in home_dir:
+ try:
+ import win32api
+ except ImportError:
+ print('Error: the path "%s" has a space in it' % home_dir)
+ print('To handle these kinds of paths, the win32api module must be installed:')
+ print(' http://sourceforge.net/projects/pywin32/')
+ sys.exit(3)
+ home_dir = win32api.GetShortPathName(home_dir)
+ lib_dir = join(home_dir, 'Lib')
+ inc_dir = join(home_dir, 'Include')
+ bin_dir = join(home_dir, 'Scripts')
+ elif is_jython:
+ lib_dir = join(home_dir, 'Lib')
+ inc_dir = join(home_dir, 'Include')
+ bin_dir = join(home_dir, 'bin')
+ elif is_pypy:
+ lib_dir = home_dir
+ inc_dir = join(home_dir, 'include')
+ bin_dir = join(home_dir, 'bin')
+ else:
+ lib_dir = join(home_dir, 'lib', py_version)
+ inc_dir = join(home_dir, 'include', py_version + abiflags)
+ bin_dir = join(home_dir, 'bin')
+ return home_dir, lib_dir, inc_dir, bin_dir
+
+
+def change_prefix(filename, dst_prefix):
+ prefixes = [sys.prefix]
+
+ if sys.platform == "darwin":
+ prefixes.extend((
+ os.path.join("/Library/Python", sys.version[:3], "site-packages"),
+ os.path.join(sys.prefix, "Extras", "lib", "python"),
+ os.path.join("~", "Library", "Python", sys.version[:3], "site-packages")))
+
+ if hasattr(sys, 'real_prefix'):
+ prefixes.append(sys.real_prefix)
+ prefixes = list(map(os.path.abspath, prefixes))
+ filename = os.path.abspath(filename)
+ for src_prefix in prefixes:
+ if filename.startswith(src_prefix):
+ _, relpath = filename.split(src_prefix, 1)
+ assert relpath[0] == os.sep
+ relpath = relpath[1:]
+ return join(dst_prefix, relpath)
+ assert False, "Filename %s does not start with any of these prefixes: %s" % \
+ (filename, prefixes)
+
+def copy_required_modules(dst_prefix):
+ import imp
+ for modname in REQUIRED_MODULES:
+ if modname in sys.builtin_module_names:
+ logger.info("Ignoring built-in bootstrap module: %s" % modname)
+ continue
+ try:
+ f, filename, _ = imp.find_module(modname)
+ except ImportError:
+ logger.info("Cannot import bootstrap module: %s" % modname)
+ else:
+ if f is not None:
+ f.close()
+ dst_filename = change_prefix(filename, dst_prefix)
+ copyfile(filename, dst_filename)
+ if filename.endswith('.pyc'):
+ pyfile = filename[:-1]
+ if os.path.exists(pyfile):
+ copyfile(pyfile, dst_filename[:-1])
+
+
+def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
+ """Install just the base environment, no distutils patches etc"""
+ if sys.executable.startswith(bin_dir):
+ print('Please use the *system* python to run this script')
+ return
+
+ if clear:
+ rmtree(lib_dir)
+ ## FIXME: why not delete it?
+ ## Maybe it should delete everything with #!/path/to/venv/python in it
+ logger.notify('Not deleting %s', bin_dir)
+
+ if hasattr(sys, 'real_prefix'):
+ logger.notify('Using real prefix %r' % sys.real_prefix)
+ prefix = sys.real_prefix
+ else:
+ prefix = sys.prefix
+ mkdir(lib_dir)
+ fix_lib64(lib_dir)
+ fix_local_scheme(home_dir)
+ stdlib_dirs = [os.path.dirname(os.__file__)]
+ if sys.platform == 'win32':
+ stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
+ elif sys.platform == 'darwin':
+ stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
+ if hasattr(os, 'symlink'):
+ logger.info('Symlinking Python bootstrap modules')
+ else:
+ logger.info('Copying Python bootstrap modules')
+ logger.indent += 2
+ try:
+ # copy required files...
+ for stdlib_dir in stdlib_dirs:
+ if not os.path.isdir(stdlib_dir):
+ continue
+ for fn in os.listdir(stdlib_dir):
+ bn = os.path.splitext(fn)[0]
+ if fn != 'site-packages' and bn in REQUIRED_FILES:
+ copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
+ # ...and modules
+ copy_required_modules(home_dir)
+ finally:
+ logger.indent -= 2
+ mkdir(join(lib_dir, 'site-packages'))
+ import site
+ site_filename = site.__file__
+ if site_filename.endswith('.pyc'):
+ site_filename = site_filename[:-1]
+ elif site_filename.endswith('$py.class'):
+ site_filename = site_filename.replace('$py.class', '.py')
+ site_filename_dst = change_prefix(site_filename, home_dir)
+ site_dir = os.path.dirname(site_filename_dst)
+ writefile(site_filename_dst, SITE_PY)
+ writefile(join(site_dir, 'orig-prefix.txt'), prefix)
+ site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
+ if not site_packages:
+ writefile(site_packages_filename, '')
+ else:
+ if os.path.exists(site_packages_filename):
+ logger.info('Deleting %s' % site_packages_filename)
+ os.unlink(site_packages_filename)
+
+ if is_pypy or is_win:
+ stdinc_dir = join(prefix, 'include')
+ else:
+ stdinc_dir = join(prefix, 'include', py_version + abiflags)
+ if os.path.exists(stdinc_dir):
+ copyfile(stdinc_dir, inc_dir)
+ else:
+ logger.debug('No include dir %s' % stdinc_dir)
+
+ # pypy never uses exec_prefix, just ignore it
+ if sys.exec_prefix != prefix and not is_pypy:
+ if sys.platform == 'win32':
+ exec_dir = join(sys.exec_prefix, 'lib')
+ elif is_jython:
+ exec_dir = join(sys.exec_prefix, 'Lib')
+ else:
+ exec_dir = join(sys.exec_prefix, 'lib', py_version)
+ for fn in os.listdir(exec_dir):
+ copyfile(join(exec_dir, fn), join(lib_dir, fn))
+
+ if is_jython:
+ # Jython has either jython-dev.jar and javalib/ dir, or just
+ # jython.jar
+ for name in 'jython-dev.jar', 'javalib', 'jython.jar':
+ src = join(prefix, name)
+ if os.path.exists(src):
+ copyfile(src, join(home_dir, name))
+ # XXX: registry should always exist after Jython 2.5rc1
+ src = join(prefix, 'registry')
+ if os.path.exists(src):
+ copyfile(src, join(home_dir, 'registry'), symlink=False)
+ copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
+ symlink=False)
+
+ mkdir(bin_dir)
+ py_executable = join(bin_dir, os.path.basename(sys.executable))
+ if 'Python.framework' in prefix:
+ if re.search(r'/Python(?:-32|-64)*$', py_executable):
+ # The name of the python executable is not quite what
+ # we want, rename it.
+ py_executable = os.path.join(
+ os.path.dirname(py_executable), 'python')
+
+ logger.notify('New %s executable in %s', expected_exe, py_executable)
+ if sys.executable != py_executable:
+ ## FIXME: could I just hard link?
+ executable = sys.executable
+ if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
+ # Cygwin misreports sys.executable sometimes
+ executable += '.exe'
+ py_executable += '.exe'
+ logger.info('Executable actually exists in %s' % executable)
+ shutil.copyfile(executable, py_executable)
+ make_exe(py_executable)
+ if sys.platform == 'win32' or sys.platform == 'cygwin':
+ pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
+ if os.path.exists(pythonw):
+ logger.info('Also created pythonw.exe')
+ shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
+ if is_pypy:
+ # make a symlink python --> pypy-c
+ python_executable = os.path.join(os.path.dirname(py_executable), 'python')
+ logger.info('Also created executable %s' % python_executable)
+ copyfile(py_executable, python_executable)
+
+ if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
+ secondary_exe = os.path.join(os.path.dirname(py_executable),
+ expected_exe)
+ py_executable_ext = os.path.splitext(py_executable)[1]
+ if py_executable_ext == '.exe':
+ # python2.4 gives an extension of '.4' :P
+ secondary_exe += py_executable_ext
+ if os.path.exists(secondary_exe):
+ logger.warn('Not overwriting existing %s script %s (you must use %s)'
+ % (expected_exe, secondary_exe, py_executable))
+ else:
+ logger.notify('Also creating executable in %s' % secondary_exe)
+ shutil.copyfile(sys.executable, secondary_exe)
+ make_exe(secondary_exe)
+
+ if 'Python.framework' in prefix:
+ logger.debug('MacOSX Python framework detected')
+
+ # Make sure we use the the embedded interpreter inside
+ # the framework, even if sys.executable points to
+ # the stub executable in ${sys.prefix}/bin
+ # See http://groups.google.com/group/python-virtualenv/
+ # browse_thread/thread/17cab2f85da75951
+ original_python = os.path.join(
+ prefix, 'Resources/Python.app/Contents/MacOS/Python')
+ shutil.copy(original_python, py_executable)
+
+ # Copy the framework's dylib into the virtual
+ # environment
+ virtual_lib = os.path.join(home_dir, '.Python')
+
+ if os.path.exists(virtual_lib):
+ os.unlink(virtual_lib)
+ copyfile(
+ os.path.join(prefix, 'Python'),
+ virtual_lib)
+
+ # And then change the install_name of the copied python executable
+ try:
+ call_subprocess(
+ ["install_name_tool", "-change",
+ os.path.join(prefix, 'Python'),
+ '@executable_path/../.Python',
+ py_executable])
+ except:
+ logger.fatal(
+ "Could not call install_name_tool -- you must have Apple's development tools installed")
+ raise
+
+ # Some tools depend on pythonX.Y being present
+ py_executable_version = '%s.%s' % (
+ sys.version_info[0], sys.version_info[1])
+ if not py_executable.endswith(py_executable_version):
+ # symlinking pythonX.Y > python
+ pth = py_executable + '%s.%s' % (
+ sys.version_info[0], sys.version_info[1])
+ if os.path.exists(pth):
+ os.unlink(pth)
+ os.symlink('python', pth)
+ else:
+ # reverse symlinking python -> pythonX.Y (with --python)
+ pth = join(bin_dir, 'python')
+ if os.path.exists(pth):
+ os.unlink(pth)
+ os.symlink(os.path.basename(py_executable), pth)
+
+ if sys.platform == 'win32' and ' ' in py_executable:
+ # There's a bug with subprocess on Windows when using a first
+ # argument that has a space in it. Instead we have to quote
+ # the value:
+ py_executable = '"%s"' % py_executable
+ cmd = [py_executable, '-c', """
+import sys
+prefix = sys.prefix
+if sys.version_info[0] == 3:
+ prefix = prefix.encode('utf8')
+if hasattr(sys.stdout, 'detach'):
+ sys.stdout = sys.stdout.detach()
+elif hasattr(sys.stdout, 'buffer'):
+ sys.stdout = sys.stdout.buffer
+sys.stdout.write(prefix)
+"""]
+ logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
+ try:
+ proc = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE)
+ proc_stdout, proc_stderr = proc.communicate()
+ except OSError:
+ e = sys.exc_info()[1]
+ if e.errno == errno.EACCES:
+ logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
+ sys.exit(100)
+ else:
+ raise e
+
+ proc_stdout = proc_stdout.strip().decode("utf-8")
+ proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
+ norm_home_dir = os.path.normcase(os.path.abspath(home_dir))
+ if hasattr(norm_home_dir, 'decode'):
+ norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
+ if proc_stdout != norm_home_dir:
+ logger.fatal(
+ 'ERROR: The executable %s is not functioning' % py_executable)
+ logger.fatal(
+ 'ERROR: It thinks sys.prefix is %r (should be %r)'
+ % (proc_stdout, norm_home_dir))
+ logger.fatal(
+ 'ERROR: virtualenv is not compatible with this system or executable')
+ if sys.platform == 'win32':
+ logger.fatal(
+ 'Note: some Windows users have reported this error when they installed Python for "Only this user". The problem may be resolvable if you install Python "For all users". (See https://bugs.launchpad.net/virtualenv/+bug/352844)')
+ sys.exit(100)
+ else:
+ logger.info('Got sys.prefix result: %r' % proc_stdout)
+
+ pydistutils = os.path.expanduser('~/.pydistutils.cfg')
+ if os.path.exists(pydistutils):
+ logger.notify('Please make sure you remove any previous custom paths from '
+ 'your %s file.' % pydistutils)
+ ## FIXME: really this should be calculated earlier
+ return py_executable
+
+def install_activate(home_dir, bin_dir, prompt=None):
+ if sys.platform == 'win32' or is_jython and os._name == 'nt':
+ files = {'activate.bat': ACTIVATE_BAT,
+ 'deactivate.bat': DEACTIVATE_BAT}
+ if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
+ files['activate'] = ACTIVATE_SH
+ else:
+ files = {'activate': ACTIVATE_SH}
+
+ # suppling activate.fish in addition to, not instead of, the
+ # bash script support.
+ files['activate.fish'] = ACTIVATE_FISH
+
+ # same for csh/tcsh support...
+ files['activate.csh'] = ACTIVATE_CSH
+
+
+
+ files['activate_this.py'] = ACTIVATE_THIS
+ home_dir = os.path.abspath(home_dir)
+ if hasattr(home_dir, 'decode'):
+ home_dir = home_dir.decode(sys.getfilesystemencoding())
+ vname = os.path.basename(home_dir)
+ for name, content in files.items():
+ content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
+ content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
+ content = content.replace('__VIRTUAL_ENV__', home_dir)
+ content = content.replace('__VIRTUAL_NAME__', vname)
+ content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
+ writefile(os.path.join(bin_dir, name), content)
+
+def install_distutils(home_dir):
+ distutils_path = change_prefix(distutils.__path__[0], home_dir)
+ mkdir(distutils_path)
+ ## FIXME: maybe this prefix setting should only be put in place if
+ ## there's a local distutils.cfg with a prefix setting?
+ home_dir = os.path.abspath(home_dir)
+ ## FIXME: this is breaking things, removing for now:
+ #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
+ writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
+ writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
+
+def fix_local_scheme(home_dir):
+ """
+ Platforms that use the "posix_local" install scheme (like Ubuntu with
+ Python 2.7) need to be given an additional "local" location, sigh.
+ """
+ try:
+ import sysconfig
+ except ImportError:
+ pass
+ else:
+ if sysconfig._get_default_scheme() == 'posix_local':
+ local_path = os.path.join(home_dir, 'local')
+ if not os.path.exists(local_path):
+ os.symlink(os.path.abspath(home_dir), local_path)
+
+def fix_lib64(lib_dir):
+ """
+ Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
+ instead of lib/pythonX.Y. If this is such a platform we'll just create a
+ symlink so lib64 points to lib
+ """
+ if [p for p in distutils.sysconfig.get_config_vars().values()
+ if isinstance(p, basestring) and 'lib64' in p]:
+ logger.debug('This system uses lib64; symlinking lib64 to lib')
+ assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
+ "Unexpected python lib dir: %r" % lib_dir)
+ lib_parent = os.path.dirname(lib_dir)
+ assert os.path.basename(lib_parent) == 'lib', (
+ "Unexpected parent dir: %r" % lib_parent)
+ copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
+
+def resolve_interpreter(exe):
+ """
+ If the executable given isn't an absolute path, search $PATH for the interpreter
+ """
+ if os.path.abspath(exe) != exe:
+ paths = os.environ.get('PATH', '').split(os.pathsep)
+ for path in paths:
+ if os.path.exists(os.path.join(path, exe)):
+ exe = os.path.join(path, exe)
+ break
+ if not os.path.exists(exe):
+ logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
+ raise SystemExit(3)
+ if not is_executable(exe):
+ logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
+ raise SystemExit(3)
+ return exe
+
+def is_executable(exe):
+ """Checks a file is executable"""
+ return os.access(exe, os.X_OK)
+
+############################################################
+## Relocating the environment:
+
+def make_environment_relocatable(home_dir):
+ """
+ Makes the already-existing environment use relative paths, and takes out
+ the #!-based environment selection in scripts.
+ """
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ activate_this = os.path.join(bin_dir, 'activate_this.py')
+ if not os.path.exists(activate_this):
+ logger.fatal(
+ 'The environment doesn\'t have a file %s -- please re-run virtualenv '
+ 'on this environment to update it' % activate_this)
+ fixup_scripts(home_dir)
+ fixup_pth_and_egg_link(home_dir)
+ ## FIXME: need to fix up distutils.cfg
+
+OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
+ 'activate', 'activate.bat', 'activate_this.py']
+
+def fixup_scripts(home_dir):
+ # This is what we expect at the top of scripts:
+ shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
+ # This is what we'll put:
+ new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
+ activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
+ if sys.platform == 'win32':
+ bin_suffix = 'Scripts'
+ else:
+ bin_suffix = 'bin'
+ bin_dir = os.path.join(home_dir, bin_suffix)
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ for filename in os.listdir(bin_dir):
+ filename = os.path.join(bin_dir, filename)
+ if not os.path.isfile(filename):
+ # ignore subdirs, e.g. .svn ones.
+ continue
+ f = open(filename, 'rb')
+ lines = f.readlines()
+ f.close()
+ if not lines:
+ logger.warn('Script %s is an empty file' % filename)
+ continue
+ if not lines[0].strip().startswith(shebang):
+ if os.path.basename(filename) in OK_ABS_SCRIPTS:
+ logger.debug('Cannot make script %s relative' % filename)
+ elif lines[0].strip() == new_shebang:
+ logger.info('Script %s has already been made relative' % filename)
+ else:
+ logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
+ % (filename, shebang))
+ continue
+ logger.notify('Making script %s relative' % filename)
+ lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
+ f = open(filename, 'wb')
+ f.writelines(lines)
+ f.close()
+
+def fixup_pth_and_egg_link(home_dir, sys_path=None):
+ """Makes .pth and .egg-link files use relative paths"""
+ home_dir = os.path.normcase(os.path.abspath(home_dir))
+ if sys_path is None:
+ sys_path = sys.path
+ for path in sys_path:
+ if not path:
+ path = '.'
+ if not os.path.isdir(path):
+ continue
+ path = os.path.normcase(os.path.abspath(path))
+ if not path.startswith(home_dir):
+ logger.debug('Skipping system (non-environment) directory %s' % path)
+ continue
+ for filename in os.listdir(path):
+ filename = os.path.join(path, filename)
+ if filename.endswith('.pth'):
+ if not os.access(filename, os.W_OK):
+ logger.warn('Cannot write .pth file %s, skipping' % filename)
+ else:
+ fixup_pth_file(filename)
+ if filename.endswith('.egg-link'):
+ if not os.access(filename, os.W_OK):
+ logger.warn('Cannot write .egg-link file %s, skipping' % filename)
+ else:
+ fixup_egg_link(filename)
+
+def fixup_pth_file(filename):
+ lines = []
+ prev_lines = []
+ f = open(filename)
+ prev_lines = f.readlines()
+ f.close()
+ for line in prev_lines:
+ line = line.strip()
+ if (not line or line.startswith('#') or line.startswith('import ')
+ or os.path.abspath(line) != line):
+ lines.append(line)
+ else:
+ new_value = make_relative_path(filename, line)
+ if line != new_value:
+ logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
+ lines.append(new_value)
+ if lines == prev_lines:
+ logger.info('No changes to .pth file %s' % filename)
+ return
+ logger.notify('Making paths in .pth file %s relative' % filename)
+ f = open(filename, 'w')
+ f.write('\n'.join(lines) + '\n')
+ f.close()
+
+def fixup_egg_link(filename):
+ f = open(filename)
+ link = f.read().strip()
+ f.close()
+ if os.path.abspath(link) != link:
+ logger.debug('Link in %s already relative' % filename)
+ return
+ new_link = make_relative_path(filename, link)
+ logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
+ f = open(filename, 'w')
+ f.write(new_link)
+ f.close()
+
+def make_relative_path(source, dest, dest_is_directory=True):
+ """
+ Make a filename relative, where the filename is dest, and it is
+ being referred to from the filename source.
+
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/usr/share/another-place/src/Directory')
+ '../another-place/src/Directory'
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/home/user/src/Directory')
+ '../../../home/user/src/Directory'
+ >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
+ './'
+ """
+ source = os.path.dirname(source)
+ if not dest_is_directory:
+ dest_filename = os.path.basename(dest)
+ dest = os.path.dirname(dest)
+ dest = os.path.normpath(os.path.abspath(dest))
+ source = os.path.normpath(os.path.abspath(source))
+ dest_parts = dest.strip(os.path.sep).split(os.path.sep)
+ source_parts = source.strip(os.path.sep).split(os.path.sep)
+ while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
+ dest_parts.pop(0)
+ source_parts.pop(0)
+ full_parts = ['..']*len(source_parts) + dest_parts
+ if not dest_is_directory:
+ full_parts.append(dest_filename)
+ if not full_parts:
+ # Special case for the current directory (otherwise it'd be '')
+ return './'
+ return os.path.sep.join(full_parts)
+
+
+
+############################################################
+## Bootstrap script creation:
+
+def create_bootstrap_script(extra_text, python_version=''):
+ """
+ Creates a bootstrap script, which is like this script but with
+ extend_parser, adjust_options, and after_install hooks.
+
+ This returns a string that (written to disk of course) can be used
+ as a bootstrap script with your own customizations. The script
+ will be the standard virtualenv.py script, with your extra text
+ added (your extra text should be Python code).
+
+ If you include these functions, they will be called:
+
+ ``extend_parser(optparse_parser)``:
+ You can add or remove options from the parser here.
+
+ ``adjust_options(options, args)``:
+ You can change options here, or change the args (if you accept
+ different kinds of arguments, be sure you modify ``args`` so it is
+ only ``[DEST_DIR]``).
+
+ ``after_install(options, home_dir)``:
+
+ After everything is installed, this function is called. This
+ is probably the function you are most likely to use. An
+ example would be::
+
+ def after_install(options, home_dir):
+ subprocess.call([join(home_dir, 'bin', 'easy_install'),
+ 'MyPackage'])
+ subprocess.call([join(home_dir, 'bin', 'my-package-script'),
+ 'setup', home_dir])
+
+ This example immediately installs a package, and runs a setup
+ script from that package.
+
+ If you provide something like ``python_version='2.4'`` then the
+ script will start with ``#!/usr/bin/env python2.4`` instead of
+ ``#!/usr/bin/env python``. You can use this when the script must
+ be run with a particular Python version.
+ """
+ filename = __file__
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ f = open(filename, 'rb')
+ content = f.read()
+ f.close()
+ py_exe = 'python%s' % python_version
+ content = (('#!/usr/bin/env %s\n' % py_exe)
+ + '## WARNING: This file is generated\n'
+ + content)
+ return content.replace('##EXT' 'END##', extra_text)
+
+##EXTEND##
+
+def convert(s):
+ b = base64.b64decode(s.encode('ascii'))
+ return zlib.decompress(b).decode('utf-8')
+
+##file site.py
+SITE_PY = convert("""
+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
+""")
+
+##file ez_setup.py
+EZ_SETUP_PY = convert("""
+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
+BDaonX65d/fwEjNqlDjLVIvM9X+XVxF7
+""")
+
+##file distribute_setup.py
+DISTRIBUTE_SETUP_PY = convert("""
+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
+""")
+
+##file activate.sh
+ACTIVATE_SH = convert("""
+eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
+H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
+DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
+cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
+G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
+EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
+wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
+5eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
+JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
+huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
+Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
+Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
+WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
+LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
+""")
+
+##file activate.fish
+ACTIVATE_FISH = convert("""
+eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A
+Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7
+pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ
+lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v
+g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u
+grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS
+xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV
+MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu
+H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM
+L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz
+fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV
+pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh
+MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT
+O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz
+7SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi
+m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq
+djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5
+mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN
+jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk=
+""")
+
+##file activate.csh
+ACTIVATE_CSH = convert("""
+eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
+XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
+kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
+pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
+sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
+yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
+E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
+lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
+r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
+""")
+
+##file activate.bat
+ACTIVATE_BAT = convert("""
+eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
+qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
+sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
+ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
+""")
+
+##file deactivate.bat
+DEACTIVATE_BAT = convert("""
+eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
+FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
+i2dASrm4rFz9XLgAwJNbyQ==
+""")
+
+##file distutils-init.py
+DISTUTILS_INIT = convert("""
+eJytV92L4zYQf/dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313dG8odkO9d7aGBB
+luZLv/nNjFacOqUtKJMIvzK3cXlhWgp5MDBsqK5SNYftsBAGpLLA4F1oe2Ytl+9wUvW55TswCi4c
+KibhbFDSglXQCFmDPXIwtm7FawLRbwtPzg2T9gf4gupKv4GS0N262w7V0NvpbCy8cvTo3eAus6C5
+ETU3ICQZX1hFTw/dzR6V/AW1RCN4/XAtbsVXqIXmlVX6liS4lOzEYY9QFB2zx6LfoSNjz1a0pqT9
+QOIfJWQ2E888NEVZNqLlZZnvIB0NpHkimlFdKn2iRRY7yGG/CCJb6Iz280d34SFXBS2yEYPNF0Q7
+yM7oCjpWvbEDQmnhRwOs6zjThpKE8HogwRAgraqYFZgGZvzmzVh+mgz9vskT3hruwyjdFcqyENJw
+bbMPO5jdzonxK68QKT7B57CMRRG5shRSWDTX3dI8LzRndZbnSWL1zfvriUmK4TcGWSnZiEPCrxXv
+bM+sP7VW2is2WgWXCO3sAu3Rzysz3FiNCA8WPyM4gb1JAAmCiyTZbhFjWx3h9SzauuRXC9MFoVbc
+yNTCm1QXOOIfIn/g1kGMhDUBN72hI5XCBQtIXQw8UEEdma6Jaz4vJIJ51Orc15hzzmu6TdFp3ogr
+Aof0c98tsw1SiaiWotHffk3XYCkqdToxWRfTFXqgpg2khcLluOHMVC0zZhLKIomesfSreUNNgbXi
+Ky9VRzwzkBneNoGQyyvGjbsFQqOZvpWIjqH281lJ/jireFgR3cPzSyTGWzQpDNIU+03Fs4XKLkhp
+/n0uFnuF6VphB44b3uWRneSbBoMSioqE8oeF0JY+qTvYfEK+bPLYdoR4McfYQ7wMZj39q0kfP8q+
+FfsymO0GzNlPh644Jje06ulqHpOEQqdJUfoidI2O4CWx4qOglLye6RrFQirpCRXvhoRqXH3sYdVJ
+AItvc+VUsLO2v2hVAWrNIfVGtkG351cUMNncbh/WdowtSPtCdkzYFv6mwYc9o2Jt68ud6wectBr8
+hYAulPSlgzH44YbV3ikjrulEaNJxt+/H3wZ7bXSXje/YY4tfVVrVmUstaDwwOBLMg6iduDB0lMVC
+UyzYx7Ab4kjCqdViEJmDcdk/SKbgsjYXgfMznUWcrtS4z4fmJ/XOM1LPk/iIpqass5XwNbdnLb1Y
+8h3ERXSWZI6rZJxKs1LBqVH65w0Oy4ra0CBYxEeuOMbDmV5GI6E0Ha/wgVTtkX0+OXvqsD02CKLf
+XHbeft85D7tTCMYy2Njp4DJP7gWJr6paVWXZ1+/6YXLv/iE0M90FktiI7yFJD9e7SOLhEkkaMTUO
+azq9i2woBNR0/0eoF1HFMf0H8ChxH/jgcB34GZIz3Qn4/vid+VEamQrOVqAPTrOfmD4MPdVh09tb
+8dLLjvh/61lEP4yW5vJaH4vHcevG8agXvzPGoOhhXNncpTr99PTHx6e/UvffFLaxUSjuSeP286Dw
+gtEMcW1xKr/he4/6IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLn7fAY78k4aiR387bCr5XT
+5C4rFgwLGfMvJuAMew==
+""")
+
+##file distutils.cfg
+DISTUTILS_CFG = convert("""
+eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
+xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
+9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
+""")
+
+##file activate_this.py
+ACTIVATE_THIS = convert("""
+eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
+VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
+Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
+qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
+4lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
+HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
+xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
+1Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
+3vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
+""")
+
+if __name__ == '__main__':
+ main()
+
+## TODO:
+## Copy python.exe.manifest
+## Monkeypatch distutils.sysconfig
diff --git a/third-party/cxxtest/bin/cxxtestgen b/third-party/cxxtest/bin/cxxtestgen
new file mode 100755
index 00000000..e001cfa8
--- /dev/null
+++ b/third-party/cxxtest/bin/cxxtestgen
@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+#
+# The CxxTest driver script, which uses the cxxtest Python package.
+#
+
+import sys
+import os
+from os.path import realpath, dirname
+if sys.version_info < (3,0):
+ sys.path.insert(0, dirname(dirname(realpath(__file__)))+os.sep+'python')
+else:
+ sys.path.insert(0, dirname(dirname(realpath(__file__)))+os.sep+'python'+os.sep+'python3')
+sys.path.append(".")
+
+import cxxtest
+
+cxxtest.main(sys.argv)
+
diff --git a/third-party/cxxtest/bin/cxxtestgen.bat b/third-party/cxxtest/bin/cxxtestgen.bat
new file mode 100644
index 00000000..95d7d140
--- /dev/null
+++ b/third-party/cxxtest/bin/cxxtestgen.bat
@@ -0,0 +1,3 @@
+@echo off
+rem Just run the python script
+python %0 %*
diff --git a/third-party/cxxtest/build_tools/SCons/AUTHORS b/third-party/cxxtest/build_tools/SCons/AUTHORS
new file mode 100644
index 00000000..1f3e7e44
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/AUTHORS
@@ -0,0 +1,19 @@
+This file is meant to be a full credit of the people who helped make the CxxTest
+builder what it is today.
+
+
+Current maintainer:
+ Gašper Ažman (gasper dot azman at gmail.com)
+
+
+Original author:
+ Gašper Ažman
+
+Additional patches and tests:
+ Diego Nieto Cid
+ Edmundo López Bobeda
+ John Darby Mitchell
+ Pavol Juhas
+
+Other helpful suggestions:
+ John Darby Mitchell
diff --git a/third-party/cxxtest/build_tools/SCons/cxxtest.py b/third-party/cxxtest/build_tools/SCons/cxxtest.py
new file mode 100644
index 00000000..a66856c4
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/cxxtest.py
@@ -0,0 +1,400 @@
+# coding=UTF-8
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+#
+# == Preamble ==
+# Authors of this script are in the Authors file in the same directory as this
+# script.
+#
+# Maintainer: Gašper Ažman
+#
+# This file is maintained as a part of the CxxTest test suite.
+#
+# == About ==
+#
+# This builder correctly tracks dependencies and supports just about every
+# configuration option for CxxTest that I can think of. It automatically
+# defines a target "check" (configurable), so all tests can be run with a
+# % scons check
+# This will first compile and then run the tests.
+#
+# The default configuration assumes that cxxtest is located at the base source
+# directory (where SConstruct is), that the cxxtestgen is under
+# cxxtest/bin/cxxtestgen and headers are in cxxtest/cxxtest/. The
+# header include path is automatically added to CPPPATH. It, however, can also
+# recognise that cxxtest is installed system-wide (based on redhat's RPM).
+#
+# For a list of environment variables and their defaults, see the generate()
+# function.
+#
+# This should be in a file called cxxtest.py somewhere in the scons toolpath.
+# (default: #/site_scons/site_tools/)
+#
+# == Usage: ==
+#
+# For configuration options, check the comment of the generate() function.
+#
+# This builder has a variety of different possible usages, so bear with me.
+#
+# env.CxxTest('target')
+# The simplest of them all, it models the Program call. This sees if target.t.h
+# is around and passes it through the cxxtestgen and compiles it. Might only
+# work on unix though, because target can't have a suffix right now.
+#
+# env.CxxTest(['target.t.h'])
+# This compiles target.t.h as in the previous example, but now sees that it is a
+# source file. It need not have the same suffix as the env['CXXTEST_SUFFIX']
+# variable dictates. The only file provided is taken as the test source file.
+#
+# env.CxxTest(['test1.t.h','test1_lib.cpp','test1_lib2.cpp','test2.t.h',...])
+# You may also specify multiple source files. In this case, the 1st file that
+# ends with CXXTEST_SUFFIX (default: .t.h) will be taken as the default test
+# file. All others will be run with the --part switch and linked in. All files
+# *not* having the right suffix will be passed to the Program call verbatim.
+#
+# In the last two cases, you may also specify the desired name of the test as
+# the 1st argument to the function. This will result in the end executable
+# called that. Normal Program builder rules apply.
+#
+
+from SCons.Script import *
+from SCons.Builder import Builder
+from SCons.Util import PrependPath, unique, uniquer
+import os
+
+# A warning class to notify users of problems
+class ToolCxxTestWarning(SCons.Warnings.Warning):
+ pass
+
+SCons.Warnings.enableWarningClass(ToolCxxTestWarning)
+
+def accumulateEnvVar(dicts, name, default = []):
+ """
+ Accumulates the values under key 'name' from the list of dictionaries dict.
+ The default value is appended to the end list if 'name' does not exist in
+ the dict.
+ """
+ final = []
+ for d in dicts:
+ final += Split(d.get(name, default))
+ return final
+
+def multiget(dictlist, key, default = None):
+ """
+ Takes a list of dictionaries as its 1st argument. Checks if the key exists
+ in each one and returns the 1st one it finds. If the key is found in no
+ dictionaries, the default is returned.
+ """
+ for dict in dictlist:
+ if dict.has_key(key):
+ return dict[key]
+ else:
+ return default
+
+def envget(env, key, default=None):
+ """Look in the env, then in os.environ. Otherwise same as multiget."""
+ return multiget([env, os.environ], key, default)
+
+def prepend_ld_library_path(env, overrides, **kwargs):
+ """Prepend LD_LIBRARY_PATH with LIBPATH to run successfully programs that
+ were linked against local shared libraries."""
+ # make it unique but preserve order ...
+ libpath = uniquer(Split(kwargs.get('CXXTEST_LIBPATH', [])) +
+ Split(env.get( 'CXXTEST_LIBPATH', [])))
+ if len(libpath) > 0:
+ libpath = env.arg2nodes(libpath, env.fs.Dir)
+ platform = env.get('PLATFORM','')
+ if platform == 'win32':
+ var = 'PATH'
+ else:
+ var = 'LD_LIBRARY_PATH'
+ eenv = overrides.get('ENV', env['ENV'].copy())
+ canonicalize = lambda p : p.abspath
+ eenv[var] = PrependPath(eenv.get(var,''), libpath, os.pathsep, 1, canonicalize)
+ overrides['ENV'] = eenv
+ return overrides
+
+def UnitTest(env, target, source = [], **kwargs):
+ """
+ Prepares the Program call arguments, calls Program and adds the result to
+ the check target.
+ """
+ # get the c and cxx flags to process.
+ ccflags = Split( multiget([kwargs, env, os.environ], 'CCFLAGS' ))
+ cxxflags = Split( multiget([kwargs, env, os.environ], 'CXXFLAGS'))
+ # get the removal c and cxx flags
+ cxxremove = set( Split( multiget([kwargs, env, os.environ],'CXXTEST_CXXFLAGS_REMOVE')))
+ ccremove = set( Split( multiget([kwargs, env, os.environ],'CXXTEST_CCFLAGS_REMOVE' )))
+ # remove the required flags
+ ccflags = [item for item in ccflags if item not in ccremove]
+ cxxflags = [item for item in cxxflags if item not in cxxremove]
+ # fill the flags into kwargs
+ kwargs["CXXFLAGS"] = cxxflags
+ kwargs["CCFLAGS"] = ccflags
+ test = env.Program(target, source = source, **kwargs)
+ testCommand = multiget([kwargs, env, os.environ], 'CXXTEST_COMMAND')
+ if testCommand:
+ testCommand = testCommand.replace('%t', test[0].abspath)
+ else:
+ testCommand = test[0].abspath
+ if multiget([kwargs, env, os.environ], 'CXXTEST_SKIP_ERRORS', False):
+ runner = env.Action(testCommand, exitstatfunc=lambda x:0)
+ else:
+ runner = env.Action(testCommand)
+ overrides = prepend_ld_library_path(env, {}, **kwargs)
+ cxxtest_target = multiget([kwargs, env], 'CXXTEST_TARGET')
+ env.Alias(cxxtest_target, test, runner, **overrides)
+ env.AlwaysBuild(cxxtest_target)
+ return test
+
+def isValidScriptPath(cxxtestgen):
+ """check keyword arg or environment variable locating cxxtestgen script"""
+
+ if cxxtestgen and os.path.exists(cxxtestgen):
+ return True
+ else:
+ SCons.Warnings.warn(ToolCxxTestWarning,
+ "Invalid CXXTEST environment variable specified!")
+ return False
+
+def defaultCxxTestGenLocation(env):
+ return os.path.join(
+ envget(env, 'CXXTEST_CXXTESTGEN_DEFAULT_LOCATION'),
+ envget(env, 'CXXTEST_CXXTESTGEN_SCRIPT_NAME')
+ )
+
+def findCxxTestGen(env):
+ """locate the cxxtestgen script by checking environment, path and project"""
+
+ # check the SCons environment...
+ # Then, check the OS environment...
+ cxxtest = envget(env, 'CXXTEST', None)
+
+ # check for common passing errors and provide diagnostics.
+ if isinstance(cxxtest, (list, tuple, dict)):
+ SCons.Warnings.warn(
+ ToolCxxTestWarning,
+ "The CXXTEST variable was specified as a list."
+ " This is not supported. Please pass a string."
+ )
+
+ if cxxtest:
+ try:
+ #try getting the absolute path of the file first.
+ # Required to expand '#'
+ cxxtest = env.File(cxxtest).abspath
+ except TypeError:
+ try:
+ #maybe only the directory was specified?
+ cxxtest = env.File(
+ os.path.join(cxxtest, defaultCxxTestGenLocation(env)
+ )).abspath
+ except TypeError:
+ pass
+ # If the user specified the location in the environment,
+ # make sure it was correct
+ if isValidScriptPath(cxxtest):
+ return os.path.realpath(cxxtest)
+
+ # No valid environment variable found, so...
+ # Next, check the path...
+ # Next, check the project
+ check_path = os.path.join(
+ envget(env, 'CXXTEST_INSTALL_DIR'),
+ envget(env, 'CXXTEST_CXXTESTGEN_DEFAULT_LOCATION'))
+
+ cxxtest = (env.WhereIs(envget(env, 'CXXTEST_CXXTESTGEN_SCRIPT_NAME')) or
+ env.WhereIs(envget(env, 'CXXTEST_CXXTESTGEN_SCRIPT_NAME'),
+ path=[Dir(check_path).abspath]))
+
+ if cxxtest:
+ return cxxtest
+ else:
+ # If we weren't able to locate the cxxtestgen script, complain...
+ SCons.Warnings.warn(
+ ToolCxxTestWarning,
+ "Unable to locate cxxtestgen in environment, path or"
+ " project!\n"
+ "Please set the CXXTEST variable to the path of the"
+ " cxxtestgen script"
+ )
+ return None
+
+def findCxxTestHeaders(env):
+ searchfile = 'TestSuite.h'
+ cxxtestgen_pathlen = len(defaultCxxTestGenLocation(env))
+
+ default_path = Dir(envget(env,'CXXTEST_INSTALL_DIR')).abspath
+
+ os_cxxtestgen = os.path.realpath(File(env['CXXTEST']).abspath)
+ alt_path = os_cxxtestgen[:-cxxtestgen_pathlen]
+
+ searchpaths = [default_path, alt_path]
+ foundpaths = []
+ for p in searchpaths:
+ if os.path.exists(os.path.join(p, 'cxxtest', searchfile)):
+ foundpaths.append(p)
+ return foundpaths
+
+def generate(env, **kwargs):
+ """
+ Keyword arguments (all can be set via environment variables as well):
+ CXXTEST - the path to the cxxtestgen script.
+ Default: searches SCons environment, OS environment,
+ path and project in that order. Instead of setting this,
+ you can also set CXXTEST_INSTALL_DIR
+ CXXTEST_RUNNER - the runner to use. Default: ErrorPrinter
+ CXXTEST_OPTS - other options to pass to cxxtest. Default: ''
+ CXXTEST_SUFFIX - the suffix of the test files. Default: '.t.h'
+ CXXTEST_TARGET - the target to append the tests to. Default: check
+ CXXTEST_COMMAND - the command that will be executed to run the test,
+ %t will be replace with the test executable.
+ Can be used for example for MPI or valgrind tests.
+ Default: %t
+ CXXTEST_CXXFLAGS_REMOVE - the flags that cxxtests can't compile with,
+ or give lots of warnings. Will be stripped.
+ Default: -pedantic -Weffc++
+ CXXTEST_CCFLAGS_REMOVE - the same thing as CXXTEST_CXXFLAGS_REMOVE, just for
+ CCFLAGS. Default: same as CXXFLAGS.
+ CXXTEST_PYTHON - the path to the python binary.
+ Default: searches path for python
+ CXXTEST_SKIP_ERRORS - set to True to continue running the next test if one
+ test fails. Default: False
+ CXXTEST_CPPPATH - If you do not want to clutter your global CPPPATH with the
+ CxxTest header files and other stuff you only need for
+ your tests, this is the variable to set. Behaves as
+ CPPPATH does.
+ CXXTEST_LIBPATH - If your test is linked to shared libraries which are
+ outside of standard directories. This is used as LIBPATH
+ when compiling the test program and to modify
+ LD_LIBRARY_PATH (or PATH on win32) when running the
+ program.
+ CXXTEST_INSTALL_DIR - this is where you tell the builder where CxxTest is
+ installed. The install directory has cxxtest,
+ python, docs and other subdirectories.
+ ... and all others that Program() accepts, like CPPPATH etc.
+ """
+
+ print "Loading CxxTest tool..."
+
+ #
+ # Expected behaviour: keyword arguments override environment variables;
+ # environment variables override default settings.
+ #
+ env.SetDefault( CXXTEST_RUNNER = 'ErrorPrinter' )
+ env.SetDefault( CXXTEST_OPTS = '' )
+ env.SetDefault( CXXTEST_SUFFIX = '.t.h' )
+ env.SetDefault( CXXTEST_TARGET = 'check' )
+ env.SetDefault( CXXTEST_CPPPATH = ['#'] )
+ env.SetDefault( CXXTEST_PYTHON = env.WhereIs('python') )
+ env.SetDefault( CXXTEST_SKIP_ERRORS = False )
+ env.SetDefault( CXXTEST_CXXFLAGS_REMOVE =
+ ['-pedantic','-Weffc++','-pedantic-errors'] )
+ env.SetDefault( CXXTEST_CCFLAGS_REMOVE =
+ ['-pedantic','-Weffc++','-pedantic-errors'] )
+ env.SetDefault( CXXTEST_INSTALL_DIR = '#/cxxtest/' )
+
+ # this one's not for public use - it documents where the cxxtestgen script
+ # is located in the CxxTest tree normally.
+ env.SetDefault( CXXTEST_CXXTESTGEN_DEFAULT_LOCATION = 'bin' )
+ # the cxxtestgen script name.
+ env.SetDefault( CXXTEST_CXXTESTGEN_SCRIPT_NAME = 'cxxtestgen' )
+
+ #Here's where keyword arguments are applied
+ apply(env.Replace, (), kwargs)
+
+ #If the user specified the path to CXXTEST, make sure it is correct
+ #otherwise, search for and set the default toolpath.
+ if (not kwargs.has_key('CXXTEST') or not isValidScriptPath(kwargs['CXXTEST']) ):
+ env["CXXTEST"] = findCxxTestGen(env)
+
+ # find and add the CxxTest headers to the path.
+ env.AppendUnique( CXXTEST_CPPPATH = findCxxTestHeaders(env) )
+
+ cxxtest = env['CXXTEST']
+ if cxxtest:
+ #
+ # Create the Builder (only if we have a valid cxxtestgen!)
+ #
+ cxxtest_builder = Builder(
+ action =
+ [["$CXXTEST_PYTHON",cxxtest,"--runner=$CXXTEST_RUNNER",
+ "$CXXTEST_OPTS","$CXXTEST_ROOT_PART","-o","$TARGET","$SOURCE"]],
+ suffix = ".cpp",
+ src_suffix = '$CXXTEST_SUFFIX'
+ )
+ else:
+ cxxtest_builder = (lambda *a: sys.stderr.write("ERROR: CXXTESTGEN NOT FOUND!"))
+
+ def CxxTest(env, target, source = None, **kwargs):
+ """Usage:
+ The function is modelled to be called as the Program() call is:
+ env.CxxTest('target_name') will build the test from the source
+ target_name + env['CXXTEST_SUFFIX'],
+ env.CxxTest('target_name', source = 'test_src.t.h') will build the test
+ from test_src.t.h source,
+ env.CxxTest('target_name, source = ['test_src.t.h', other_srcs]
+ builds the test from source[0] and links in other files mentioned in
+ sources,
+ You may also add additional arguments to the function. In that case, they
+ will be passed to the actual Program builder call unmodified. Convenient
+ for passing different CPPPATHs and the sort. This function also appends
+ CXXTEST_CPPPATH to CPPPATH. It does not clutter the environment's CPPPATH.
+ """
+ if (source == None):
+ suffix = multiget([kwargs, env, os.environ], 'CXXTEST_SUFFIX', "")
+ source = [t + suffix for t in target]
+ sources = Flatten(Split(source))
+ headers = []
+ linkins = []
+ for l in sources:
+ # check whether this is a file object or a string path
+ try:
+ s = l.abspath
+ except AttributeError:
+ s = l
+
+ if s.endswith(multiget([kwargs, env, os.environ], 'CXXTEST_SUFFIX', None)):
+ headers.append(l)
+ else:
+ linkins.append(l)
+
+ deps = []
+ if len(headers) == 0:
+ if len(linkins) != 0:
+ # the 1st source specified is the test
+ deps.append(env.CxxTestCpp(linkins.pop(0), **kwargs))
+ else:
+ deps.append(env.CxxTestCpp(headers.pop(0), **kwargs))
+ deps.extend(
+ [env.CxxTestCpp(header, CXXTEST_RUNNER = 'none',
+ CXXTEST_ROOT_PART = '--part', **kwargs)
+ for header in headers]
+ )
+ deps.extend(linkins)
+ kwargs['CPPPATH'] = unique(
+ Split(kwargs.get('CPPPATH', [])) +
+ Split(env.get( 'CPPPATH', [])) +
+ Split(kwargs.get('CXXTEST_CPPPATH', [])) +
+ Split(env.get( 'CXXTEST_CPPPATH', []))
+ )
+ kwargs['LIBPATH'] = unique(
+ Split(kwargs.get('LIBPATH', [])) +
+ Split(env.get( 'LIBPATH', [])) +
+ Split(kwargs.get('CXXTEST_LIBPATH', [])) +
+ Split(env.get( 'CXXTEST_LIBPATH', []))
+ )
+
+ return UnitTest(env, target, source = deps, **kwargs)
+
+ env.Append( BUILDERS = { "CxxTest" : CxxTest, "CxxTestCpp" : cxxtest_builder } )
+
+def exists(env):
+ return os.path.exists(env['CXXTEST'])
+
diff --git a/third-party/cxxtest/build_tools/SCons/test/default_env/README b/third-party/cxxtest/build_tools/SCons/test/default_env/README
new file mode 100644
index 00000000..d8c8b69a
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/default_env/README
@@ -0,0 +1,2 @@
+Tests if the 'default environment' defaults are sane and work out of the box.
+by: Gašper Ažman
diff --git a/third-party/cxxtest/build_tools/SCons/test/default_env/SConstruct b/third-party/cxxtest/build_tools/SCons/test/default_env/SConstruct
new file mode 100644
index 00000000..637992ee
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/default_env/SConstruct
@@ -0,0 +1,10 @@
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest']
+ )
+
+env['CXXTEST_SKIP_ERRORS'] = True
+env.CxxTest(['src/ThrowNoStd.h'])
+env.CxxTest(['src/AborterNoThrow.h'])
+env.CxxTest(['src/Comments.h'])
+
diff --git a/third-party/cxxtest/build_tools/SCons/test/default_env/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/default_env/TestDef.py
new file mode 100644
index 00000000..c951f102
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/default_env/TestDef.py
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+expect_success = True
+type = 'scons'
+links = {
+ 'cxxtest': '../../../../',
+ 'src' : '../../../../test/'
+ }
+
+
diff --git a/third-party/cxxtest/build_tools/SCons/test/empty_source_list/README b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/README
new file mode 100644
index 00000000..419901bb
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/README
@@ -0,0 +1,2 @@
+Tests if cxxtest behaves correctly if no sources are given.
+by: Gašper Ažman
diff --git a/third-party/cxxtest/build_tools/SCons/test/empty_source_list/SConstruct b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/SConstruct
new file mode 100644
index 00000000..9f1dda96
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/SConstruct
@@ -0,0 +1,4 @@
+env = Environment(toolpath=['../../'],tools=['default','cxxtest'])
+
+env.CxxTest('test_bar')
+env.CxxTest('test_foo')
diff --git a/third-party/cxxtest/build_tools/SCons/test/empty_source_list/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/empty_source_list/requirement.hpp b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/requirement.hpp
new file mode 100644
index 00000000..3a6f7574
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/requirement.hpp
@@ -0,0 +1,12 @@
+/**
+ * @file requirement.cpp
+ * Implementation of the requirement function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:09:42 AM
+ */
+
+bool call_a_requirement() {
+ return true;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/empty_source_list/test_bar.t.h b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/test_bar.t.h
new file mode 100644
index 00000000..4cd1adad
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/test_bar.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_BAR_T_H
+#define TEST_BAR_T_H
+/**
+ * @file test_bar.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:04:06 AM
+ */
+
+#include
+#include "requirement.hpp"
+
+class TestBar : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/empty_source_list/test_foo.t.h b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/test_foo.t.h
new file mode 100644
index 00000000..2850447c
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/empty_source_list/test_foo.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_FOO_T_H
+#define TEST_FOO_T_H
+/**
+ * @file test_foo.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:02:06 AM
+ */
+
+#include "requirement.hpp"
+#include
+
+class TestFoo : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/eprouvette.py b/third-party/cxxtest/build_tools/SCons/test/eprouvette.py
new file mode 100755
index 00000000..c1e6550b
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/eprouvette.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+# vim: fileencoding=utf-8
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+from __future__ import print_function
+import os, sys
+from os.path import isdir, isfile, islink, join
+from optparse import OptionParser
+from subprocess import check_call, CalledProcessError, PIPE
+
+options = None
+args = []
+available_types = set(['scons'])
+tool_stdout = PIPE
+
+def main():
+ global options
+ global args
+ global tool_stdout
+ """Parse the options and execute the program."""
+ usage = \
+ """Usage: %prog [options] [test1 [test2 [...]]]
+
+ If you provide one or more tests, this will run the provided tests.
+ Otherwise, it will look for tests in the current directory and run them all.
+ """
+ # option parsing
+ parser = OptionParser(usage)
+
+ parser.set_defaults(
+ action='run',
+ verbose=True)
+
+ parser.add_option("-c", "--clean",
+ action='store_const', const='clean', dest='action',
+ help="deletes any generated files in the tests")
+ parser.add_option("--run",
+ action='store_const', const='run', dest='action',
+ help="sets up the environment, compiles and runs the tests")
+ parser.add_option("-v", "--verbose",
+ action='store_true', dest='verbose',
+ help="spew out more details")
+ parser.add_option("-q", "--quiet",
+ action='store_false', dest='verbose',
+ help="spew out only success/failure of tests")
+ parser.add_option("--target-dir",
+ dest='target_dir', action='store', default='./',
+ help='target directory to look for tests in. default: %default')
+ parser.add_option("--debug",
+ dest='debug', action='store_true', default=False,
+ help='turn on debug output.')
+
+ (options, args) = parser.parse_args()
+
+ if options.debug or options.verbose:
+ tool_stdout = None
+ # gather the tests
+ tests = []
+ if len(args) == 0:
+ tests = crawl_tests(options.target_dir)
+ else:
+ tests = args
+ tests = purge_tests(tests)
+
+ # run the tests
+ if options.action == 'run':
+ for t in tests:
+ run_test(t)
+ elif options.action == 'clean':
+ for t in tests:
+ clean_test(t)
+
+def crawl_tests(target):
+ """Gather the directories in the test directory."""
+ files = os.listdir(target)
+ return [f for f in files if isdir(f) and f[0] != '.']
+
+def purge_tests(dirs):
+ """Look at the test candidates and purge those that aren't from the list"""
+ tests = []
+ for t in dirs:
+ if isfile(join(t, 'TestDef.py')):
+ tests.append(t)
+ else:
+ warn("{0} is not a test (missing TestDef.py file).".format(t))
+ return tests
+
+def warn(msg):
+ """A general warning function."""
+ if options.verbose:
+ print('[Warn]: ' + msg, file=sys.stderr)
+
+def notice(msg):
+ """A general print function."""
+ if options.verbose:
+ print(msg)
+
+def debug(msg):
+ """A debugging function"""
+ if options.debug:
+ print(msg)
+
+def run_test(t):
+ """Runs the test in directory t."""
+ opts = read_opts(t)
+ notice("-----------------------------------------------------")
+ notice("running test '{0}':\n".format(t))
+ readme = join(t, 'README')
+ if isfile(readme):
+ notice(open(readme).read())
+ notice("")
+ if opts['type'] not in available_types:
+ warn('{0} is not a recognised test type in {1}'.format(opts['type'], t))
+ return
+ if not opts['expect_success']:
+ warn("tests that fail intentionally are not yet supported.")
+ return
+
+ # set up the environment
+ setup_env(t, opts)
+ # run the test
+ try:
+ if opts['type'] == 'scons':
+ run_scons(t, opts)
+ except RuntimeError as e:
+ print("Test {0} failed.".format(t))
+ return
+
+ if not options.verbose:
+ print('.', end='')
+ sys.stdout.flush()
+ else:
+ print("test '{0}' successful.".format(t))
+
+def read_opts(t):
+ """Read the test options and return them."""
+ opts = {
+ 'expect_success' : True,
+ 'type' : 'scons',
+ 'links' : {}
+ }
+ f = open(join(t, "TestDef.py"))
+ exec(f.read(), opts)
+ return opts
+
+def setup_env(t, opts):
+ """Set up the environment for the test."""
+ # symlinks
+ links = opts['links']
+ for link in links:
+ frm = links[link]
+ to = join(t, link)
+ debug("Symlinking {0} to {1}".format(frm, to))
+ if islink(to):
+ os.unlink(to)
+ os.symlink(frm, to)
+
+def teardown_env(t, opts):
+ """Remove all files generated for the test."""
+ links = opts['links']
+ for link in links:
+ to = join(t, link)
+ debug('removing link {0}'.format(to))
+ os.unlink(to)
+
+def clean_test(t):
+ """Remove all generated files."""
+ opts = read_opts(t)
+ notice("cleaning test {0}".format(t))
+ if opts['type'] == 'scons':
+ setup_env(t, opts) # scons needs the environment links to work
+ clean_scons(t, opts)
+ teardown_env(t, opts)
+
+def clean_scons(t, opts):
+ """Make scons clean after itself."""
+ cwd = os.getcwd()
+ os.chdir(t)
+ try:
+ check_call(['scons', '--clean'], stdout=tool_stdout, stderr=None)
+ except CalledProcessError as e:
+ warn("SCons failed with error {0}".format(e.returncode))
+ os.chdir(cwd)
+ sconsign = join(t, '.sconsign.dblite')
+ if isfile(sconsign):
+ os.unlink(sconsign)
+
+def run_scons(t, opts):
+ """Run scons test."""
+ cwd = os.getcwd()
+ os.chdir(t)
+ try:
+ check_call(['scons', '--clean'], stdout=tool_stdout)
+ check_call(['scons', '.'], stdout=tool_stdout)
+ check_call(['scons', 'check'], stdout=tool_stdout)
+ except CalledProcessError as e:
+ os.chdir(cwd) # clean up
+ raise e
+ os.chdir(cwd)
+
+if __name__ == "__main__":
+ main()
+
+if not options.verbose:
+ print() # quiet doesn't output newlines.
diff --git a/third-party/cxxtest/build_tools/SCons/test/expanding_#/README b/third-party/cxxtest/build_tools/SCons/test/expanding_#/README
new file mode 100644
index 00000000..eac1c926
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/expanding_#/README
@@ -0,0 +1,3 @@
+Tests whether expanding '#' to the top-level directory works as intended in
+scons.
+by: Gašper Ažman
diff --git a/third-party/cxxtest/build_tools/SCons/test/expanding_#/SConstruct b/third-party/cxxtest/build_tools/SCons/test/expanding_#/SConstruct
new file mode 100644
index 00000000..bae8789b
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/expanding_#/SConstruct
@@ -0,0 +1,10 @@
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CXXTEST='./../../../../bin/cxxtestgen'
+ )
+
+env['CXXTEST_SKIP_ERRORS'] = True
+env.CxxTest(['src/ThrowNoStd.h'])
+env.CxxTest(['src/AborterNoThrow.h'])
+env.CxxTest(['src/Comments.h'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/expanding_#/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/expanding_#/TestDef.py
new file mode 100644
index 00000000..1ec6c2cc
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/expanding_#/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'src' : '../../../../test'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/README b/third-party/cxxtest/build_tools/SCons/test/globbing/README
new file mode 100644
index 00000000..a83d021f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/README
@@ -0,0 +1,2 @@
+Tests whether we can swallow file nodes as sources as well as strings.
+by: Gašper Ažman
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/SConstruct b/third-party/cxxtest/build_tools/SCons/test/globbing/SConstruct
new file mode 100644
index 00000000..f647182c
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/SConstruct
@@ -0,0 +1,3 @@
+env = Environment(toolpath=['../../'],tools=['default','cxxtest'])
+
+env.CxxTest('joint_tests',[Glob('src/*.t.h'), 'src/requirement.cpp'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/globbing/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/src/requirement.cpp b/third-party/cxxtest/build_tools/SCons/test/globbing/src/requirement.cpp
new file mode 100644
index 00000000..45d60ad7
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/src/requirement.cpp
@@ -0,0 +1,14 @@
+/**
+ * @file requirement.cpp
+ * Implementation of the requirement function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:09:42 AM
+ */
+
+#include "requirement.h"
+
+bool call_a_requirement() {
+ return true;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/src/requirement.h b/third-party/cxxtest/build_tools/SCons/test/globbing/src/requirement.h
new file mode 100644
index 00000000..9bb94370
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/src/requirement.h
@@ -0,0 +1,14 @@
+#ifndef REQUIREMENT_H
+#define REQUIREMENT_H
+/**
+ * @file requirement.h
+ * Prototype for the call_a_requirement() function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:08:35 AM
+ */
+
+bool call_a_requirement();
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/src/test_bar.t.h b/third-party/cxxtest/build_tools/SCons/test/globbing/src/test_bar.t.h
new file mode 100644
index 00000000..76e594df
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/src/test_bar.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_BAR_T_H
+#define TEST_BAR_T_H
+/**
+ * @file test_bar.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:04:06 AM
+ */
+
+#include
+#include "requirement.h"
+
+class TestBar : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing/src/test_foo.t.h b/third-party/cxxtest/build_tools/SCons/test/globbing/src/test_foo.t.h
new file mode 100644
index 00000000..418a3ca0
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing/src/test_foo.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_FOO_T_H
+#define TEST_FOO_T_H
+/**
+ * @file test_foo.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:02:06 AM
+ */
+
+#include "requirement.h"
+#include
+
+class TestFoo : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/README b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/README
new file mode 100644
index 00000000..188908b6
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/README
@@ -0,0 +1,2 @@
+Test for various things cxxtest failed to do, but now does.
+by: Edmundo López B.
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/SConstruct b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/SConstruct
new file mode 100644
index 00000000..fdfd3bd4
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/SConstruct
@@ -0,0 +1,35 @@
+# What I want to do is the following:
+# I have my class files ending with .cc and
+# the main file ending with .cpp. This way it
+# very easy to do the following line just to
+# have all sources in that variable
+
+import os
+
+mySrc = Glob("*.cc")
+myFlags = ['-I.']
+
+myEnv = Environment( ENV = os.environ, tools = ['default', \
+ 'cxxtest'], toolpath=['../../'])
+
+# Here is the first problem I corrected:
+# Flags won't be correctly recognized by cxxtest
+myEnv.Replace(CXXFLAGS = myFlags)
+
+
+# Then I want to convert those sources to objects
+
+myObjs = myEnv.Object(mySrc)
+
+# Having the objects I can create my program
+# this way:
+
+myEnv.Program('hello', ['main.cpp'] + myObjs)
+
+# Now I want to do the same thing with the tests
+# target
+# With the non corrected version you'll get 2 errors:
+# The CXXFLAGS are not set correctly
+# It won't even accept this construction, which as you see
+# works perfectly with Program (and CxxTest should work like it)
+myEnv.CxxTest('helloTest', ['hellotest.t.h'] + myObjs)
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hello.cc b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hello.cc
new file mode 100644
index 00000000..e18191d5
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hello.cc
@@ -0,0 +1,22 @@
+/**
+ * \file
+ * Implementation of class.
+ */
+/****************************************************
+ * Author: Edmundo LOPEZ
+ * email: lopezed5@etu.unige.ch
+ *
+ * This code was written as a part of my bachelor
+ * thesis at the University of Geneva.
+ *
+ * $Id$
+ *
+ * **************************************************/
+
+#include
+
+int
+Hello::foo(int x, int y)
+ {
+ return x + y;
+ }
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hello.hh b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hello.hh
new file mode 100644
index 00000000..72299954
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hello.hh
@@ -0,0 +1,15 @@
+/**
+ * \file
+ * File containing a class
+ */
+/****************************************************
+ * Author: Edmundo LOPEZ
+ * email: lopezed5@etu.unige.ch
+ *
+ * **************************************************/
+
+class Hello
+ {
+ public:
+ int foo(int x, int y);
+ };
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hellotest.t.h b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hellotest.t.h
new file mode 100644
index 00000000..e90f26b2
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/hellotest.t.h
@@ -0,0 +1,23 @@
+/**
+ * \file
+ * The test file.
+ */
+/****************************************************
+ * Author: Edmundo LOPEZ
+ * email: lopezed5@etu.unige.ch
+ *
+ * **************************************************/
+
+#include
+#include
+
+
+class helloTestSuite : public CxxTest::TestSuite
+ {
+ public:
+ void testFoo()
+ {
+ Hello h;
+ TS_ASSERT_EQUALS (h.foo(2,2), 4);
+ }
+ };
diff --git a/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/main.cpp b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/main.cpp
new file mode 100644
index 00000000..21f1938f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/globbing_edmundo/main.cpp
@@ -0,0 +1,18 @@
+/**
+ * \file
+ * Main function comes here.
+ */
+/****************************************************
+ * Author: Edmundo LOPEZ
+ * email: lopezed5@etu.unige.ch
+ *
+ * **************************************************/
+
+#include
+#include
+
+int main (int argc, char *argv[])
+ {
+ Hello h;
+ std::cout << h.foo(2,3) << std::endl;
+ }
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/README b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/README
new file mode 100644
index 00000000..64905b91
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/README
@@ -0,0 +1,3 @@
+Tests:
+ - if CXXTEST_CXXFLAGS_REMOVE and CXXTEST_CCFLAGS_REMOVE flags work,
+ - if CCFLAGS and CXXFLAGS vars work.
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/SConstruct b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/SConstruct
new file mode 100644
index 00000000..d946c33f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/SConstruct
@@ -0,0 +1,12 @@
+flags = '-pedantic-errors -Weffc++ -Wall -Wextra -ansi'
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CCFLAGS=flags,
+ CXXFLAGS=flags,
+ CXXTEST_CXXFLAGS_REMOVE=['-pedantic-errors','-Weffc++','-Wextra','-Wall','-W'],
+ CXXTEST_CCFLAGS_REMOVE=['-pedantic-errors','-Weffc++','-Wextra','-Wall','-W']
+ )
+
+env.CxxTest(['src/not-with-pedantic.h'])
+env.CxxTest(['src/only_with_ansi.t.h'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/src/not-with-pedantic.h b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/src/not-with-pedantic.h
new file mode 100644
index 00000000..e7377bb2
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/src/not-with-pedantic.h
@@ -0,0 +1,20 @@
+/**
+ * @file not-with-pedantic.h
+ * Compiles, but not with -pedantic.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-09-30 13:33:50
+ */
+
+
+#include
+
+class TestPedantic : public CxxTest::TestSuite
+{
+public:
+ void testPedanticPresent() {
+ TS_ASSERT(true);
+ int f = (true)?:5;
+ }
+};
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/src/only_with_ansi.t.h b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/src/only_with_ansi.t.h
new file mode 100644
index 00000000..4f6615e6
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CCFLAGS/src/only_with_ansi.t.h
@@ -0,0 +1,22 @@
+/**
+ * @file only_with_ansi.t.h
+ * This test only runs correctly if -ansi was supplied as a g++ switch.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2009-02-11 06:26:59 PM
+ */
+
+#include
+
+class TestAnsi : public CxxTest::TestSuite
+{
+public:
+ void testAnsiPresent() {
+#ifdef __STRICT_ANSI__
+ TS_ASSERT(true);
+#else
+ TS_ASSERT(false);
+#endif
+ }
+};
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/README b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/README
new file mode 100644
index 00000000..07a99470
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/README
@@ -0,0 +1,5 @@
+This test tests whether variables that are put into the environment after it has
+been initialised work as expected.
+
+If they do not, -pedantic-errors will appear in the gcc commandline and the
+compilation WILL FAIL, failing the test.
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/SConstruct b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/SConstruct
new file mode 100644
index 00000000..aefb4393
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/SConstruct
@@ -0,0 +1,16 @@
+flags = '-Weffc++ -Wall -Wextra -std=gnu++0x'
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CCFLAGS = Split(flags) + ['-pedantic-errors'],
+ CXXFLAGS = Split(flags) + ['-pedantic-errors']
+ )
+
+env['CXXTEST_CXXFLAGS_REMOVE']=['-Weffc++','-Wextra','-Wall','-W']
+env['CXXTEST_CCFLAGS_REMOVE']='-Weffc++ -Wextra -Wall -W'
+env['CCFLAGS'] = flags
+env['CXXFLAGS'] = flags
+env['CXXTEST_SKIP_ERRORS'] = True
+
+env.CxxTest(['src/not-with-pedantic.h'])
+
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/src/not-with-pedantic.h b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/src/not-with-pedantic.h
new file mode 100644
index 00000000..2b92cd69
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/include_CXXFLAGS/src/not-with-pedantic.h
@@ -0,0 +1,19 @@
+/**
+ * @file not-with-pedantic.h
+ * Compiles, but not with -pedantic.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-09-30 13:33:50
+ */
+
+
+#include
+
+class TestPedantic : public CxxTest::TestSuite
+{
+public:
+ void testPedanticPresent() {
+ int f = (true)?:5;
+ }
+};
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/README b/third-party/cxxtest/build_tools/SCons/test/libpath/README
new file mode 100644
index 00000000..4eefa741
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/README
@@ -0,0 +1,2 @@
+Test whether we can run program that depends on (shared) libraries that we know
+but they are outside of standard load path.
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/SConstruct b/third-party/cxxtest/build_tools/SCons/test/libpath/SConstruct
new file mode 100644
index 00000000..b89e2b89
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/SConstruct
@@ -0,0 +1,3 @@
+env = Environment(toolpath=['../../'],tools=['default','cxxtest'])
+
+SConscript(['src/SConscript', 'test/SConscript'], exports = ['env'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/libpath/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/src/SConscript b/third-party/cxxtest/build_tools/SCons/test/libpath/src/SConscript
new file mode 100644
index 00000000..889aa8ad
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/src/SConscript
@@ -0,0 +1,3 @@
+Import('env')
+
+env.SharedLibrary('foo', 'foo.cpp')
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/src/foo.cpp b/third-party/cxxtest/build_tools/SCons/test/libpath/src/foo.cpp
new file mode 100644
index 00000000..e05eb7e6
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/src/foo.cpp
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/test/SConscript b/third-party/cxxtest/build_tools/SCons/test/libpath/test/SConscript
new file mode 100644
index 00000000..476e11d0
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/test/SConscript
@@ -0,0 +1,2 @@
+Import('env')
+env.CxxTest('test.t.h', LIBS = ['foo'], CXXTEST_LIBPATH = ['../src'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath/test/test.t.h b/third-party/cxxtest/build_tools/SCons/test/libpath/test/test.t.h
new file mode 100644
index 00000000..eb505f14
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath/test/test.t.h
@@ -0,0 +1,12 @@
+// test/test.t.h
+#include
+
+extern int foo();
+class FooTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testFoo(void)
+ {
+ TS_ASSERT_EQUALS(foo(), 0);
+ }
+};
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/README b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/README
new file mode 100644
index 00000000..756e57cf
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/README
@@ -0,0 +1,3 @@
+Test whether we can run program that depends on (shared) libraries that we know
+but they are outside of standard load path. Test whether multiple test runners
+do not alter each other.
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/SConstruct b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/SConstruct
new file mode 100644
index 00000000..98288e9b
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/SConstruct
@@ -0,0 +1,3 @@
+env = Environment(toolpath=['../../'],tools=['default','cxxtest'])
+
+SConscript(['src1/SConscript', 'src2/SConscript', 'test/SConscript'], exports = ['env'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src1/SConscript b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src1/SConscript
new file mode 100644
index 00000000..889aa8ad
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src1/SConscript
@@ -0,0 +1,3 @@
+Import('env')
+
+env.SharedLibrary('foo', 'foo.cpp')
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src1/foo.cpp b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src1/foo.cpp
new file mode 100644
index 00000000..e05eb7e6
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src1/foo.cpp
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src2/SConscript b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src2/SConscript
new file mode 100644
index 00000000..591773fa
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src2/SConscript
@@ -0,0 +1,3 @@
+Import('env')
+
+env.SharedLibrary('bar', 'bar.cpp')
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src2/bar.cpp b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src2/bar.cpp
new file mode 100644
index 00000000..01eedf70
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/src2/bar.cpp
@@ -0,0 +1,4 @@
+int bar()
+{
+ return 0;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/SConscript b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/SConscript
new file mode 100644
index 00000000..502196ac
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/SConscript
@@ -0,0 +1,5 @@
+Import('env')
+env.CxxTest('test1.t.h', LIBS = ['foo'], CXXTEST_LIBPATH = ['../src1'], CXXTEST_TARGET = 'check-1')
+env.CxxTest('test2.t.h', LIBS = ['bar'], CXXTEST_LIBPATH = ['../src2'], CXXTEST_TARGET = 'check-2')
+env.Alias('check', ['check-1', 'check-2'])
+env.AlwaysBuild('check')
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/test1.t.h b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/test1.t.h
new file mode 100644
index 00000000..eb505f14
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/test1.t.h
@@ -0,0 +1,12 @@
+// test/test.t.h
+#include
+
+extern int foo();
+class FooTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testFoo(void)
+ {
+ TS_ASSERT_EQUALS(foo(), 0);
+ }
+};
diff --git a/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/test2.t.h b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/test2.t.h
new file mode 100644
index 00000000..7378ba49
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/libpath_multitarget/test/test2.t.h
@@ -0,0 +1,12 @@
+// test/test.t.h
+#include
+
+extern int bar();
+class BarTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testBar(void)
+ {
+ TS_ASSERT_EQUALS(bar(), 0);
+ }
+};
diff --git a/third-party/cxxtest/build_tools/SCons/test/multifile_tests/SConstruct b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/SConstruct
new file mode 100644
index 00000000..435b9cb3
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/SConstruct
@@ -0,0 +1,8 @@
+env = Environment(toolpath=['../../'],tools=['default','cxxtest'])
+
+env.CxxTest('joint_tests',
+ Split('src/test_foo.t.h '
+ 'src/test_bar.t.h '
+ 'src/requirement.cpp'
+ )
+ )
diff --git a/third-party/cxxtest/build_tools/SCons/test/multifile_tests/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/requirement.cpp b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/requirement.cpp
new file mode 100644
index 00000000..45d60ad7
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/requirement.cpp
@@ -0,0 +1,14 @@
+/**
+ * @file requirement.cpp
+ * Implementation of the requirement function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:09:42 AM
+ */
+
+#include "requirement.h"
+
+bool call_a_requirement() {
+ return true;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/requirement.h b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/requirement.h
new file mode 100644
index 00000000..9bb94370
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/requirement.h
@@ -0,0 +1,14 @@
+#ifndef REQUIREMENT_H
+#define REQUIREMENT_H
+/**
+ * @file requirement.h
+ * Prototype for the call_a_requirement() function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:08:35 AM
+ */
+
+bool call_a_requirement();
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/test_bar.t.h b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/test_bar.t.h
new file mode 100644
index 00000000..76e594df
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/test_bar.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_BAR_T_H
+#define TEST_BAR_T_H
+/**
+ * @file test_bar.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:04:06 AM
+ */
+
+#include
+#include "requirement.h"
+
+class TestBar : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/test_foo.t.h b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/test_foo.t.h
new file mode 100644
index 00000000..418a3ca0
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/multifile_tests/src/test_foo.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_FOO_T_H
+#define TEST_FOO_T_H
+/**
+ * @file test_foo.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:02:06 AM
+ */
+
+#include "requirement.h"
+#include
+
+class TestFoo : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/need_cpppath/SConstruct b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/SConstruct
new file mode 100644
index 00000000..d457e55e
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/SConstruct
@@ -0,0 +1,9 @@
+
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CXXTEST_INSTALL_DIR = '../../../../',
+ CPPPATH = ['src/cpppathdir/']
+ )
+
+env.CxxTest(['src/cpppath.t.h'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/need_cpppath/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/TestDef.py
new file mode 100644
index 00000000..e69de29b
diff --git a/third-party/cxxtest/build_tools/SCons/test/need_cpppath/src/cpppath.t.h b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/src/cpppath.t.h
new file mode 100644
index 00000000..3c08c391
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/src/cpppath.t.h
@@ -0,0 +1,25 @@
+#ifndef CPPPATH_T_H
+#define CPPPATH_T_H
+
+/**
+ * @file cpppath.t.h
+ * This file needs the include in the include dir.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-28 11:16:46 AM
+ */
+
+// actual path cpppathdir/include.h
+#include "include.h"
+#include
+
+class CppPathTest : public CxxTest::TestSuite
+{
+public:
+ void test_i_need_me_exists() {
+ TS_ASSERT(i_need_me() == 0);
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/need_cpppath/src/cpppathdir/include.h b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/src/cpppathdir/include.h
new file mode 100644
index 00000000..93d3b039
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/need_cpppath/src/cpppathdir/include.h
@@ -0,0 +1,16 @@
+#ifndef INCLUDE_H
+#define INCLUDE_H
+/**
+ * @file include.h
+ * Include file for this test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-28 11:15:40 AM
+ */
+
+int i_need_me() {
+ return 0;
+}
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/nonstandard_cxxtest_dir/SConstruct b/third-party/cxxtest/build_tools/SCons/test/nonstandard_cxxtest_dir/SConstruct
new file mode 100644
index 00000000..9b811621
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/nonstandard_cxxtest_dir/SConstruct
@@ -0,0 +1,10 @@
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CXXTEST_INSTALL_DIR = '../../../../'
+ )
+
+env['CXXTEST_SKIP_ERRORS'] = True
+env.CxxTest(['src/ThrowNoStd.h'])
+env.CxxTest(['src/AborterNoThrow.h'])
+env.CxxTest(['src/Comments.h'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/nonstandard_cxxtest_dir/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/nonstandard_cxxtest_dir/TestDef.py
new file mode 100644
index 00000000..b76a14cb
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/nonstandard_cxxtest_dir/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'src' : '../../../../test/'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/printer_propagation/SConstruct b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/SConstruct
new file mode 100644
index 00000000..d87118ff
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/SConstruct
@@ -0,0 +1,8 @@
+
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CXXTEST_INSTALL_DIR = '../../../../',
+ )
+
+env.CxxTest(['src/failtest.t.h'], CPPPATH=['#'], CXXTEST_RUNNER="CrazyRunner")
diff --git a/third-party/cxxtest/build_tools/SCons/test/printer_propagation/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/TestDef.py
new file mode 100644
index 00000000..e69de29b
diff --git a/third-party/cxxtest/build_tools/SCons/test/printer_propagation/cxxtest/CrazyRunner.h b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/cxxtest/CrazyRunner.h
new file mode 100644
index 00000000..6ceac42a
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/cxxtest/CrazyRunner.h
@@ -0,0 +1,16 @@
+#ifndef __cxxtest_CrazyRunner_h__
+#define __cxxtest_CrazyRunner_h__
+
+
+/*
+ * This is not a proper runner. Just a simple class that looks like one.
+ */
+namespace CxxTest {
+ class CrazyRunner {
+ public:
+ int run() { return 0; }
+ void process_commandline(int argc, char** argv) { }
+ };
+}
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/printer_propagation/src/failtest.t.h b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/src/failtest.t.h
new file mode 100644
index 00000000..ac8c8295
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/printer_propagation/src/failtest.t.h
@@ -0,0 +1,23 @@
+#ifndef FAILTEST_T_H
+#define FAILTEST_T_H
+
+/**
+ * @file failtest.t.h
+ * This test will succed only with a CrazyRunner.
+ *
+ * @author
+ * @version 1.0
+ * @since jue ago 28 14:18:57 ART 2008
+ */
+
+#include
+
+class CppPathTest : public CxxTest::TestSuite
+{
+public:
+ void test_i_will_fail() {
+ TS_ASSERT(false);
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/README b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/README
new file mode 100644
index 00000000..e1e6b749
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/README
@@ -0,0 +1,2 @@
+Tests whether we can swallow recursively supplied sources - a list of lists, for
+instance.
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/SConstruct b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/SConstruct
new file mode 100644
index 00000000..5ba85026
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/SConstruct
@@ -0,0 +1,3 @@
+env = Environment(toolpath=['../../'],tools=['default','cxxtest'])
+
+env.CxxTest('joint_tests',['src/test_foo.t.h',['src/test_bar.t.h','src/requirement.cpp']])
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/TestDef.py
new file mode 100644
index 00000000..3758853f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/TestDef.py
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+links = {'cxxtest' : '../../../../'}
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/requirement.cpp b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/requirement.cpp
new file mode 100644
index 00000000..45d60ad7
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/requirement.cpp
@@ -0,0 +1,14 @@
+/**
+ * @file requirement.cpp
+ * Implementation of the requirement function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:09:42 AM
+ */
+
+#include "requirement.h"
+
+bool call_a_requirement() {
+ return true;
+}
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/requirement.h b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/requirement.h
new file mode 100644
index 00000000..9bb94370
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/requirement.h
@@ -0,0 +1,14 @@
+#ifndef REQUIREMENT_H
+#define REQUIREMENT_H
+/**
+ * @file requirement.h
+ * Prototype for the call_a_requirement() function.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:08:35 AM
+ */
+
+bool call_a_requirement();
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/test_bar.t.h b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/test_bar.t.h
new file mode 100644
index 00000000..76e594df
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/test_bar.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_BAR_T_H
+#define TEST_BAR_T_H
+/**
+ * @file test_bar.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:04:06 AM
+ */
+
+#include
+#include "requirement.h"
+
+class TestBar : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/test_foo.t.h b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/test_foo.t.h
new file mode 100644
index 00000000..418a3ca0
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/recursive_sources/src/test_foo.t.h
@@ -0,0 +1,23 @@
+#ifndef TEST_FOO_T_H
+#define TEST_FOO_T_H
+/**
+ * @file test_foo.t.h
+ * Test one for the joint test ehm, test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-29 10:02:06 AM
+ */
+
+#include "requirement.h"
+#include
+
+class TestFoo : public CxxTest::TestSuite
+{
+public:
+ void test_foo() {
+ TS_ASSERT(call_a_requirement());
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/string_cpppath/SConstruct b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/SConstruct
new file mode 100644
index 00000000..4e1e8fee
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/SConstruct
@@ -0,0 +1,9 @@
+
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CXXTEST_INSTALL_DIR = '../../../../',
+ CPPPATH = 'src/cpppathdir/'
+ )
+
+env.CxxTest(['src/cpppath.t.h'])
diff --git a/third-party/cxxtest/build_tools/SCons/test/string_cpppath/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/TestDef.py
new file mode 100644
index 00000000..e69de29b
diff --git a/third-party/cxxtest/build_tools/SCons/test/string_cpppath/src/cpppath.t.h b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/src/cpppath.t.h
new file mode 100644
index 00000000..3c08c391
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/src/cpppath.t.h
@@ -0,0 +1,25 @@
+#ifndef CPPPATH_T_H
+#define CPPPATH_T_H
+
+/**
+ * @file cpppath.t.h
+ * This file needs the include in the include dir.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-28 11:16:46 AM
+ */
+
+// actual path cpppathdir/include.h
+#include "include.h"
+#include
+
+class CppPathTest : public CxxTest::TestSuite
+{
+public:
+ void test_i_need_me_exists() {
+ TS_ASSERT(i_need_me() == 0);
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/string_cpppath/src/cpppathdir/include.h b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/src/cpppathdir/include.h
new file mode 100644
index 00000000..93d3b039
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/string_cpppath/src/cpppathdir/include.h
@@ -0,0 +1,16 @@
+#ifndef INCLUDE_H
+#define INCLUDE_H
+/**
+ * @file include.h
+ * Include file for this test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-28 11:15:40 AM
+ */
+
+int i_need_me() {
+ return 0;
+}
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/target_syntax/SConstruct b/third-party/cxxtest/build_tools/SCons/test/target_syntax/SConstruct
new file mode 100644
index 00000000..7a600bba
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/target_syntax/SConstruct
@@ -0,0 +1,9 @@
+
+env = Environment(
+ toolpath=['../../'],
+ tools=['default','cxxtest'],
+ CXXTEST_INSTALL_DIR = '../../../../',
+ CPPPATH = ['src/cpppathdir/']
+ )
+
+env.CxxTest('src/cpppath')
diff --git a/third-party/cxxtest/build_tools/SCons/test/target_syntax/TestDef.py b/third-party/cxxtest/build_tools/SCons/test/target_syntax/TestDef.py
new file mode 100644
index 00000000..e69de29b
diff --git a/third-party/cxxtest/build_tools/SCons/test/target_syntax/src/cpppath.t.h b/third-party/cxxtest/build_tools/SCons/test/target_syntax/src/cpppath.t.h
new file mode 100644
index 00000000..3c08c391
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/target_syntax/src/cpppath.t.h
@@ -0,0 +1,25 @@
+#ifndef CPPPATH_T_H
+#define CPPPATH_T_H
+
+/**
+ * @file cpppath.t.h
+ * This file needs the include in the include dir.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-28 11:16:46 AM
+ */
+
+// actual path cpppathdir/include.h
+#include "include.h"
+#include
+
+class CppPathTest : public CxxTest::TestSuite
+{
+public:
+ void test_i_need_me_exists() {
+ TS_ASSERT(i_need_me() == 0);
+ }
+};
+
+#endif
diff --git a/third-party/cxxtest/build_tools/SCons/test/target_syntax/src/cpppathdir/include.h b/third-party/cxxtest/build_tools/SCons/test/target_syntax/src/cpppathdir/include.h
new file mode 100644
index 00000000..93d3b039
--- /dev/null
+++ b/third-party/cxxtest/build_tools/SCons/test/target_syntax/src/cpppathdir/include.h
@@ -0,0 +1,16 @@
+#ifndef INCLUDE_H
+#define INCLUDE_H
+/**
+ * @file include.h
+ * Include file for this test.
+ *
+ * @author Gašper Ažman (GA), gasper.azman@gmail.com
+ * @version 1.0
+ * @since 2008-08-28 11:15:40 AM
+ */
+
+int i_need_me() {
+ return 0;
+}
+
+#endif
diff --git a/third-party/cxxtest/build_tools/cmake/CxxTest.cmake b/third-party/cxxtest/build_tools/cmake/CxxTest.cmake
new file mode 100644
index 00000000..6ed3652f
--- /dev/null
+++ b/third-party/cxxtest/build_tools/cmake/CxxTest.cmake
@@ -0,0 +1,17 @@
+
+include("${CMAKE_CURRENT_LIST_DIR}/FindCxxTest.cmake")
+
+function(cxx_test target source)
+ get_filename_component(CPP_FILE_NAME ${source} NAME)
+ string(REGEX REPLACE "h$|hpp$" "cpp" CPP_FILE_NAME ${CPP_FILE_NAME})
+ message(${CPP_FILE_NAME})
+ set(CPP_FULL_NAME "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE_NAME}")
+ add_custom_command(
+ OUTPUT "${CPP_FULL_NAME}"
+ COMMAND ${CXXTESTGEN} --runner=ErrorPrinter --output "${CPP_FULL_NAME}" "${source}"
+ DEPENDS "${source}"
+ )
+ add_executable(${target} ${CPP_FULL_NAME})
+ set_target_properties(${target} PROPERTIES COMPILE_FLAGS "-Wno-effc++")
+ add_test(${target} ${RUNTIME_OUTPUT_DIRECTORY}/${target})
+endfunction(cxx_test)
diff --git a/third-party/cxxtest/build_tools/cmake/FindCxxTest.cmake b/third-party/cxxtest/build_tools/cmake/FindCxxTest.cmake
new file mode 100644
index 00000000..e1e4404c
--- /dev/null
+++ b/third-party/cxxtest/build_tools/cmake/FindCxxTest.cmake
@@ -0,0 +1,36 @@
+IF (DEFINED FIND_CXXTEST_CMAKE_INCLUDED)
+ RETURN()
+ENDIF (DEFINED FIND_CXXTEST_CMAKE_INCLUDED)
+SET(FIND_CXXTEST_CMAKE_INCLUDED true)
+
+FIND_PROGRAM(CXXTESTGEN
+ NAMES cxxtestgen
+ PATHS "${CXXTEST_PATH}/bin"
+ "${PROJECT_SOURCE_DIR}/cxxtest/bin"
+ "${PROJECT_SOURCE_DIR}/lib/cxxtest/bin"
+ "${PROJECT_BINARY_DIR}/cxxtest/bin"
+ "${PROJECT_BINARY_DIR}/lib/cxxtest/bin"
+ /usr/bin
+ /bin
+ )
+
+FIND_PATH(CXXTEST_INCLUDES
+ NAMES "cxxtest/TestSuite.h"
+ PATHS "${CXXTEST_PATH}"
+ "${PROJECT_SOURCE_DIR}/cxxtest/"
+ "${PROJECT_SOURCE_DIR}/lib/cxxtest/"
+ )
+
+IF(NOT CXXTESTGEN)
+ MESSAGE(FATAL_ERROR "Unable to find 'cxxtestgen'")
+ SET(CXXTEST_FOUND false)
+ELSEIF(NOT CXXTEST_INCLUDES)
+ SET(CXXTEST_FOUND false)
+ELSE(NOT CXXTESTGEN)
+ SET(CXXTEST_FOUND true)
+ SET(CXXTEST_ROOT ${CXXTEST_INCLUDES})
+ENDIF(NOT CXXTESTGEN)
+
+SET(CXXTEST_CMAKE_MODULES_PATH "${CMAKE_CURRENT_LIST_DIR}")
+INCLUDE("${CXXTEST_CMAKE_MODULES_PATH}/CxxTest.cmake")
+
diff --git a/third-party/cxxtest/cxxtest b/third-party/cxxtest/cxxtest
new file mode 160000
index 00000000..191adddb
--- /dev/null
+++ b/third-party/cxxtest/cxxtest
@@ -0,0 +1 @@
+Subproject commit 191adddb3876ab389c0c856e1c03874bf70f8ee4
diff --git a/third-party/cxxtest/doc/Makefile b/third-party/cxxtest/doc/Makefile
new file mode 100644
index 00000000..f3e890f1
--- /dev/null
+++ b/third-party/cxxtest/doc/Makefile
@@ -0,0 +1,40 @@
+.PHONY: all anchors outputs clean manpages
+
+export XML_CATALOG_FILES = catalog.xml
+PY = python
+XSLTPROC_OPTS := --stringparam toc.section.depth 2 --stringparam generate.section.toc.level 1
+DBLATEX_OPTS := -P latex.output.revhistory=0 -P doc.collab.show=1 -P toc.section.depth=2
+A2X_OPTS := -a toc -a icons -L -d article -v --xsltproc-opts "$(XSLTPROC_OPTS)" --dblatex-opts "$(DBLATEX_OPTS)"
+
+%.html: %.txt anchors outputs
+ asciidoc -a data-uri -v -b html -d article -n -a toc2 -a icons $<
+
+# Ignore errors (dblatex may not be installed)
+%.pdf: %.txt anchors outputs
+ - a2x -f pdf $(A2X_OPTS) $<
+
+# Ignore errors
+%.epub: %.txt anchors outputs
+ - a2x -f epub $(A2X_OPTS) $<
+
+all: guide.html guide.pdf guide.epub
+
+manpages:
+ cd man; ./create_manpage;
+ cd man; asciidoc -v -d manpage ./cxxtestgen.1.txt
+
+html: guide.html
+
+pdf: guide.pdf
+
+epub: guide.epub
+
+anchors: guide.txt
+ $(PY) include_anchors.py $<
+
+outputs:
+ ../bin/cxxtestgen -h > examples/cxxtestgen.out
+
+clean:
+ - \rm -f guide.xml
+ - \rm -f examples/.*.py examples/.*.h examples/.*.cpp examples/.*.sh examples/runner examples/TEST*.xml examples/parsetab.py examples/*.orig examples/runner.cpp
diff --git a/third-party/cxxtest/doc/README.txt b/third-party/cxxtest/doc/README.txt
new file mode 100644
index 00000000..75254456
--- /dev/null
+++ b/third-party/cxxtest/doc/README.txt
@@ -0,0 +1,43 @@
+This directory supports the creation of the CxxTest User Guide using
+asciidoc and a2x commands.
+
+HTML
+
+The command
+
+ make html
+
+creates the guide.html file.
+
+
+PDF
+
+The command
+
+ make pdf
+
+creates the guide.tex file, which generates the guide.pdf file using
+dblatex.
+
+
+
+EPUB
+
+The command
+
+ make epub
+
+creates the file make.epub. Note that the `catalog.xml` file is
+used, which configures asciidoc to use the docbook XML data in the
+`epub` directory. This is a bit of a hack. It apparently works
+around a limitation of the MacPorts installation of asciidoc.
+
+
+MANPAGES
+
+The command
+
+ make manpages
+
+creates CxxTest man pages in the doc/man directory.
+
diff --git a/third-party/cxxtest/doc/catalog.xml b/third-party/cxxtest/doc/catalog.xml
new file mode 100644
index 00000000..fde98a7f
--- /dev/null
+++ b/third-party/cxxtest/doc/catalog.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/third-party/cxxtest/doc/epub/README b/third-party/cxxtest/doc/epub/README
new file mode 100644
index 00000000..5e2587a1
--- /dev/null
+++ b/third-party/cxxtest/doc/epub/README
@@ -0,0 +1,88 @@
+----------------------------------------------------------------------
+ README file for the DocBook XSL Stylesheets
+----------------------------------------------------------------------
+
+These are XSL stylesheets for transforming DocBook XML document
+instances into .epub format.
+
+.epub is an open standard of the The International Digital Publishing Forum (IDPF),
+a the trade and standards association for the digital publishing industry.
+
+An alpha-quality reference implementation (dbtoepub) for a DocBook to .epub
+converter (written in Ruby) is available under bin/.
+
+From http://idpf.org
+ What is EPUB, .epub, OPS/OCF & OEB?
+
+ ".epub" is the file extension of an XML format for reflowable digital
+ books and publications. ".epub" is composed of three open standards,
+ the Open Publication Structure (OPS), Open Packaging Format (OPF) and
+ Open Container Format (OCF), produced by the IDPF. "EPUB" allows
+ publishers to produce and send a single digital publication file
+ through distribution and offers consumers interoperability between
+ software/hardware for unencrypted reflowable digital books and other
+ publications. The Open eBook Publication Structure or "OEB",
+ originally produced in 1999, is the precursor to OPS.
+
+----------------------------------------------------------------------
+.epub Constraints
+----------------------------------------------------------------------
+
+.epub does not support all of the image formats that DocBook supports.
+When an image is available in an accepted format, it will be used. The
+accepted @formats are: 'GIF','GIF87a','GIF89a','JPEG','JPG','PNG','SVG'
+A mime-type for the image will be guessed from the file extension,
+which may not work if your file extensions are non-standard.
+
+Non-supported elements:
+ *
+ * , , , with text/XML
+ @filerefs
+ *
+ * in lists (generic XHTML rendering inability)
+ * (just make your programlistings
+ siblings, rather than descendents of paras)
+
+----------------------------------------------------------------------
+dbtoepub Reference Implementation
+----------------------------------------------------------------------
+
+An alpha-quality DocBook to .epub conversion program, dbtoepub, is provided
+in bin/dbtoepub.
+
+This tool requires:
+ - 'xsltproc' in your PATH
+ - 'zip' in your PATH
+ - Ruby 1.8.4+
+
+Windows compatibility has not been extensively tested; bug reports encouraged.
+[See http://www.zlatkovic.com/libxml.en.html and http://unxutils.sourceforge.net/]
+
+$ dbtoepub --help
+ Usage: dbtoepub [OPTIONS] [DocBook Files]
+
+ dbtoepub converts DocBook and s into to .epub files.
+
+ .epub is defined by the IDPF at www.idpf.org and is made up of 3 standards:
+ - Open Publication Structure (OPS)
+ - Open Packaging Format (OPF)
+ - Open Container Format (OCF)
+
+ Specific options:
+ -d, --debug Show debugging output.
+ -h, --help Display usage info
+ -v, --verbose Make output verbose
+
+
+----------------------------------------------------------------------
+Validation
+----------------------------------------------------------------------
+
+The epubcheck project provides limited validation for .epub documents.
+See http://code.google.com/p/epubcheck/ for details.
+
+----------------------------------------------------------------------
+Copyright information
+----------------------------------------------------------------------
+See the accompanying file named COPYING.
+
diff --git a/third-party/cxxtest/doc/epub/bin/dbtoepub b/third-party/cxxtest/doc/epub/bin/dbtoepub
new file mode 100755
index 00000000..9976f816
--- /dev/null
+++ b/third-party/cxxtest/doc/epub/bin/dbtoepub
@@ -0,0 +1,76 @@
+#!/usr/bin/env ruby
+# This program converts DocBook documents into .epub files.
+#
+# Usage: dbtoepub [OPTIONS] [DocBook Files]
+#
+# .epub is defined by the IDPF at www.idpf.org and is made up of 3 standards:
+# - Open Publication Structure (OPS)
+# - Open Packaging Format (OPF)
+# - Open Container Format (OCF)
+#
+# Specific options:
+# -c, --css [FILE] Use FILE for CSS on generated XHTML.
+# -d, --debug Show debugging output.
+# -f, --font [OTF FILE] Embed OTF FILE in .epub.
+# -h, --help Display usage info.
+# -s, --stylesheet [XSL FILE] Use XSL FILE as a customization
+# layer (imports epub/docbook.xsl).
+# -v, --verbose Make output verbose.
+
+lib = File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
+$LOAD_PATH.unshift(lib) if File.exist?(lib)
+
+require 'fileutils'
+require 'optparse'
+require 'tmpdir'
+
+require 'docbook'
+
+verbose = false
+debug = false
+css_file = nil
+otf_files = []
+customization_layer = nil
+output_file = nil
+
+#$DEBUG=true
+
+# Set up the OptionParser
+opts = OptionParser.new
+opts.banner = "Usage: #{File.basename($0)} [OPTIONS] [DocBook Files]
+
+#{File.basename($0)} converts DocBook and s into to .epub files.
+
+.epub is defined by the IDPF at www.idpf.org and is made up of 3 standards:
+- Open Publication Structure (OPS)
+- Open Packaging Format (OPF)
+- Open Container Format (OCF)
+
+Specific options:"
+opts.on("-c", "--css [FILE]", "Use FILE for CSS on generated XHTML.") {|f| css_file = f}
+opts.on("-d", "--debug", "Show debugging output.") {debug = true; verbose = true}
+opts.on("-f", "--font [OTF FILE]", "Embed OTF FILE in .epub.") {|f| otf_files << f}
+opts.on("-h", "--help", "Display usage info.") {puts opts.to_s; exit 0}
+opts.on("-o", "--output [OUTPUT FILE]", "Output ePub file as OUTPUT FILE.") {|f| output_file = f}
+opts.on("-s", "--stylesheet [XSL FILE]", "Use XSL FILE as a customization layer (imports epub/docbook.xsl).") {|f| customization_layer = f}
+opts.on("-v", "--verbose", "Make output verbose.") {verbose = true}
+
+db_files = opts.parse(ARGV)
+if db_files.size == 0
+ puts opts.to_s
+ exit 0
+end
+
+db_files.each {|docbook_file|
+ dir = File.expand_path(File.join(Dir.tmpdir, ".epubtmp#{Time.now.to_f.to_s}"))
+ FileUtils.mkdir_p(dir)
+ e = DocBook::Epub.new(docbook_file, dir, css_file, customization_layer, otf_files)
+
+ if output_file
+ epub_file = output_file
+ else
+ epub_file = File.basename(docbook_file, ".xml") + ".epub"
+ end
+ puts "Rendering DocBook file #{docbook_file} to #{epub_file}" if verbose
+ e.render_to_file(epub_file)
+}
diff --git a/third-party/cxxtest/doc/epub/bin/lib/docbook.rb b/third-party/cxxtest/doc/epub/bin/lib/docbook.rb
new file mode 100755
index 00000000..14110d60
--- /dev/null
+++ b/third-party/cxxtest/doc/epub/bin/lib/docbook.rb
@@ -0,0 +1,227 @@
+require 'fileutils'
+require 'rexml/parsers/pullparser'
+
+module DocBook
+
+ class Epub
+ CHECKER = "epubcheck"
+ STYLESHEET = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', "docbook.xsl"))
+ CALLOUT_PATH = File.join('images', 'callouts')
+ CALLOUT_FULL_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', CALLOUT_PATH))
+ CALLOUT_LIMIT = 15
+ CALLOUT_EXT = ".png"
+ XSLT_PROCESSOR = "xsltproc"
+ OUTPUT_DIR = ".epubtmp#{Time.now.to_f.to_s}"
+ MIMETYPE = "application/epub+zip"
+ META_DIR = "META-INF"
+ OEBPS_DIR = "OEBPS"
+ ZIPPER = "zip"
+
+ attr_reader :output_dir
+
+ def initialize(docbook_file, output_dir=OUTPUT_DIR, css_file=nil, customization_layer=nil, embedded_fonts=[])
+ @docbook_file = docbook_file
+ @output_dir = output_dir
+ @meta_dir = File.join(@output_dir, META_DIR)
+ @oebps_dir = File.join(@output_dir, OEBPS_DIR)
+ @css_file = css_file ? File.expand_path(css_file) : css_file
+ @embedded_fonts = embedded_fonts
+ @to_delete = []
+
+ if customization_layer
+ @stylesheet = File.expand_path(customization_layer)
+ else
+ @stylesheet = STYLESHEET
+ end
+
+ unless File.exist?(@docbook_file)
+ raise ArgumentError.new("File #{@docbook_file} does not exist")
+ end
+ end
+
+ def render_to_file(output_file, verbose=false)
+ render_to_epub(output_file, verbose)
+ bundle_epub(output_file, verbose)
+ cleanup_files(@to_delete)
+ end
+
+ def self.invalid?(file)
+ # Obnoxiously, we can't just check for a non-zero output...
+ cmd = %Q(#{CHECKER} "#{file}")
+ output = `#{cmd} 2>&1`
+
+ if $?.to_i == 0
+ return false
+ else
+ STDERR.puts output if $DEBUG
+ return output
+ end
+ end
+
+ private
+ def render_to_epub(output_file, verbose)
+ @collapsed_docbook_file = collapse_docbook()
+
+ chunk_quietly = "--stringparam chunk.quietly " + (verbose ? '0' : '1')
+ callout_path = "--stringparam callout.graphics.path #{CALLOUT_PATH}/"
+ callout_limit = "--stringparam callout.graphics.number.limit #{CALLOUT_LIMIT}"
+ callout_ext = "--stringparam callout.graphics.extension #{CALLOUT_EXT}"
+ html_stylesheet = "--stringparam html.stylesheet #{File.basename(@css_file)}" if @css_file
+ base = "--stringparam base.dir #{OEBPS_DIR}/"
+ unless @embedded_fonts.empty?
+ embedded_fonts = @embedded_fonts.map {|f| File.basename(f)}.join(',')
+ font = "--stringparam epub.embedded.fonts \"#{embedded_fonts}\""
+ end
+ meta = "--stringparam epub.metainf.dir #{META_DIR}/"
+ oebps = "--stringparam epub.oebps.dir #{OEBPS_DIR}/"
+ options = [chunk_quietly,
+ callout_path,
+ callout_limit,
+ callout_ext,
+ base,
+ font,
+ meta,
+ oebps,
+ html_stylesheet,
+ ].join(" ")
+ # Double-quote stylesheet & file to help Windows cmd.exe
+ db2epub_cmd = %Q(cd "#{@output_dir}" && #{XSLT_PROCESSOR} #{options} "#{@stylesheet}" "#{@collapsed_docbook_file}")
+ STDERR.puts db2epub_cmd if $DEBUG
+ success = system(db2epub_cmd)
+ raise "Could not render as .epub to #{output_file} (#{db2epub_cmd})" unless success
+ @to_delete << Dir["#{@meta_dir}/*"]
+ @to_delete << Dir["#{@oebps_dir}/*"]
+ end
+
+ def bundle_epub(output_file, verbose)
+
+ quiet = verbose ? "" : "-q"
+ mimetype_filename = write_mimetype()
+ meta = File.basename(@meta_dir)
+ oebps = File.basename(@oebps_dir)
+ images = copy_images()
+ csses = copy_csses()
+ fonts = copy_fonts()
+ callouts = copy_callouts()
+ # zip -X -r ../book.epub mimetype META-INF OEBPS
+ # Double-quote stylesheet & file to help Windows cmd.exe
+ zip_cmd = %Q(cd "#{@output_dir}" && #{ZIPPER} #{quiet} -X -r "#{File.expand_path(output_file)}" "#{mimetype_filename}" "#{meta}" "#{oebps}")
+ puts zip_cmd if $DEBUG
+ success = system(zip_cmd)
+ raise "Could not bundle into .epub file to #{output_file}" unless success
+ end
+
+ # Input must be collapsed because REXML couldn't find figures in files that
+ # were XIncluded or added by ENTITY
+ # http://sourceforge.net/tracker/?func=detail&aid=2750442&group_id=21935&atid=373747
+ def collapse_docbook
+ # Double-quote stylesheet & file to help Windows cmd.exe
+ collapsed_file = File.join(File.expand_path(File.dirname(@docbook_file)),
+ '.collapsed.' + File.basename(@docbook_file))
+ entity_collapse_command = %Q(xmllint --loaddtd --noent -o "#{collapsed_file}" "#{@docbook_file}")
+ entity_success = system(entity_collapse_command)
+ raise "Could not collapse named entites in #{@docbook_file}" unless entity_success
+
+ xinclude_collapse_command = %Q(xmllint --xinclude -o "#{collapsed_file}" "#{collapsed_file}")
+ xinclude_success = system(xinclude_collapse_command)
+ raise "Could not collapse XIncludes in #{@docbook_file}" unless xinclude_success
+
+ @to_delete << collapsed_file
+ return collapsed_file
+ end
+
+ def copy_callouts
+ new_callout_images = []
+ if has_callouts?
+ calloutglob = "#{CALLOUT_FULL_PATH}/*#{CALLOUT_EXT}"
+ Dir.glob(calloutglob).each {|img|
+ img_new_filename = File.join(@oebps_dir, CALLOUT_PATH, File.basename(img))
+
+ # TODO: What to rescue for these two?
+ FileUtils.mkdir_p(File.dirname(img_new_filename))
+ FileUtils.cp(img, img_new_filename)
+ @to_delete << img_new_filename
+ new_callout_images << img
+ }
+ end
+ return new_callout_images
+ end
+
+ def copy_fonts
+ new_fonts = []
+ @embedded_fonts.each {|font_file|
+ font_new_filename = File.join(@oebps_dir, File.basename(font_file))
+ FileUtils.cp(font_file, font_new_filename)
+ new_fonts << font_file
+ }
+ return new_fonts
+ end
+
+ def copy_csses
+ if @css_file
+ css_new_filename = File.join(@oebps_dir, File.basename(@css_file))
+ FileUtils.cp(@css_file, css_new_filename)
+ end
+ end
+
+ def copy_images
+ image_references = get_image_refs()
+ new_images = []
+ image_references.each {|img|
+ # TODO: It'd be cooler if we had a filetype lookup rather than just
+ # extension
+ if img =~ /\.(svg|png|gif|jpe?g|xml)/i
+ img_new_filename = File.join(@oebps_dir, img)
+ img_full = File.join(File.expand_path(File.dirname(@docbook_file)), img)
+
+ # TODO: What to rescue for these two?
+ FileUtils.mkdir_p(File.dirname(img_new_filename))
+ puts(img_full + ": " + img_new_filename) if $DEBUG
+ FileUtils.cp(img_full, img_new_filename)
+ @to_delete << img_new_filename
+ new_images << img_full
+ end
+ }
+ return new_images
+ end
+
+ def write_mimetype
+ mimetype_filename = File.join(@output_dir, "mimetype")
+ File.open(mimetype_filename, "w") {|f| f.print MIMETYPE}
+ @to_delete << mimetype_filename
+ return File.basename(mimetype_filename)
+ end
+
+ def cleanup_files(file_list)
+ file_list.flatten.each {|f|
+ # Yikes
+ FileUtils.rm_r(f, :force => true )
+ }
+ end
+
+ # Returns an Array of all of the (image) @filerefs in a document
+ def get_image_refs
+ parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
+ image_refs = []
+ while parser.has_next?
+ el = parser.pull
+ if el.start_element? and (el[0] == "imagedata" or el[0] == "graphic")
+ image_refs << el[1]['fileref']
+ end
+ end
+ return image_refs.uniq
+ end
+
+ # Returns true if the document has code callouts
+ def has_callouts?
+ parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
+ while parser.has_next?
+ el = parser.pull
+ if el.start_element? and (el[0] == "calloutlist" or el[0] == "co")
+ return true
+ end
+ end
+ return false
+ end
+ end
+end
diff --git a/third-party/cxxtest/doc/epub/bin/xslt/obfuscate.xsl b/third-party/cxxtest/doc/epub/bin/xslt/obfuscate.xsl
new file mode 100644
index 00000000..4ea4cd55
--- /dev/null
+++ b/third-party/cxxtest/doc/epub/bin/xslt/obfuscate.xsl
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/third-party/cxxtest/doc/epub/docbook.xsl b/third-party/cxxtest/doc/epub/docbook.xsl
new file mode 100644
index 00000000..753fcd00
--- /dev/null
+++ b/third-party/cxxtest/doc/epub/docbook.xsl
@@ -0,0 +1,1690 @@
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+
+ book toc,title
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ncxtoc
+ htmltoc
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+ .png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Note
+
+
+ namesp. cut
+
+
+ stripped namespace before processing
+
+
+
+
+
+
+ Note
+
+
+ namesp. cut
+
+
+ processing stripped document
+
+
+
+
+
+
+
+
+
+
+ ID '
+
+ ' not found in document.
+
+
+
+
+
+
+
+
+ Formatting from
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:
+
+ :
+
+
+
+
+ urn:isbn:
+
+
+
+ urn:issn:
+
+
+
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ cover
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.0
+
+
+
+
+
+
+ application/oebps-package+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2005-1
+
+
+
+
+
+ cover
+
+
+
+
+
+
+ dtb:uid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ©
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ cover
+ Cover
+
+
+
+
+
+
+
+
+
+
+ toc
+ Table of Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ yes
+
+ no
+
+
+
+
+
+
+
+
+
+ yes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ application/x-dtbncx+xml
+
+
+
+
+
+
+ application/xhtml+xml
+
+
+
+
+
+
+
+
+
+
+ text/css
+ css
+
+
+
+
+
+
+
+
+
+
+ application/xhtml+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/gif
+
+
+ image/gif
+
+
+ image/png
+
+
+ image/png
+
+
+ image/jpeg
+
+
+ image/jpeg
+
+
+ image/jpeg
+
+
+ image/jpeg
+
+
+ image/svg+xml
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WARNING: mediaobjectco almost certainly will not render as expected in .epub!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ application/xhtml+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (missing alt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text-align:
+
+ middle
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+
+ 1
+
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No insertfile extension available.
+
+
+
+
+
+
+
+ No insertfile extension available. Use a different processor (with extensions) or turn on $use.extensions and $textinsert.extension (see docs for more).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cover
+
+ text/css
+
+ img { max-width: 100%; }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -toc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ font/opentype
+
+
+
+ WARNING: OpenType fonts should be supplied! (
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+ clear: both
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+ 5
+ 4
+ 3
+ 2
+ 1
+
+
+
+
+ title
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/third-party/cxxtest/doc/examples/Assertions.h b/third-party/cxxtest/doc/examples/Assertions.h
new file mode 100644
index 00000000..14be035c
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/Assertions.h
@@ -0,0 +1,193 @@
+// Assertions.h
+#include
+
+class Test : public CxxTest::TestSuite
+{
+public:
+
+// @assert:
+ void test_assert(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ }
+// @:assert
+
+// @assertDelta:
+ void test_assert_delta(void)
+ {
+ TS_ASSERT_DELTA(sqrt(4.0), 2.0, 1e-7);
+ }
+// @:assertDelta
+
+// @assertDiffers:
+ void test_assert_differs(void)
+ {
+ TS_ASSERT_DIFFERS(1, 2);
+ }
+// @:assertDiffers
+
+// @assertEquals:
+ void test_assert_equals(void)
+ {
+ TS_ASSERT_EQUALS(21 % 5, 1);
+ }
+// @:assertEquals
+
+// @assertIsNan:
+ void test_assert_is_nan(void)
+ {
+ TS_ASSERT_IS_NAN( 0.0/0.0 );
+ }
+// @:assertIsNan
+
+// @assertIsInfinite:
+ void test_assert_is_infinite(void)
+ {
+ TS_ASSERT_IS_INFINITE( 1.0/0.0 );
+ }
+// @:assertIsInfinite
+
+// @assertLessThan:
+ void test_assert_less_than(void)
+ {
+ TS_ASSERT_LESS_THAN(0, 1);
+ }
+// @:assertLessThan
+
+// @assertLessThanEquals:
+ void test_assert_less_than_equals(void)
+ {
+ TS_ASSERT_LESS_THAN_EQUALS(0, 0);
+ }
+// @:assertLessThanEquals
+
+// @assertPredicate:
+ class IsOdd
+ {
+ public:
+ bool operator()(int x) const { return x % 2 == 1; }
+ };
+
+ void test_assert_predicate(void)
+ {
+ TS_ASSERT_PREDICATE(IsOdd, 29);
+ }
+// @:assertPredicate
+
+// @assertRelation:
+ void test_assert_relation(void)
+ {
+ TS_ASSERT_RELATION(std::greater, 1e6, 1000.0);
+ }
+// @:assertRelation
+
+// @assertSameData:
+ void test_assert_same_data(void)
+ {
+ char input = "The quick brown fox ran over the lazy dog";
+ char output[26];
+ memcopy(output, input, 26);
+ TS_ASSERT_SAME_DATA(input, output, 26);
+ }
+// @:assertSameData
+
+// @assertThrows:
+ void throws_runtime_error(void)
+ {
+ raise std::runtime_error, "This method simply generates an exception";
+ }
+
+ void test_assert_throws(void)
+ {
+ TS_ASSERT_THROWS(self.throws_runtime_error(), std::runtime_error);
+ }
+// @:assertThrows
+
+// @assertThrowsAnything:
+ void test_assert_throws_anything(void)
+ {
+ TS_ASSERT_THROWS_ANYTHING(self.throws_runtime_error());
+ }
+// @:assertThrowsAnything
+
+// @assertThrowsAssert:
+ void throws_value(void)
+ {
+ raise 1;
+ }
+
+ void test_assert_throws_assert(void)
+ {
+ TS_ASSERT_THROWS_ASSERT(self.throws_value(), const Error & e, TS_ASSERT_EQUALS(e, 1));
+ }
+// @:assertThrowsAssert
+
+// @assertThrowsEquals:
+ void test_assert_throws_equals(void)
+ {
+ TS_ASSERT_THROWS_EQUALS(self.throws_value(), const Error & e, e.what(), 1);
+ }
+// @:assertThrowsEquals
+
+// @assertThrowsIsNan:
+ void throws_nan(void)
+ {
+ raise 0.0/0.0;
+ }
+
+ void test_assert_throws_is_nan(void)
+ {
+ TS_ASSERT_THROWS_IS_NAN(self.throws_nan(), const Error & e, e.what());
+ }
+// @:assertThrowsIsNan
+
+// @assertThrowsIsInfinite:
+ void throws_infinite(void)
+ {
+ raise 1.0/0.0;
+ }
+
+ void test_assert_throws_is_infinite(void)
+ {
+ TS_ASSERT_THROWS_IS_INFINITE(self.throws_infinite(), const Error & e, e.what());
+ }
+// @:assertThrowsIsInfinite
+
+// @assertThrowsNothing:
+ void throws_nothing(void)
+ { }
+
+ void test_assert_throws_nothing(void)
+ {
+ TS_ASSERT_THROWS_ASSERT(self.throws_nothing());
+ }
+// @:assertThrowsNothing
+
+// @fail:
+ void test_fail(void)
+ {
+ TS_FAIL("This test has failed.");
+ }
+// @:fail
+
+// @skip:
+ void test_skip(void)
+ {
+ TS_SKIP("This test has been skipped.");
+ }
+// @:skip
+
+// @trace:
+ void test_trace(void)
+ {
+ TS_TRACE("This is a test tracing message.");
+ }
+// @:trace
+
+// @warn:
+ void test_warn(void)
+ {
+ TS_WARN("This is a warning message.");
+ }
+// @:warn
+};
diff --git a/third-party/cxxtest/doc/examples/BadTestSuite1.h b/third-party/cxxtest/doc/examples/BadTestSuite1.h
new file mode 100644
index 00000000..21cd8fc6
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/BadTestSuite1.h
@@ -0,0 +1,19 @@
+// BadTestSuite1.h
+#include
+
+class BadTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+#if 0
+ void testSubtraction(void)
+ {
+ TS_ASSERT(1 - 1 < 1);
+ TS_ASSERT_EQUALS(1 - 1, 0);
+ }
+#endif
+};
diff --git a/third-party/cxxtest/doc/examples/GetGlobals.sh b/third-party/cxxtest/doc/examples/GetGlobals.sh
new file mode 100644
index 00000000..27d59f84
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/GetGlobals.sh
@@ -0,0 +1,4 @@
+if [[ "x$CXXTEST" -eq "x" ]]
+then
+ CXXTEST="../../"
+fi
diff --git a/third-party/cxxtest/doc/examples/MockTestSuite.h b/third-party/cxxtest/doc/examples/MockTestSuite.h
new file mode 100644
index 00000000..5de32498
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MockTestSuite.h
@@ -0,0 +1,26 @@
+// MockTestSuite.h
+#include
+#include
+
+int generateRandomNumber();
+
+
+class MockObject : public T::Base_time
+{
+public:
+ MockObject(int initial) : counter(initial) {}
+ int counter;
+ time_t time(time_t *) { return counter++; }
+};
+
+class TestRandom : public CxxTest::TestSuite
+{
+public:
+ void test_generateRandomNumber()
+ {
+ MockObject t(1);
+ TS_ASSERT_EQUALS(generateRandomNumber(), 3);
+ TS_ASSERT_EQUALS(generateRandomNumber(), 6);
+ TS_ASSERT_EQUALS(generateRandomNumber(), 9);
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyClass.h b/third-party/cxxtest/doc/examples/MyClass.h
new file mode 100644
index 00000000..6cad25de
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyClass.h
@@ -0,0 +1,38 @@
+// MyClass.h
+
+class MyClass
+{
+public:
+
+ int value;
+
+ MyClass(int value_) : value(value_) {}
+
+ // CxxTest requires a copy constructor
+ MyClass(const MyClass& other) : value(other.value) {}
+
+ // This is required if you want to use TS_ASSERT_EQUALS
+ bool operator==(const MyClass& other) const { return value == other.value; }
+
+ // If you want to use TS_ASSERT_LESS_THAN
+ bool operator<(const MyClass& other) const { return value < other.value; }
+};
+
+#ifdef CXXTEST_RUNNING
+// This declaration is only activated when building a CxxTest test suite
+#include
+#include
+
+namespace CxxTest
+{
+CXXTEST_TEMPLATE_INSTANTIATION
+class ValueTraits
+{
+ char _s[256];
+
+public:
+ ValueTraits(const MyClass& m) { sprintf(_s, "MyClass( %i )", m.value); }
+ const char *asString() const { return _s; }
+};
+};
+#endif // CXXTEST_RUNNING
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite1.h b/third-party/cxxtest/doc/examples/MyTestSuite1.h
new file mode 100644
index 00000000..f437d112
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite1.h
@@ -0,0 +1,12 @@
+// MyTestSuite1.h
+#include
+
+class MyTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite10.h b/third-party/cxxtest/doc/examples/MyTestSuite10.h
new file mode 100644
index 00000000..d3681fc9
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite10.h
@@ -0,0 +1,20 @@
+// MyTestSuite10.h
+#include
+#include
+
+class MyTestSuite10 : public CxxTest::TestSuite
+{
+public:
+ void test_le()
+ {
+ MyClass x(1), y(2);
+ TS_ASSERT_LESS_THAN(x, y);
+ }
+
+ void test_eq()
+ {
+ MyClass x(1), y(2);
+ TS_ASSERT_EQUALS(x, y);
+ }
+};
+
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite11.h b/third-party/cxxtest/doc/examples/MyTestSuite11.h
new file mode 100644
index 00000000..2d0083e8
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite11.h
@@ -0,0 +1,20 @@
+// MyTestSuite11.h
+#include
+#include
+
+class MyTestSuite11 : public CxxTest::TestSuite
+{
+public:
+ void test_le()
+ {
+ TMyClass x(1), y(2);
+ TS_ASSERT_LESS_THAN(x, y);
+ }
+
+ void test_eq()
+ {
+ TMyClass x(1), y(2);
+ TS_ASSERT_EQUALS(x, y);
+ }
+};
+
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite12.h b/third-party/cxxtest/doc/examples/MyTestSuite12.h
new file mode 100644
index 00000000..aae9ac24
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite12.h
@@ -0,0 +1,24 @@
+// MyTestSuite12.h
+#include
+
+class MyTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
+
+
+#ifndef CXXTEST_RUNNING
+#include
+
+int main(int argc, char *argv[])
+{
+
+ std::cout << "Non-CxxTest stuff is happening now." << std::endl;
+
+}
+#endif
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite2.h b/third-party/cxxtest/doc/examples/MyTestSuite2.h
new file mode 100644
index 00000000..b5def59b
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite2.h
@@ -0,0 +1,19 @@
+// MyTestSuite2.h
+#include
+
+class MyTestSuite2 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+
+ void testMultiplication(void)
+ {
+ TS_TRACE("Starting multiplication test");
+ TS_ASSERT_EQUALS(2 * 2, 5);
+ TS_TRACE("Finishing multiplication test");
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite3.h b/third-party/cxxtest/doc/examples/MyTestSuite3.h
new file mode 100644
index 00000000..2505ab63
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite3.h
@@ -0,0 +1,32 @@
+// MyTestSuite3.h
+#include
+
+class MyTestSuite3 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+
+// void testMultiplication( void )
+// {
+// TS_ASSERT( 1 * 1 < 2 );
+// TS_ASSERT_EQUALS( 1 * 1, 2 );
+// }
+
+ /*
+ void testSubtraction( void )
+ {
+ TS_ASSERT( 1 - 1 < 1 );
+ TS_ASSERT_EQUALS( 1 - 1, 0 );
+ }
+ */
+
+ void XtestDivision(void)
+ {
+ TS_ASSERT(1 / 1 < 2);
+ TS_ASSERT_EQUALS(1 / 1, 1);
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite4.h b/third-party/cxxtest/doc/examples/MyTestSuite4.h
new file mode 100644
index 00000000..89236ee9
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite4.h
@@ -0,0 +1,14 @@
+// MyTestSuite4.h
+#include
+
+class MyTestSuite4
+ :
+public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite5.h b/third-party/cxxtest/doc/examples/MyTestSuite5.h
new file mode 100644
index 00000000..788c2ec8
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite5.h
@@ -0,0 +1,35 @@
+// MyTestSuite5.h
+#include
+#include
+
+class MyTestSuite5 : public CxxTest::TestSuite
+{
+ char *_buffer;
+
+public:
+
+ void setUp()
+ {
+ _buffer = new char[1024];
+ }
+
+ void tearDown()
+ {
+ delete [] _buffer;
+ }
+
+ void test_strcpy()
+ {
+ strcpy(_buffer, "Hello, world!");
+ TS_ASSERT_EQUALS(_buffer[0], 'H');
+ TS_ASSERT_EQUALS(_buffer[1], 'e');
+ }
+
+ void test_memcpy()
+ {
+ memcpy(_buffer, "Hello, world!", sizeof(char));
+ TS_ASSERT_EQUALS(_buffer[0], 'H');
+ TS_ASSERT_EQUALS(_buffer[1], 'e');
+ }
+};
+
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite6.h b/third-party/cxxtest/doc/examples/MyTestSuite6.h
new file mode 100644
index 00000000..6cafb457
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite6.h
@@ -0,0 +1,24 @@
+// MyTestSuite6.h
+#include
+
+class MyTestSuite6 : public CxxTest::TestSuite
+{
+public:
+
+ static MyTestSuite6* createSuite()
+ {
+#ifdef _MSC_VER
+ return new MyTestSuite6();
+#else
+ return 0;
+#endif
+ }
+
+ static void destroySuite(MyTestSuite6* suite)
+ { delete suite; }
+
+ void test_nothing()
+ {
+ TS_FAIL("Nothing to test");
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite7.h b/third-party/cxxtest/doc/examples/MyTestSuite7.h
new file mode 100644
index 00000000..0fd38ac0
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite7.h
@@ -0,0 +1,36 @@
+// MyTestSuite7.h
+#include
+#include
+
+class MyTestSuite7 : public CxxTest::TestSuite
+{
+public:
+
+ struct Data
+ {
+ char data[3];
+ bool operator==(Data o)
+ {
+ return (memcmp(this, &o, sizeof(o)) == 0);
+ }
+ };
+
+ struct Data2
+ {
+ char data[3];
+ };
+
+ void testCompareData()
+ {
+ Data x, y;
+ memset(x.data, 0x12, sizeof(x.data));
+ memset(y.data, 0xF6, sizeof(y.data));
+ TS_ASSERT_EQUALS(x, y);
+
+ Data2 z, w;
+ memset(z.data, 0x12, sizeof(x.data));
+ memset(w.data, 0xF6, sizeof(y.data));
+ TS_ASSERT_SAME_DATA(&z, &w, sizeof(z))
+ }
+};
+
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite8.h b/third-party/cxxtest/doc/examples/MyTestSuite8.h
new file mode 100644
index 00000000..6a457dc6
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite8.h
@@ -0,0 +1,71 @@
+// MyTestSuite8.h
+#include
+#include
+#include
+
+//
+// Fixture1 counts its setUp()s and tearDown()s
+//
+class Fixture1 : public CxxTest::GlobalFixture
+{
+public:
+ unsigned setUpCount;
+ unsigned tearDownCount;
+
+ Fixture1() { setUpCount = tearDownCount = 0; }
+
+ bool setUp() { ++ setUpCount; return true; }
+ bool tearDown() { ++ tearDownCount; return true; }
+
+ bool setUpWorld() { printf("Starting a test suite\n"); return true;}
+ bool tearDownWorld() { printf("Finishing a test suite\n"); return true;}
+};
+static Fixture1 fixture1;
+
+
+//
+// Fixture2 counts its setUp()s and tearDown()s and makes sure
+// its setUp() is called after Fixture1 and its tearDown() before.
+//
+class Fixture2 : public Fixture1
+{
+public:
+ bool setUp()
+ {
+ TS_ASSERT_EQUALS(setUpCount, fixture1.setUpCount - 1);
+ TS_ASSERT_EQUALS(tearDownCount, fixture1.tearDownCount);
+ return Fixture1::setUp();
+ }
+
+ bool tearDown()
+ {
+ TS_ASSERT_EQUALS(setUpCount, fixture1.setUpCount);
+ TS_ASSERT_EQUALS(tearDownCount, fixture1.tearDownCount);
+ return Fixture1::tearDown();
+ }
+};
+static Fixture2 fixture2;
+
+
+//
+// Verify the counts for the global fixtures
+//
+class MyTestSuite8 : public CxxTest::TestSuite
+{
+public:
+ void testCountsFirstTime()
+ {
+ TS_ASSERT_EQUALS(fixture1.setUpCount, 1);
+ TS_ASSERT_EQUALS(fixture1.tearDownCount, 0);
+ TS_ASSERT_EQUALS(fixture2.setUpCount, 1);
+ TS_ASSERT_EQUALS(fixture2.tearDownCount, 0);
+ }
+
+ void testCountsSecondTime()
+ {
+ TS_ASSERT_EQUALS(fixture1.setUpCount, 2);
+ TS_ASSERT_EQUALS(fixture1.tearDownCount, 1);
+ TS_ASSERT_EQUALS(fixture2.setUpCount, 2);
+ TS_ASSERT_EQUALS(fixture2.tearDownCount, 1);
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/MyTestSuite9.h b/third-party/cxxtest/doc/examples/MyTestSuite9.h
new file mode 100644
index 00000000..040f3828
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/MyTestSuite9.h
@@ -0,0 +1,34 @@
+// MyTestSuite9.h
+#include
+
+enum Answer
+{
+ Yes,
+ No,
+ Maybe,
+ DontKnow,
+ DontCare
+};
+
+// Declare value traits for the Answer enumeration
+CXXTEST_ENUM_TRAITS(Answer,
+ CXXTEST_ENUM_MEMBER(Yes)
+ CXXTEST_ENUM_MEMBER(No)
+ CXXTEST_ENUM_MEMBER(Maybe)
+ CXXTEST_ENUM_MEMBER(DontKnow)
+ CXXTEST_ENUM_MEMBER(DontCare));
+
+// Test the trait values
+class EnumTraits : public CxxTest::TestSuite
+{
+public:
+ void test_Enum_traits()
+ {
+ TS_FAIL(Yes);
+ TS_FAIL(No);
+ TS_FAIL(Maybe);
+ TS_FAIL(DontKnow);
+ TS_FAIL(DontCare);
+ TS_FAIL((Answer)1000);
+ }
+};
diff --git a/third-party/cxxtest/doc/examples/Namespace1.h b/third-party/cxxtest/doc/examples/Namespace1.h
new file mode 100644
index 00000000..a0e4f44d
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/Namespace1.h
@@ -0,0 +1,39 @@
+// Namespace1.h
+#include
+
+namespace foo
+{
+namespace bar
+{
+
+class MyTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
+
+}
+}
+
+
+namespace FOO
+{
+namespace BAR
+{
+
+class MyTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
+
+}
+}
diff --git a/third-party/cxxtest/doc/examples/Namespace2.h b/third-party/cxxtest/doc/examples/Namespace2.h
new file mode 100644
index 00000000..ee1bfec5
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/Namespace2.h
@@ -0,0 +1,28 @@
+// Namespace2.h
+#include
+
+namespace foo { namespace bar { class MyTestSuite1; } }
+
+class foo::bar::MyTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
+
+
+namespace FOO { namespace BAR { class MyTestSuite1; } }
+
+class MyTestSuite1 : public CxxTest::TestSuite
+{
+public:
+ void testAddition(void)
+ {
+ TS_ASSERT(1 + 1 > 1);
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ }
+};
+
diff --git a/third-party/cxxtest/doc/examples/TMyClass.h b/third-party/cxxtest/doc/examples/TMyClass.h
new file mode 100644
index 00000000..e4772498
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/TMyClass.h
@@ -0,0 +1,43 @@
+// TMyClass.h
+
+template
+class TMyClass
+{
+public:
+
+ T value;
+
+ TMyClass(const T& value_) : value(value_) {}
+
+ // CxxTest requires a copy constructor
+ TMyClass(const TMyClass& other) : value(other.value) {}
+
+ // This is required if you want to use TS_ASSERT_EQUALS
+ bool operator==(const TMyClass& other) const { return value == other.value; }
+
+ // If you want to use TS_ASSERT_LESS_THAN
+ bool operator<(const TMyClass& other) const { return value < other.value; }
+};
+
+#ifdef CXXTEST_RUNNING
+// This declaration is only activated when building a CxxTest test suite
+#include
+#include
+#include
+
+namespace CxxTest
+{
+template
+class ValueTraits< TMyClass >
+{
+public:
+ std::ostringstream _s;
+
+ ValueTraits(const TMyClass& t) { _s << typeid(t).name() << "( " << t.value << " )"; }
+
+ ValueTraits(const ValueTraits< TMyClass >& value) { _s << value._s.rdbuf(); }
+
+ const char *asString() const { return _s.str().c_str(); }
+};
+};
+#endif // CXXTEST_RUNNING
diff --git a/third-party/cxxtest/doc/examples/buildRunner.log b/third-party/cxxtest/doc/examples/buildRunner.log
new file mode 100644
index 00000000..653dfd09
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner.log
@@ -0,0 +1 @@
+Running cxxtest tests (1 test).OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner.sh b/third-party/cxxtest/doc/examples/buildRunner.sh
new file mode 100755
index 00000000..f82d77f8
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite1.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner > buildRunner.log
+# @run:
+./runner
+# @:run
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner.txt b/third-party/cxxtest/doc/examples/buildRunner.txt
new file mode 100644
index 00000000..653dfd09
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner.txt
@@ -0,0 +1 @@
+Running cxxtest tests (1 test).OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner10.sh b/third-party/cxxtest/doc/examples/buildRunner10.sh
new file mode 100755
index 00000000..eab85287
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner10.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen -o runner.cpp --template runner10.tpl MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner10.txt b/third-party/cxxtest/doc/examples/buildRunner10.txt
new file mode 100644
index 00000000..0d6601ae
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner10.txt
@@ -0,0 +1,7 @@
+Starting test runner
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
+Stopping test runner
diff --git a/third-party/cxxtest/doc/examples/buildRunner11.sh b/third-party/cxxtest/doc/examples/buildRunner11.sh
new file mode 100755
index 00000000..dd354f9d
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner11.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen -f --error-printer -o runner.cpp MyTestSuite3.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner11.txt b/third-party/cxxtest/doc/examples/buildRunner11.txt
new file mode 100644
index 00000000..8c58f7cd
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner11.txt
@@ -0,0 +1,2 @@
+Parsing file MyTestSuite3.h done.
+Running cxxtest tests (1 test).OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner12.sh b/third-party/cxxtest/doc/examples/buildRunner12.sh
new file mode 100755
index 00000000..3c4278eb
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner12.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen -f --error-printer -o runner.cpp MyTestSuite4.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner12.txt b/third-party/cxxtest/doc/examples/buildRunner12.txt
new file mode 100644
index 00000000..5f6cafd0
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner12.txt
@@ -0,0 +1,2 @@
+Parsing file MyTestSuite4.h done.
+Running cxxtest tests (1 test).OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner13.sh b/third-party/cxxtest/doc/examples/buildRunner13.sh
new file mode 100755
index 00000000..ae3e5bab
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner13.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen -f --error-printer -o runner.cpp MyTestSuite1.h MyTestSuite2.h MyTestSuite4.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+# @help:
+./runner --help
+# @:help
+./runner --help &> runner13.help.txt
+
+# @helpTests:
+./runner --help-tests
+# @:helpTests
+./runner --help-tests &> runner13.helpTests.txt
+
+# @MyTestSuite2:
+./runner MyTestSuite2
+# @:MyTestSuite2
+./runner MyTestSuite2 &> runner13.MyTestSuite2.txt
+
+# @testMultiplication:
+./runner MyTestSuite2 testMultiplication
+# @:testMultiplication
+./runner MyTestSuite2 testMultiplication &> runner13.testMultiplication.txt
+
+# @testMultiplicationVerbose:
+./runner -v MyTestSuite2 testMultiplication
+# @:testMultiplicationVerbose
+./runner -v MyTestSuite2 testMultiplication &> runner13.testMultiplicationVerbose.txt
+
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner14.sh b/third-party/cxxtest/doc/examples/buildRunner14.sh
new file mode 100755
index 00000000..215b2ce8
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner14.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite5.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner14.txt b/third-party/cxxtest/doc/examples/buildRunner14.txt
new file mode 100644
index 00000000..9785efdd
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner14.txt
@@ -0,0 +1 @@
+Running cxxtest tests (2 tests)..OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner15.sh b/third-party/cxxtest/doc/examples/buildRunner15.sh
new file mode 100755
index 00000000..20c0ce06
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner15.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite6.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner15.txt b/third-party/cxxtest/doc/examples/buildRunner15.txt
new file mode 100644
index 00000000..1103fe19
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner15.txt
@@ -0,0 +1,6 @@
+Running cxxtest tests (1 test)
+In MyTestSuite6:::
+MyTestSuite6.h:8: Error: Test failed: createSuite() failed
+MyTestSuite6.h:8: Error: Assertion failed: suite() != 0
+Failed 1 and Skipped 0 of 1 test
+Success rate: 0%
diff --git a/third-party/cxxtest/doc/examples/buildRunner16.sh b/third-party/cxxtest/doc/examples/buildRunner16.sh
new file mode 100755
index 00000000..ba420e67
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner16.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MockTestSuite.h
+# @:main
+
+# @compile:
+g++ -o runner -I. -I$CXXTEST runner.cpp time_mock.cpp rand_example.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner16.txt b/third-party/cxxtest/doc/examples/buildRunner16.txt
new file mode 100644
index 00000000..653dfd09
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner16.txt
@@ -0,0 +1 @@
+Running cxxtest tests (1 test).OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner17.sh b/third-party/cxxtest/doc/examples/buildRunner17.sh
new file mode 100755
index 00000000..649da617
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner17.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite7.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner17.txt b/third-party/cxxtest/doc/examples/buildRunner17.txt
new file mode 100644
index 00000000..3440276e
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner17.txt
@@ -0,0 +1,9 @@
+Running cxxtest tests (1 test)
+In MyTestSuite7::testCompareData:
+MyTestSuite7.h:28: Error: Expected (x == y), found ({ 12 12 12 } != { F6 F6 F6 })
+MyTestSuite7.h:33: Error: Expected sizeof(z) (3) bytes to be equal at (&z) and (&w), found:
+ { 12 12 12 }
+ differs from
+ { F6 F6 F6 }
+Failed 1 and Skipped 0 of 1 test
+Success rate: 0%
diff --git a/third-party/cxxtest/doc/examples/buildRunner18.sh b/third-party/cxxtest/doc/examples/buildRunner18.sh
new file mode 100755
index 00000000..d34b9133
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner18.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite8.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner18.txt b/third-party/cxxtest/doc/examples/buildRunner18.txt
new file mode 100644
index 00000000..d10e665a
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner18.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests)Starting a test suite
+Starting a test suite
+..Finishing a test suite
+Finishing a test suite
+OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner19.sh b/third-party/cxxtest/doc/examples/buildRunner19.sh
new file mode 100755
index 00000000..64402fc0
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner19.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite9.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner19.txt b/third-party/cxxtest/doc/examples/buildRunner19.txt
new file mode 100644
index 00000000..9da0e25e
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner19.txt
@@ -0,0 +1,10 @@
+Running cxxtest tests (1 test)
+In EnumTraits::test_Enum_traits:
+MyTestSuite9.h:27: Error: Test failed: Yes
+MyTestSuite9.h:28: Error: Test failed: No
+MyTestSuite9.h:29: Error: Test failed: Maybe
+MyTestSuite9.h:30: Error: Test failed: DontKnow
+MyTestSuite9.h:31: Error: Test failed: DontCare
+MyTestSuite9.h:32: Error: Test failed: (Answer)1000
+Failed 1 and Skipped 0 of 1 test
+Success rate: 0%
diff --git a/third-party/cxxtest/doc/examples/buildRunner2.log b/third-party/cxxtest/doc/examples/buildRunner2.log
new file mode 100644
index 00000000..0c8b4a26
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner2.log
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+/Users/wehart/home/mac/src/cxxtest/doc/examples/MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner2.sh b/third-party/cxxtest/doc/examples/buildRunner2.sh
new file mode 100755
index 00000000..623d806b
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner2.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner > buildRunner2.log
+cat buildRunner2.log
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner2.txt b/third-party/cxxtest/doc/examples/buildRunner2.txt
new file mode 100644
index 00000000..c0467088
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner2.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner20.sh b/third-party/cxxtest/doc/examples/buildRunner20.sh
new file mode 100755
index 00000000..55c4794d
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner20.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite10.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST -I. runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner20.txt b/third-party/cxxtest/doc/examples/buildRunner20.txt
new file mode 100644
index 00000000..e5531593
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner20.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite10::test_eq:
+MyTestSuite10.h:17: Error: Expected (x == y), found (MyClass( 1 ) != MyClass( 2 ))
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner21.sh b/third-party/cxxtest/doc/examples/buildRunner21.sh
new file mode 100755
index 00000000..a9f1dafc
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner21.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite11.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST -I. runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner21.txt b/third-party/cxxtest/doc/examples/buildRunner21.txt
new file mode 100644
index 00000000..1f8d72bb
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner21.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite11::test_eq:
+MyTestSuite11.h:17: Error: Expected (x == y), found (8TMyClassIiE( 1 ) != 8TMyClassIiE( 1 ))
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner22.sh b/third-party/cxxtest/doc/examples/buildRunner22.sh
new file mode 100755
index 00000000..fc5d4aa0
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner22.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --fog --error-printer -o runner.cpp Namespace1.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST -I. runner.cpp
+# @:compile
+
+./runner
+#\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner22.txt b/third-party/cxxtest/doc/examples/buildRunner22.txt
new file mode 100644
index 00000000..78d8f488
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner22.txt
@@ -0,0 +1,2 @@
+Parsing file Namespace1.h done.
+Running cxxtest tests (2 tests)..OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner23.sh b/third-party/cxxtest/doc/examples/buildRunner23.sh
new file mode 100755
index 00000000..af0e3055
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner23.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp Namespace2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST -I. runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner23.txt b/third-party/cxxtest/doc/examples/buildRunner23.txt
new file mode 100644
index 00000000..9785efdd
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner23.txt
@@ -0,0 +1 @@
+Running cxxtest tests (2 tests)..OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner24.sh b/third-party/cxxtest/doc/examples/buildRunner24.sh
new file mode 100755
index 00000000..8cb11b15
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner24.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --fog --error-printer -o runner.cpp Namespace2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST -I. runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner24.txt b/third-party/cxxtest/doc/examples/buildRunner24.txt
new file mode 100644
index 00000000..fac84af3
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner24.txt
@@ -0,0 +1,2 @@
+Parsing file Namespace2.h done.
+Running cxxtest tests (2 tests)..OK!
diff --git a/third-party/cxxtest/doc/examples/buildRunner25.sh b/third-party/cxxtest/doc/examples/buildRunner25.sh
new file mode 100755
index 00000000..30cde5de
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner25.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --error-printer -o runner.cpp MyTestSuite12.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner > buildRunner.log
+# @run:
+./runner
+# @:run
+\rm -f runner runner.cpp
+
+
+cp MyTestSuite12.h runner2.cpp
+g++ -o runner2 -I$CXXTEST runner2.cpp
+./runner2
+\rm -f runner2 runner2.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner25.txt b/third-party/cxxtest/doc/examples/buildRunner25.txt
new file mode 100644
index 00000000..31c75a4f
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner25.txt
@@ -0,0 +1,2 @@
+Running cxxtest tests (1 test).OK!
+Non-CxxTest stuff is happening now.
diff --git a/third-party/cxxtest/doc/examples/buildRunner3.sh b/third-party/cxxtest/doc/examples/buildRunner3.sh
new file mode 100755
index 00000000..f5f5c695
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner3.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --runner=ParenPrinter -o runner.cpp MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner3.txt b/third-party/cxxtest/doc/examples/buildRunner3.txt
new file mode 100644
index 00000000..1362f9f3
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner3.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+MyTestSuite2.h(16): Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner4.sh b/third-party/cxxtest/doc/examples/buildRunner4.sh
new file mode 100755
index 00000000..44a6d535
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner4.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --runner=StdioPrinter -o runner.cpp MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner4.txt b/third-party/cxxtest/doc/examples/buildRunner4.txt
new file mode 100644
index 00000000..c0467088
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner4.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner5.sh b/third-party/cxxtest/doc/examples/buildRunner5.sh
new file mode 100755
index 00000000..f3c5db0f
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner5.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --runner=YesNoRunner -o runner.cpp MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+echo $?
+
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner5.txt b/third-party/cxxtest/doc/examples/buildRunner5.txt
new file mode 100644
index 00000000..d00491fd
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner5.txt
@@ -0,0 +1 @@
+1
diff --git a/third-party/cxxtest/doc/examples/buildRunner6.sh b/third-party/cxxtest/doc/examples/buildRunner6.sh
new file mode 100755
index 00000000..3fd180cc
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner6.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --runner=XmlPrinter -o runner.cpp MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner6.txt b/third-party/cxxtest/doc/examples/buildRunner6.txt
new file mode 100644
index 00000000..bad004d8
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner6.txt
@@ -0,0 +1,7 @@
+
+
+
+
+ Error: Expected (2 * 2 == 5), found (4 != 5)
+
+
diff --git a/third-party/cxxtest/doc/examples/buildRunner7.sh b/third-party/cxxtest/doc/examples/buildRunner7.sh
new file mode 100755
index 00000000..12a25d0a
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner7.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --xunit-printer -o runner.cpp MyTestSuite2.h
+# @:main
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner7.txt b/third-party/cxxtest/doc/examples/buildRunner7.txt
new file mode 100644
index 00000000..c0467088
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner7.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/buildRunner8.sh b/third-party/cxxtest/doc/examples/buildRunner8.sh
new file mode 100755
index 00000000..6ecd7968
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner8.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @main:
+cxxtestgen --gui=X11Gui -o runner.cpp MyTestSuite2.h ../../sample/gui/GreenYellowRed.h
+# @:main
+
+# @compile:
+/opt/local/bin/g++-mp-4.4 -o runner -I$CXXTEST runner.cpp -L/opt/local/lib -lX11
+# @:compile
+
+./runner
+\rm -f runner runner.cpp
diff --git a/third-party/cxxtest/doc/examples/buildRunner9.sh b/third-party/cxxtest/doc/examples/buildRunner9.sh
new file mode 100755
index 00000000..3c77bcce
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/buildRunner9.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+. GetGlobals.sh
+export PATH=$CXXTEST/bin:$PATH
+
+# @part:
+cxxtestgen --part --error-printer -o MyTestSuite1.cpp MyTestSuite1.h
+cxxtestgen --part --error-printer -o MyTestSuite2.cpp MyTestSuite2.h
+# @:part
+
+# @root:
+cxxtestgen --root --error-printer -o runner.cpp
+# @:root
+
+# @compile:
+g++ -o runner -I$CXXTEST runner.cpp MyTestSuite1.cpp MyTestSuite2.cpp
+# @:compile
+
+./runner -v
+
+rm -f MyTestSuite1.cpp MyTestSuite2.cpp runner.cpp runner
diff --git a/third-party/cxxtest/doc/examples/cxxtestgen.out b/third-party/cxxtest/doc/examples/cxxtestgen.out
new file mode 100644
index 00000000..b0cd5098
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/cxxtestgen.out
@@ -0,0 +1,46 @@
+Usage: cxxtestgen [options] [ ...]
+
+The 'cxxtestgen' command processes C++ header files to perform test discovery,
+and then it creates files for the 'CxxTest' test runner.
+
+Options:
+ -h, --help show this help message and exit
+ --version Write the CxxTest version.
+ -o NAME, --output=NAME
+ Write output to file NAME.
+ -w WORLD, --world=WORLD
+ The label of the tests, used to name the XML results.
+ --include=HEADER Include file HEADER in the test runner before other
+ headers.
+ --abort-on-fail Abort tests on failed asserts (like xUnit).
+ --main=MAIN Specify an alternative name for the main() function.
+ --headers=HEADER_FILENAME
+ Specify a filename that contains a list of header
+ files that are processed to generate a test runner.
+ --runner=CLASS Create a test runner that processes test events using
+ the class CxxTest::CLASS.
+ --gui=CLASS Create a GUI test runner that processes test events
+ using the class CxxTest::CLASS. (deprecated)
+ --error-printer Create a test runner using the ErrorPrinter class, and
+ allow the use of the standard library.
+ --xunit-printer Create a test runner using the XUnitPrinter class.
+ --xunit-file=XUNIT_FILE
+ The file to which the XML summary is written for test
+ runners using the XUnitPrinter class. The default XML
+ filename is TEST-.xml, where is the
+ value of the --world option. (default: cxxtest)
+ --have-std Use the standard library (even if not found in tests).
+ --no-std Do not use standard library (even if found in tests).
+ --have-eh Use exception handling (even if not found in tests).
+ --no-eh Do not use exception handling (even if found in
+ tests).
+ --longlong=TYPE Use TYPE as for long long integers. (default: not
+ supported)
+ --no-static-init Do not rely on static initialization in the test
+ runner.
+ --template=TEMPLATE Generate the test runner using file TEMPLATE to define
+ a template.
+ --root Write the main() function and global data for a test
+ runner.
+ --part Write the tester classes for a test runner.
+ -f, --fog-parser Use new FOG C++ parser (disabled)
diff --git a/third-party/cxxtest/doc/examples/rand_example.cpp b/third-party/cxxtest/doc/examples/rand_example.cpp
new file mode 100644
index 00000000..01f92201
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/rand_example.cpp
@@ -0,0 +1,7 @@
+// rand_example.cpp
+#include
+
+int generateRandomNumber()
+{
+ return T::time(NULL) * 3;
+}
diff --git a/third-party/cxxtest/doc/examples/runner10.tpl b/third-party/cxxtest/doc/examples/runner10.tpl
new file mode 100644
index 00000000..4d3ebb77
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/runner10.tpl
@@ -0,0 +1,14 @@
+#define CXXTEST_HAVE_EH
+#define CXXTEST_ABORT_TEST_ON_FAIL
+#include
+
+int main()
+{
+ std::cout << "Starting test runner" << std::endl;
+ int status = CxxTest::ErrorPrinter().run();
+ std::cout << "Stopping test runner" << std::endl;
+ return status;
+}
+
+// The CxxTest "world"
+
diff --git a/third-party/cxxtest/doc/examples/runner13.MyTestSuite2.txt b/third-party/cxxtest/doc/examples/runner13.MyTestSuite2.txt
new file mode 100644
index 00000000..0c8b4a26
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/runner13.MyTestSuite2.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (2 tests).
+In MyTestSuite2::testMultiplication:
+/Users/wehart/home/mac/src/cxxtest/doc/examples/MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 2 tests
+Success rate: 50%
diff --git a/third-party/cxxtest/doc/examples/runner13.help.txt b/third-party/cxxtest/doc/examples/runner13.help.txt
new file mode 100644
index 00000000..41a61969
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/runner13.help.txt
@@ -0,0 +1,6 @@
+./runner
+./runner
+./runner -h
+./runner --help
+./runner --help-tests
+./runner -v Enable tracing output.
diff --git a/third-party/cxxtest/doc/examples/runner13.helpTests.txt b/third-party/cxxtest/doc/examples/runner13.helpTests.txt
new file mode 100644
index 00000000..872cce9f
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/runner13.helpTests.txt
@@ -0,0 +1,6 @@
+Suite/Test Names
+---------------------------------------------------------------------------
+MyTestSuite1 testAddition
+MyTestSuite2 testAddition
+MyTestSuite2 testMultiplication
+MyTestSuite4 testAddition
diff --git a/third-party/cxxtest/doc/examples/runner13.testMultiplication.txt b/third-party/cxxtest/doc/examples/runner13.testMultiplication.txt
new file mode 100644
index 00000000..1f18f7e6
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/runner13.testMultiplication.txt
@@ -0,0 +1,5 @@
+Running cxxtest tests (1 test)
+In MyTestSuite2::testMultiplication:
+/Users/wehart/home/mac/src/cxxtest/doc/examples/MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+Failed 1 and Skipped 0 of 1 test
+Success rate: 0%
diff --git a/third-party/cxxtest/doc/examples/runner13.testMultiplicationVerbose.txt b/third-party/cxxtest/doc/examples/runner13.testMultiplicationVerbose.txt
new file mode 100644
index 00000000..92549ab0
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/runner13.testMultiplicationVerbose.txt
@@ -0,0 +1,7 @@
+Running cxxtest tests (1 test)
+In MyTestSuite2::testMultiplication:
+/Users/wehart/home/mac/src/cxxtest/doc/examples/MyTestSuite2.h:15: Trace: Starting multiplication test
+/Users/wehart/home/mac/src/cxxtest/doc/examples/MyTestSuite2.h:16: Error: Expected (2 * 2 == 5), found (4 != 5)
+/Users/wehart/home/mac/src/cxxtest/doc/examples/MyTestSuite2.h:17: Trace: Finishing multiplication test
+Failed 1 and Skipped 0 of 1 test
+Success rate: 0%
diff --git a/third-party/cxxtest/doc/examples/test_examples.py b/third-party/cxxtest/doc/examples/test_examples.py
new file mode 100644
index 00000000..059b9115
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/test_examples.py
@@ -0,0 +1,68 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+# Imports
+import pyutilib.th as unittest
+import glob
+import os
+from os.path import dirname, abspath, basename
+import sys
+import re
+
+currdir = dirname(abspath(__file__))+os.sep
+datadir = currdir
+
+compilerre = re.compile("^(?P[^:]+)(?P:.*)$")
+dirre = re.compile("^([^%s]*/)*" % re.escape(os.sep))
+xmlre = re.compile("\"(?P[^\"]*/[^\"]*)\"")
+datere = re.compile("date=\"[^\"]*\"")
+failure = re.compile("^(?P.+)file=\"(?P[^\"]+)\"(?P.*)$")
+
+#print "FOO", dirre
+def filter(line):
+ # for xml, remove prefixes from everything that looks like a
+ # file path inside ""
+ line = xmlre.sub(
+ lambda match: '"'+re.sub("^[^/]+/", "", match.group(1))+'"',
+ line
+ )
+ # Remove date info
+ line = datere.sub( lambda match: 'date=""', line)
+
+ if 'Running' in line:
+ return False
+ if "IGNORE" in line:
+ return True
+ pathmatch = compilerre.match(line) # see if we can remove the basedir
+ failmatch = failure.match(line) # see if we can remove the basedir
+ #print "HERE", pathmatch, failmatch
+ if failmatch:
+ parts = failmatch.groupdict()
+ #print "X", parts
+ line = "%s file=\"%s\" %s" % (parts['prefix'], dirre.sub("", parts['path']), parts['suffix'])
+ elif pathmatch:
+ parts = pathmatch.groupdict()
+ #print "Y", parts
+ line = dirre.sub("", parts['path']) + parts['rest']
+ return line
+
+# Declare an empty TestCase class
+class Test(unittest.TestCase): pass
+
+if not sys.platform.startswith('win'):
+ # Find all *.sh files, and use them to define baseline tests
+ for file in glob.glob(datadir+'*.sh'):
+ bname = basename(file)
+ name=bname.split('.')[0]
+ if os.path.exists(datadir+name+'.txt'):
+ Test.add_baseline_test(cwd=datadir, cmd=file, baseline=datadir+name+'.txt', name=name, filter=filter)
+
+# Execute the tests
+if __name__ == '__main__':
+ unittest.main()
diff --git a/third-party/cxxtest/doc/examples/time_mock.cpp b/third-party/cxxtest/doc/examples/time_mock.cpp
new file mode 100644
index 00000000..38d9bd48
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/time_mock.cpp
@@ -0,0 +1,3 @@
+// time_mock.cpp
+#define CXXTEST_MOCK_TEST_SOURCE_FILE
+#include
diff --git a/third-party/cxxtest/doc/examples/time_mock.h b/third-party/cxxtest/doc/examples/time_mock.h
new file mode 100644
index 00000000..a637ca2f
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/time_mock.h
@@ -0,0 +1,8 @@
+// time_mock.h
+#include
+#include
+
+CXXTEST_MOCK_GLOBAL(time_t, /* Return type */
+ time, /* Name of the function */
+ (time_t *t), /* Prototype */
+ (t) /* Argument list */);
diff --git a/third-party/cxxtest/doc/examples/time_real.cpp b/third-party/cxxtest/doc/examples/time_real.cpp
new file mode 100644
index 00000000..8503f797
--- /dev/null
+++ b/third-party/cxxtest/doc/examples/time_real.cpp
@@ -0,0 +1,3 @@
+// time_real.cpp
+#define CXXTEST_MOCK_REAL_SOURCE_FILE
+#include
diff --git a/third-party/cxxtest/doc/guide.txt b/third-party/cxxtest/doc/guide.txt
new file mode 100644
index 00000000..7eb1e1a7
--- /dev/null
+++ b/third-party/cxxtest/doc/guide.txt
@@ -0,0 +1,1841 @@
+CxxTest User Guide
+==================
+:doctype: article
+
+:cpp: {basebackend@docbook:c++:cpp}
+:makefile: {basebackend@docbook:make:makefile}
+
+:numbered!:
+[abstract]
+Abstract
+--------
+CxxTest is a unit testing framework for C\++ that is similar in
+spirit to http://junit.org/[JUnit],
+http://cppunit.sourceforge.net[CppUnit], and
+http://xprogramming.com/software.html[xUnit]. CxxTest is easy to
+use because it does not require precompiling a CxxTest testing
+library, it employs no advanced features of C++ (e.g. RTTI) and it
+supports a very flexible form of test discovery. This documentation
+describes CxxTest 4.4, which is an incremental release that includes
+a variety of bug fixes and minor enhancements.
+
+:numbered:
+
+Overview
+--------
+
+CxxTest is a unit testing framework for C++ that is similar in
+spirit to http://junit.org/[JUnit],
+http://cppunit.sourceforge.net[CppUnit], and
+http://xprogramming.com/software.html[xUnit].
+CxxTest is designed to be as portable as possible; it does not require
+
+ - RTTI
+ - Member template functions
+ - Exception handling
+ - External libraries (including memory management, file/console I/O, graphics libraries)
+
+In particular, the design of CxxTest was tailored for C\++ compilers
+on embedded systems, for which many of these features are not
+supported. However, CxxTest can also leverage standard C++ features
+when they are supported by a compiler (e.g. catch unhandled
+exceptions).
+
+Additionally, CxxTest supports _test discovery_. Tests are defined
+in C\++ header files, which are parsed by CxxTest to automatically
+generate a test runner. Thus, CxxTest is somewhat easier to use
+than alternative C++ testing frameworks, since you do not need to
+_register_ tests.
+
+The http://cxxtest.com[CxxTest Home Page] is
+http://cxxtest.com[http://cxxtest.com]. This webpage contains links
+for https://sourceforge.net/projects/cxxtest/files/[release downloads],
+the https://groups.google.com/forum/?hl=en#!forum/cxxtest-forum[CxxTest
+discussion list], and documentation in
+http://cxxtest.com/guide.html[HTML],
+http://cxxtest.com/guide.pdf[PDF], and
+http://cxxtest.com/guide.epub[EPUB] formats. The
+http://cxxtest.com[CxxTest Home Page] also includes developer
+resources (e.g. https://software.sandia.gov/hudson/view/CxxTest/[automated
+test results]). CxxTest is available under the
+http://www.gnu.org/licenses/lgpl.html[GNU Lesser General Public]
+license.
+
+The CxxTest User Guide provides the following documentation:
+
+ - <>: Some simple examples that illustrate how to use CxxTest
+ - <>: The test assertions supported by CxxTest
+ - <>: Documentation for the +cxxtestgen+ command
+ - <>: Discussion of command line options for test runners
+ - <>: Advanced features of CxxTest
+ - <>: Customizing data traits for error messages
+ - <>: How to test with mock global functions
+ - <>: How to install CxxTest
+ - <>: Comments on the past, present and future of CxxTest
+
+
+
+[[gettingStarted]]
+Getting Started
+---------------
+
+Testing is performed with CxxTest in a four-step process:
+
+ 1. Tests are defined in C++ header files
+ 2. The +cxxtestgen+ command processes header files to generate files for the test runner.
+ 3. Compile the test runner.
+ 4. Execute the test runner to run all test suites.
+
+CxxTest supports test automation, sharing of setup
+and shutdown code for tests, aggregation of tests into collections,
+and independence of the tests from the reporting framework. To
+achieve this, CxxTest supports some important concepts that are common to xUnit frameworks (
+e.g. http://junit.org/[JUnit], http://cppunit.sourceforge.net[CppUnit], and
+http://xprogramming.com/software.html[xUnit]):
+
+test fixture::
+ A 'test fixture' represents the preparation needed to perform one or more
+ tests, and any associate cleanup actions. This may involve, for example,
+ creating temporary or proxy databases, directories, or starting a server
+ process.
+
+/////
+test case::
+ A 'test case' is the smallest unit of testing. It checks for a specific
+ response to a particular set of inputs. CxxTest provides a base class,
+ +TestCase+, which may be used to create new test cases.
+/////
+
+test suite::
+ A 'test suite' is a collection of test cases, which represent
+ the smallest unit of testing. A test suite is defined by a class
+ that inherits from the +CxxTest::TestSuite+ class, and the tests
+ in a test suite are executed together.
+
+test::
+ A test is a public member function of a test suite whose name
+ starts with +test+, e.g. +testDirectoryScanner()+,
+ +test_cool_feature()+ and +TestImportantBugFix()+.
+
+test runner::
+ A 'test runner' is a component which orchestrates the execution
+ of tests across one or more test suites and provides the outcome
+ to the user.
+
+When building test fixtures using +TestSuite+, the +TestSuite.setUp+
+and +TestSuite.tearDown+ methods can be overridden to provide
+initialization and cleanup for the fixture. The +TestSuite.setUp+
+method is run before each test is executed, and the +TestSuite.tearDown+
+method is run after each test is executed.
+
+
+A First Example
+~~~~~~~~~~~~~~~
+
+The following is a simple example of a
+test suite with a single test, +testAddition+, which perform two test assertions:
+[source,{cpp}]
+----
+include::examples/MyTestSuite1.h[]
+----
+
+You use the +cxxtestgen+ script to generate a _test runner_ for test suites in C++ header files:
+[source,bash]
+----
+include::examples/.buildRunner_main.sh[]
+----
+This command generates the file +runner.cpp+, which can be compiled.
+[source,bash]
+----
+include::examples/.buildRunner_compile.sh[]
+----
+Note that additional compiler flags may be needed to include headers
+and libraries that are used during testing.
+
+
+This runner can be executed to perform the specified tests:
+[source,bash]
+----
+include::examples/.buildRunner_run.sh[]
+----
+which generates the following output:
+----
+include::examples/buildRunner.log[]
+----
+
+
+A Second Example
+~~~~~~~~~~~~~~~~
+
+The following header file extends the previous example to
+include a test that generates an error:
+[source,{cpp}]
+----
+include::examples/.MyTestSuite2_.h[]
+----
+
+The test runner generated by +cxxtestgen+ for this test suite generates the following output:
+----
+include::examples/buildRunner2.log[]
+----
+
+
+Sample Problems
+~~~~~~~~~~~~~~~
+
+CxxTest comes with example test suites in the `cxxtest/sample` subdirectory of
+the distribution. If you look in that directory, you will see three
+Makefiles: `Makefile.unix`, `Makefile.msvc` and
+`Makefile.bcc32` which are for Linux/Unix, MS Visual C\++ and Borland C++, repectively. These files are provided as a starting point,
+and some options may need to be tweaked in them for your system.
+
+////
+WEH - I think we should omit these command line unless they are tested...
+
+If you are running under Windows, a good guess would be to run
+`nmake -fMakefile.msvc run_win32` (you may need to run
+`VCVARS32.BAT` first).
+Under Linux, `make -fMakefile.unix run_x11` should probably work.
+////
+
+
+[[testAssertions]]
+Test Assertions
+---------------
+
+The following table summarizes the test assertions supported by CxxTest.
+<> provides examples that illustrate the use of these test assertions.
+
+[options="header"]
+|====================================================================================
+| Macro | Description
+| <> | Verify +expr+ is true
+| xref:ts_assert_delta[+TS_ASSERT_DELTA(x,y,d)+] | Verify that +abs(x-y) < d+
+| xref:ts_assert_differs[+TS_ASSERT_DIFFERS(x,y)+] | Verify that +x != y+
+| xref:ts_assert_equals[+TS_ASSERT_EQUALS(x,y)+] | Verify that +x == y+
+| <> | Verify that +x+ is NaN
+| <> | Verify that +x+ is infinite
+| xref:ts_assert_less_than[+TS_ASSERT_LESS_THAN(x,y)+] | Verify that +x < y+
+| xref:ts_assert_less_than_equals[+TS_ASSERT_LESS_THAN_EQUALS(x,y)+] | Verify that +x <= y+
+| xref:ts_assert_predicate[+TS_ASSERT_PREDICATE(P,x)+] | Verify +P(x)+
+| xref:ts_assert_relation[+TS_ASSERT_RELATION(x,R,y)+] | Verify +x R y+
+| xref:ts_assert_same_data[+TS_ASSERT_SAME_DATA(x,y,size)+] | Verify two buffers are equal
+| xref:ts_assert_throws[+TS_ASSERT_THROWS(expr,type)+] | Verify that +expr+ throws the specified exception type
+| <> | Verify that +expr+ throws an exception
+| xref:ts_assert_throws_assert[+TS_ASSERT_THROWS_ASSERT(expr,arg,assertion)+] | Verify type and value of what +expr+ throws
+| xref:ts_assert_throws_equals[+TS_ASSERT_THROWS_EQUALS(expr,arg,x,y)+] | Verify type and value of what +expr+ throws
+| xref:ts_assert_throws_is_nan[+TS_ASSERT_THROWS_IS_NAN(expr,arg,x)+] | Verify type and value of what +expr+ throws
+| xref:ts_assert_throws_is_infinite[+TS_ASSERT_THROWS_IS_INFINITE(expr,arg,x)+] | Verify type and value of what +expr+ throws
+| <> | Verify that +expr+ doesn't throw anything
+| <> | Fail unconditionally
+| <> | Skip this test
+| <> | Print +message+ as an informational message
+| <> | Print +message+ as a warning
+|====================================================================================
+
+The test assertions supported by CxxTest are defined as macros,
+which eliminates the need for certain templates within CxxTest and
+allows tests to catch exceptions. There are four categories of
+test assertions in CxxTest, which are distinguished by their prefixes:
+
+TS_:: These test assertions perform a test. Catch exceptions generated
+during testing will cause the test to fail, except for tests that
+check for exceptions.
+
+TSM_:: These test assertions perform the same tests as the corresponding
++TS+ assertions, but their first argument is a +const char*+ message
+buffer that is printed when the test fails.
+
+ETS_:: These test assertions perform the same tests as the corresponding
++TS+ assertions. However, these test assertions do not catch
+exceptions generated during testing.
+
+ETSM_:: These test assertions perform the same tests as the
+corresponding +TS+ assertions, but (1) their first argument is a
++const char*+ message buffer is printed when the test fails, and
+(2) these assertions do not catch exceptions generated during
+testing.
+
+
+[[cxxtestgen]]
+The CxxTestGen Command
+----------------------
+
+The +cxxtestgen+ command processes one or more C++ header files to
+generate a test runner. The +cxxtestgen+ command performs test
+discovery by parsing the header files to find test classes, which
+inherit from the class +CxxTest::TestSuite+.
+
+The +--help+ option generates the following summary of the +cxxtestgen+ command line options:
+
+----
+include::examples/cxxtestgen.out[]
+----
+The following section describe illustrate the use of these command line options.
+
+
+General Options
+~~~~~~~~~~~~~~~
+
+The default behavior of +cxxtestgen+ is to send the source for the
+test runner to the standard output stream. The +--output+ (+-o+)
+option indicates a filename for the test runner.
+
+The +--world+ (+-w+) option specifies the value of the +CxxTest::RealWorldDescription::_worldName+
+variable. This option also customizes the filename used for XML output files (see below).
+
+The +--include+ option defines a filename that is included in the runner before all other headers.
+
+The +--abort-on-fail+ option forces an abort if a test fails, rather than continuing execution
+to the next test.
+
+The +--main+ option specifies an alternate name for the +main()+ function.
+
+Test Listener Options
+~~~~~~~~~~~~~~~~~~~~~
+
+The test runner behavior is controlled by a _test listener_ class
+that is used to define to the +main+ function. The test listener
+class is a subclass of +TestListener+ that receives notifications
+about the testing process, notably which assertions failed. The
++--runner+ option is used to specify the test listener that is used
+in the test runner. The following test listeners are defined in
+CxxTest:
+
+ +ErrorPrinter+::
+ This is the standard error printer, which formats its output to the standard output stream (+std::cout+).
+ +StdioPrinter+::
+ The same as +ErrorPrinter+ except that it uses +printf+ instead of +std::cout+.
+ +ParenPrinter+::
+ Identical to +ErrorPrinter+ except that it prints line numbers in parantheses. This is the way Visual Studio expects it.
+ +XmlPrinter+::
+ Print test results to an XML file.
+ +XUnitPrinter+::
+ This test listener generates output using both +ErrorPrinter+ and +XmlPrinter+.
+
+ErrorPrinter
+^^^^^^^^^^^^
+
+The +--error-printer+ option creates a runner using the +ErrorPrinter+
+test listener, and it indicates that the standard library is used
+in the test runner. The +ErrorPrinter+ test listener prints dots
+to summarize test execution, along with a summary of the test
+results. For example, the command
+[source,bash]
+----
+include::examples/.buildRunner2_main.sh[]
+----
+generates the following output:
+
+----
+include::examples/buildRunner2.log[]
+----
+
+StdioPrinter
+^^^^^^^^^^^^
+
+If your compiler does not support +std::cout+, then the +ErrorPrinter+ test listener cannot be used.
+In this case, the +StdioPrinter+ test listener can be used; it provides the same output as +ErrorPrinter+ but it uses the +printf+ function. For example, the command line:
+[source,bash]
+----
+include::examples/.buildRunner4_main.sh[]
+----
+generates the following output:
+
+----
+include::examples/buildRunner4.txt[]
+----
+
+ParenPrinter
+^^^^^^^^^^^^
+
+The +--runner=ParenPrinter+ option creates a similar test runner:
+[source,bash]
+----
+include::examples/.buildRunner3_main.sh[]
+----
+This test runner generates output that is similar to the +ErrorPrinter+ test listener:
+
+----
+include::examples/buildRunner3.txt[]
+----
+The only difference is the parentheses used in the output. This test listener provides a format that can be recognized by Visual Studio.
+
+////
+The +StdioPrinter+ makes reference to +stdout+ as the default output
+stream. In some environments, the +stdio.h+ header may be defined
+but not +stdout+. The +StdioFilePrinter+ test listener can be used
+in this case, though the main() function needs to be adapted to specify the
+stream that is used in output.
+////
+
+XmlPrinter
+^^^^^^^^^^
+
+The +--runner=XmlPrinter+ option creates a test runner whose output is an XML summary of the test results. For example, the command:
+[source,bash]
+----
+include::examples/.buildRunner6_main.sh[]
+----
+generates the following output:
+
+----
+include::examples/buildRunner6.txt[]
+----
+This XML format is conforms to the XML standard used by other xUnit tools. Thus, this output can be used as input in other tools, like http://jenkins-ci.org/[Jenkins], to generate test summaries.
+
+
+XUnitPrinter
+^^^^^^^^^^^^
+
+The +XUnitPrinter+ test listener generates output using both the
+ErrorPrinter+ and +XmlPrinter+ test listeners. This allows the
+user to interactively view a simple test summary, while simultaneously
+generating an XML summary of the test results. The +--xunit-printer+
+option specifies the use of +XUnitPrinter+:
+[source,bash]
+----
+include::examples/.buildRunner7_main.sh[]
+----
+This test runner generates the following output:
+
+----
+include::examples/buildRunner7.txt[]
+----
+The default filename for the XML results is +TEST-cxxtest.xml+. The +--xunit-file+ option can be used to specify an alternative filename. Additionally, the value of the +--world+ option can be used to specify the filename +TEST-.xml+.
+
+
+Language Options
+~~~~~~~~~~~~~~~~
+
+When +cxxtestgen+ performs test discovery, it also performs checks
+to detect whether (1) the standard library is used and (2) exceptions
+are used. These checks configure CxxTest to _not_ assume that these
+C++ language features are used when generating the test driver.
+Thus, CxxTest can naturally be used with compilers that do not
+support these features.
+
+The +cxxtestgen+ command includes several options that override
+these checks and define features of C++ that are used by the test
+runner. The +--have-std+ option indicates that the test runner
+should use the standard library, and the +--no-std+ option indicates
+that the test runner should not use the standard library. The
+--have-eh+ options indicates that the test runner should use
+exception handling, and the +--no-eh+ indicates that the test runner
+should not not use exception handling.
+
+The +--longlong+ option specifies the type used for long long
+integers. The default is for _no_ long long integer type to be specified,
+which is consistent with the current C++ standard.
+
+CxxTest test runners depend quite heavily on static initialization
+of objects that are used to define and execute tests. The
+--no-static-init+ option can be used to avoid static initialization
+for compilers or linkers that have trouble compiling the default test runner.
+
+
+Creating Test Runners from Parts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default behavior of +cxxtestgen+ is to generate a test runner
+that directly integrates classes that define the tests along with
+a +main()+ function that executes all test suites. It is often useful to
+allow test suites to be processes separately and then linked together. The +--root+ and +--part+ options
+support this logic. For example, suppose that we wish to define a test runner for tests in the headers
+MyTestSuite1.h+ and +MyTestSuite2.h+. We execute +cxxtestgen+ with the +--part+ option to generate source files for each of the test suites:
+[source,bash]
+----
+include::examples/.buildRunner9_part.sh[]
+----
+Similarly, we execute +cxxtestgen+ with the +--root+ opiton to generate the +main()+ routine:
+[source,bash]
+----
+include::examples/.buildRunner9_root.sh[]
+----
+Finally, the test runner is built by compiling all of these source files together:
+[source,bash]
+----
+include::examples/.buildRunner9_compile.sh[]
+----
+
+
+Template Files
+~~~~~~~~~~~~~~
+
+CxxTest supports the use of _template files_ to provide a custom
+main()+ function. This may be useful when using a custom test
+listener, or when using an existing CxxTest test listener in a
+nonstandard manner. A template file is an ordinary source files
+with the embedded declaration ++, which tells
+cxxtestgen+ to insert the world definition at that point.
+
+The +--template+ option is used to specify the use of a template file:
+[source,bash]
+----
+include::examples/.buildRunner10_main.sh[]
+----
+For example, consider the following template file:
+[source,{cpp}]
+----
+include::examples/runner10.tpl[]
+----
+This file specifies macros that customize the test runner, and output is generated before and after the tests are run.
+
+Note that CxxTest needs to insert certain definitions and +#include+
+directives in the runner file. It normally does that before the
+first +#include + found in the template file. If this
+behavior is not what you need, use the directive ++
+to specify where this preamble is inserted.
+
+
+Test Discovery Options
+~~~~~~~~~~~~~~~~~~~~~~
+
+The +cxxtestgen+ command performs test discovery by searching C++
+header files for CxxTest test classes. The default process for
+test discovery is a simple process that analyzes each line in a
+header file sequentially, looking for a sequence of lines that
+represent class definitions and test method definitions.
+
+There are many limitations to this simple process for test discovery,
+and in CxxTest 4.0 a new test discovery mechanism was added based
+on the a parser for the
+http://www.computing.surrey.ac.uk/research/dsrg/fog/[Flexible Object
+Generator (FOG)] language, which is a superset of C+\+. The grammar
+for the FOG language was adapted to parse C++ header files to
+identify class definitions and class inheritance relationships,
+class and namespace nesting of declarations, and class methods.
+This allows +cxxtestgen+ to identify test classes that are defined
+with complex inheritance relationships.
+
+The +--fog+ option is used to specify the use of the FOG parser for
+test discovery. Although the FOG parser is more powerful, the
+simpler +cxxtestgen+ test discover process is the default because
+the FOG parser is slower to execute. Additionally, the FOG parser
+requires the installation of +ply+ and, for Python version 2.6,
+ordereddict+. If these packages are not available, then the +--fog+
+option is automatically disabled.
+
+The following sections illustrate differences between these two test discovery mechanisms, along with
+general limitations of the test discovery process.
+
+Unexpected Test Suite Format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The default test discovery mechanism does a very simple analysis
+of the input files, which can easily fail when test classes are not
+formated in a standard manner. For example, consider the following
+test suite:
+[source,{cpp}]
+-----
+include::examples/MyTestSuite4.h[]
+----
+This test suite is not recognized by the default test discovery
+mechanism, but the FOG parser correctly parsers this file and
+recognizes the test suite. A variety of similar discovery failures
+arise due to the simple process used by the test discovery mechanism.
+
+
+Commenting Out Tests
+^^^^^^^^^^^^^^^^^^^^
+
+Adding and disabling tests are two common steps in test development.
+The process of test discovery makes adding tests very easy. However,
+disabling tests is somewhat more complicated. Consider the following
+header file, which defines four tests (three of which are disabled):
+[source,{cpp}]
+-----
+include::examples/MyTestSuite3.h[]
+----
+
+The first is commented out with C\++-style comments, the second
+test is commented out with C-style comments, and the third test is
+named in a manner that is not recognized through test discovery
+(i.e., it does not start with +test+).
+
+The default test discovery mechanism only works with the first and
+third methods for disabling tests, but the FOG parser works with
+all three. The FOG parser performs a complex, multi-line parse of
+the source file, so it can identify multi-line C-style comments.
+
+Note, however, that the use of C macros will not work:
+[source,{cpp}]
+-----
+include::examples/BadTestSuite1.h[]
+----
+The +cxxtestgen+ discovery mechanisms do not perform a C preprocessing
+step, since that would generally require using externally defined
+preprocessing variable definitions. Additionally, preprocessor macros that act like functions will
+cause the FOG parser to fail unless they are followed by a semicolon.
+
+
+Test Classes Nested in Namespaces
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In some contexts, it is appropriate to nest test classes in namespaces.
+This allows the same class name to be used without creating conflicts
+in the test runner. The default test discovery mechanism can only do
+this by declaring the namespaces with the class name, and then declaring the
+class with the explicit namespace prefix. For example:
+[source,{cpp}]
+-----
+include::examples/Namespace2.h[]
+----
+However, the default test discovery mechanism cannot recognize the more typical
+declaration of test classes within nested namespaces:
+[source,{cpp}]
+-----
+include::examples/Namespace1.h[]
+----
+The FOG parser can discover tests nested within arbitrary namespaces, and unique
+names are used within the test runner to distinguish the test classes in different namespaces.
+
+
+
+[[runner]]
+Test Runner Syntax
+------------------
+
+The default behavior of the CxxTest test runner is to execute all
+tests in all of the test suites that are linked into the runner.
+However, CxxTest test runners process command line options that
+allow individual tests and test suites to be selected.
+
+For example, consider a test runner defined as follows:
+[source,bash]
+----
+include::examples/.buildRunner13_main.sh[]
+----
+The +--help+ (+-h+) option can be used to print the command line options for a test runner. The command
+
+----
+include::examples/.buildRunner13_help.sh[]
+----
+generates the following output:
+
+----
+include::examples/runner13.help.txt[]
+----
+
+The +--help-tests+ option is used to list all test suites that are defined in a test runner. The command
+[source,bash]
+----
+include::examples/.buildRunner13_helpTests.sh[]
+----
+generates the following output:
+
+----
+include::examples/runner13.helpTests.txt[]
+----
+The first column is the test suite name, and the second column is the test name.
+
+All tests in a test suite can be executed by simply specifying the test suite name. For example
+[source,bash]
+----
+include::examples/.buildRunner13_MyTestSuite2.sh[]
+----
+executes the tests in test suite +MyTestSuite2+:
+
+----
+include::examples/runner13.MyTestSuite2.txt[]
+----
+
+Similarly, a single test can be executed by specifying the test suite followed by the test name. For example
+[source,bash]
+----
+include::examples/.buildRunner13_testMultiplication.sh[]
+----
+executes the +testMultiplication+ test in test suite +MyTestSuite2+:
+
+----
+include::examples/runner13.testMultiplication.txt[]
+----
+
+The +-v+ option enables the printing of trace information generated
+by the +TS_TRACE+ function. For example, the +testMultiplication+ test contains trace declarations
+before and after the multiplication test. Thus, the command
+[source,bash]
+----
+include::examples/.buildRunner13_testMultiplicationVerbose.sh[]
+----
+generates this trace output before and after the test:
+
+----
+include::examples/runner13.testMultiplicationVerbose.txt[]
+----
+
+
+[[advanced]]
+Advanced Testing Features
+-------------------------
+
+Preprocessor Macros
+~~~~~~~~~~~~~~~~~~~
+
+CxxTest recognizes a variety of preprocessor macros that can be used to modify the behavior of a test runner. Many of these mimic the options of the +cxxtestgen+ command.
+
+[options="header"]
+|====================================================================================
+| Preprocessor Macro | Description
+| +CXXTEST_HAVE_STD+ | Use the standard library.
+| +CXXTEST_HAVE_EH+ | Use exception handling.
+| +CXXTEST_ABORT_TEST_ON_FAIL+ | Abort tests on failed asserts.
+| +CXXTEST_USER_VALUE_TRAITS+ | Enable user-defined value traits. The default traits dump up to 8 bytes of the data as hex values.
+| +CXXTEST_OLD_TEMPLATE_SYNTAX+ | Use old template syntax that is used by some compilers (e.g. Borland C++ 5).
+| +CXXTEST_OLD_STD+ | Use old syntax for libraries where +std::+ is not recognized.
+| +CXXTEST_MAX_DUMP_SIZE+ | The value of this macro defines the maximum number of bytes to dump if +TS_ASSERT_SAME_DATA()+ fails. The default is 0, which indicates no limit.
+| +CXXTEST_DEFAULT_ABORT+ | The value of this macro is the default value of the dynamic _abort on fail_ flag.
+| +CXXTEST_LONGLONG+ | The value of this macro is used to define long long integers.
+|=====================================
+
+These preprocessor macros must be defined before the CxxTest header
+files are included in the test runner. For example, the following
+template file defines +CXXTEST_HAVE_EH+ and +CXXTEST_ABORT_TEST_ON_FAIL+
+before other headers are included:
+[source,{cpp}]
+----
+include::examples/runner10.tpl[]
+----
+
+Several of these macros concern whether modern C++ conventions are
+supported by the compiler. If tests need to be ported to multiple
+compilers, then one important convention is whether the namespace
++std::+ is supported. For example, switching between +cout+ and
++std::cout+ typically needs to be done throughout a code. CxxTest
+supports this with the +CXXTEST_STD()+ macro. For example,
++CXXTEST_STD(cout)+ can be used within a test suite, and CxxTest
+handles the mapping of this to +cout+ or +std::cout+ depending on
+options provided to +cxxtestgen+.
+
+Finally, CxxTest defines the +CXXTEST_RUNNING+ preprocessor macro.
+This can be used in a test header file to define code that is
+executed when the header is not used in a test runner. For example:
+[source,{cpp}]
+-----
+include::examples/MyTestSuite12.h[]
+----
+Note that test suites derived from +CxxTest::TestSuite+ class cannot
+easily be built outside of the test runner.
+
+
+
+Customizing Test Fixtures
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Setup and Teardown
+^^^^^^^^^^^^^^^^^^
+
+CxxTest test fixtures can be customized in several ways to manage
+the environment for test suites and individual tests. A common
+feature of test suites is that they share a common logic for setting
+up data used in the tests. Thus, there may be duplicate code for
+creating objects, files, inputs, etc. Similarly, the tests may
+share common logic for cleaning up after the test is finished (e.g. deleting temporary objects).
+
+You can put this shared code in a common place by overriding the
+virtual functions `TestSuite::setUp()` and `TestSuite::tearDown()`.
+The `setUp()` function is called before each test, and `tearDown()`
+is called after each test.
+
+For example, the following test suite employs +setUp()+ and +tearDown()+ methods to
+allocate and deallocate memory for a string buffer:
+[source,{cpp}]
+-----
+include::examples/MyTestSuite5.h[]
+-----
+
+Note that test assertions cannot be used in within the +setUp()+
+or +tearDown()+ methods. The scope of these methods is outside any
+test case, so an assertion failure does not have a clear semantics.
+Similarly, test assertions cannot be used in
+world setup and teardown or in +createSuite()+ or +destroySuite()+ methods for for
+dynamicly created test suites (see below).
+
+
+Dynamically Created Test Suites
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CxxTest test fixtures can also be customized during the construction
+and deconstruction of test suites. By default, CxxTest test suites
+are instantiated statically in the test runner. However, dynamically
+created test suites can be used to perform suite-level setup and
+teardown operations, verify the environment needed to execute a
+test suite, and construct test suites that require a nontrivial
+constructor.
+
+CxxTest instantiates a test suite dynamically if the +createSuite()+
+or +destroySuite()+ methods are defined. For example, the following
+test suite checks to see if it is being compiled with Microsoft
+Visual Studio. If not, the +createSuite()+ returns a null pointer,
+indicating that the test suite was not created.
+[source,{cpp}]
+-----
+include::examples/MyTestSuite6.h[]
+-----
+
+Global and World Fixtures
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CxxTest supports two related mechanisms for performing _global_
+setup and teardown operations. _Global fixtures_ are classes that
+inherit from `CxxTest::GlobalFixture`, and they define `setUp` and
+`tearDown` methods. The `setUp` method for all global fixtures is
+called before each test is executed, and the `tearDown` method for
+all global fixtures is called after each test is completed. Thus,
+this mechanism provides a convenient way of defining setup and
+teardown operations that apply to all test suites.
+
+For example, consider the following test suite:
+[source,{cpp}]
+-----
+include::examples/MyTestSuite8.h[]
+-----
+This test suite defines a runner that generates the following output:
+
+-----
+include::examples/buildRunner18.txt[]
+-----
+
+Note that the global fixtures are instantiated with static global
+values. This ensures that these fixtures are created before the
+runner is initialized. Also, note that the `setUp` methods are
+called in the same sequence that the global fixtures are instantiated,
+and the `tearDown` methods are called in the reverse sequence.
+Finally, note that the `setUp` and `tearDown` methods in global
+fixtures return a boolean value, which indicates success or failure
+of that operation.
+
+This example also illustrates the use of _world fixtures_, which
+perform setup and teardown operations that are executed once each
+when beginning and finishing tests in each test suite. World
+fixtures are defined with the `setUpWorld` and `tearDownWorld`
+methods in a global fixture.
+
+
+Runtime Test Customization
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CxxTest defines several functions that can be called in a test suite to modify the default behavior of CxxTest.
+
+[options="header"]
+|==================================
+| Test Suite Method | Description
+| +setAbortTestOnFail(bool)+ | This function specifies whether tests abort after a failure. The default value of the flag is +false+. This function only has an effect if exception handling is enabled.
+| +setMaxDumpSize(unsigned)+ | This function sets the maximum number of bytes that are dumped when
++TS_ASSERT_SAME_DATA()+ fails. The default is 0, which indicates no limit.
+|=============
+
+Note that the the configuration parameters are reset to their default
+values after each test is executed (more precisely, after +tearDown()+
+is called). Consequently, calling these functions in the +setUp()+
+function has the effect of setting that value for the entire test
+suite.
+
+
+
+[[traits]]
+Value Traits
+------------
+
+CxxTest's test assertions like <>
+work for built-in types, but they will not likely work for user-defined
+data types. This is because CxxTest needs a way to compare objects
+and to convert them to strings when printing test failure summaries.
+Thus, user-defined data types need to have the `operator=` method
+defined to ensure that test assertions can be applied.
+
+For example, the following code
+[source,{cpp}]
+-----
+include::examples/MyTestSuite7.h[]
+-----
+defines a test runner that generates the following output
+
+-----
+include::examples/buildRunner17.txt[]
+-----
+The `operator=` method is required to apply
+<> to `Data` objects. However,
+the <> assertion can be
+applied to `Data2` objects that do not have `operator=` defined.
+
+Since CxxTest does not rely on any external library, conversion
+from arbitrary data types to strings is done using _value traits_.
+For example, to convert an integer to a string, CxxTest does the following:
+[source,{cpp}]
+----
+int i = 10;
+CxxTest::ValueTraits converter(i);
+const char* string = converter.asString();
+----
+The CxxTest header file `cxxtest/ValueTraits.h` defines value traits
+for standard types like `int`, `char`, `double`, etc. The default
+`ValueTraits` class for unknown types dumps up to 8 bytes of the value
+in hex format.
+
+If the macro `CXXTEST_USER_VALUE_TRAITS` is defined, then CxxTest will
+omit the default definitions for `ValueTraits`. This allows a user to define their own trait specifications to customize the display of trait information.
+
+
+
+Enumeration Traits
+~~~~~~~~~~~~~~~~~~
+
+CxxTest provides a simple way to define value traits for enumeration
+types. The `CXXTEST_ENUM_TRAITS` macro is used to define value
+traits for all members of an enumeration set.
+
+For example, the following code
+[source,{cpp}]
+-----
+include::examples/MyTestSuite9.h[]
+-----
+defines a test runner that generates the following output
+
+-----
+include::examples/buildRunner19.txt[]
+-----
+The enumeration value traits print strings that represent the elements of the enumeration, except where a numeric value is provided.
+
+Note that the `CXXTEST_ENUM_TRAITS` macros has two arguments; the list of `CXXTEST_ENUM_MEMBER` macros is not separated by commas!
+
+
+Defining New Value Traits
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Defining value traits for a new class is done by providing a class
+specialization of `ValueTraits` that converts an object of the new
+class to a string. For example, consider the definition of the
+`MyClass` class:
+[source,{cpp}]
+-----
+include::examples/MyClass.h[]
+-----
+This class includes definitions of `operator==` and `operator<`
+that support comparisons with <>
+and <>. Additionally,
+this header contains a specialization of `ValueTraits` (in the
+`CxxTest` namespace) that generates a string description of a `MyClass`
+instance.
+
+The following test suite illustrates how these definitions can be
+used to define a test runner:
+[source,{cpp}]
+-----
+include::examples/MyTestSuite10.h[]
+-----
+This runner for this test suite generates the following output:
+
+-----
+include::examples/buildRunner20.txt[]
+-----
+The test failure print logic uses the specialization of `ValueTraits` to create
+the string description of `MyClass` that appears in the output.
+
+
+Defining Value Traits for Template Classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A simple modification to the above example illustrates how a trait can be defined for a
+template class:
+[source,{cpp}]
+-----
+include::examples/MyTestSuite11.h[]
+-----
+Unfortunately, this example employs partial template specialization, which is not supported by all C++ compilers.
+
+
+[[mock]]
+Testing with Mock Objects
+-------------------------
+
+Mock Objects are a very useful concept for testing complex software.
+The key idea is to pass special objects to tested code that facilitates
+the testing process. For instance, a class that implements a
+protocol over TCP might rely on an abstract `ISocket` interface.
+Then a mock testing strategy could pass a `MockSocket` object that
+does anything that is useful for testing (e.g., keep a log of all
+data ``sent'' to verify later).
+
+However, when a challenge for C/C++ developers is that you may need
+to call _global_ functions which you cannot override. Consider any
+code that uses `fopen()`, `fwrite()` and `fclose()`. It is not
+very elegant to have this code actually create files while being
+tested. Even more importantly, you need to test how the code behaves
+when ``bad'' things happen (e.g., when `fopen()` fails). Handling
+these types of exceptional conditions is often a very challenging
+issue for software testing.
+
+CxxTest addresses this challenge by providing a generic mechanism for
+defining mock global functions. The next section illustrates this mechanism for a single
+global function. The following section provides more detail about specific features of CxxTest's
+support for mock testing.
+
+
+Example: A Mock +time()+ Function
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Suppose that we want to perform mock testing using the well known
+standard library function `time()`. Setting up a test suite with
+a mock global function for `time()` can be broken down into the
+following steps.
+
+Declare Mock Functions
+^^^^^^^^^^^^^^^^^^^^^^
+
+The `CXXTEST_MOCK_GLOBAL` macro is used to declare mock global functions. It is often convenient to include
+these declarations in a header file, which is used in both the test suite as well as the code that is being tested:
+[source,{cpp}]
+-----
+include::examples/time_mock.h[]
+-----
+
+Mock Functions in Tested Code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The tested code uses mock global functions, rather than using the global functions directly.
+You access mock functions in the `T` (for _Test_) namespace, so the tested code calls `T::time()` instead of
+`time()`. This is the equivalent of using abstract interfaces
+instead of concrete classes.
+[source,{cpp}]
+-----
+include::examples/rand_example.cpp[]
+-----
+
+
+Mock Source Files
+^^^^^^^^^^^^^^^^^
+
+A source file needs to be defined that implements `T::time()` by
+calling the real global function. This definition is performed automatically by
+defining `CXXTEST_MOCK_REAL_SOURCE_FILE` before the header file is defined:
+[source,{cpp}]
+-----
+include::examples/time_real.cpp[]
+-----
+This source file is not used for testing, but instead it supports normal use of the tested code.
+
+Similarly, a source file needs to be defined that implements `T::time()` by calling the mock
+global function. This definition is performed automatically by defining `CXXTEST_MOCK_TEST_SOURCE_FILE` before the header file is defined:
+[source,{cpp}]
+-----
+include::examples/time_mock.cpp[]
+-----
+
+
+Test Suites using Mock Functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A mock object for the `time()` function is created using the `T::Base_time` class,
+which is automatically created by CxxTest. This class includes a `time()` method whose
+API is the same as the global `time()` function. Thus, this method can be defined to have
+whatever behavior is desired during testing. For example, the following example defines a
+mock object that increments a counter to define an incremental value for `time()`.
+[source,{cpp}]
+-----
+include::examples/MockTestSuite.h[]
+-----
+Note that CxxTest uses global data to associate calls made with `T::time()`
+to calls to `MockObject::time()`. The `MockObject` class simply
+needs to be instantiated prior to the call to `T::time()`.
+
+
+Building the Test Runner
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The +cxxtestgen+ command is used to create a test runner with mock functions in a normal manner:
+[source,bash]
+-----
+include::examples/.buildRunner16_main.sh[]
+-----
+The test runner source file, `runner.cpp`, needs to be compiled an linked to the mock function definition, `time_mock.cpp`, as well as the code being tested, `rand_example.cpp`:
+[source,bash]
+-----
+include::examples/.buildRunner16_compile.sh[]
+-----
+This generates a test runner that generates the following output:
+
+-----
+include::examples/buildRunner16.txt[]
+-----
+
+
+Advanced Topics
+~~~~~~~~~~~~~~~
+
+Void Functions
+^^^^^^^^^^^^^^
+
+The `CXXTEST_MOCK_VOID_GLOBAL` is used to define mock global functions that return `void`.
+This is identical to
+`CXXTEST_MOCK_GLOBAL` except that it does not specify the return
+type. Take a look in `sample/mock/T/stdlib.h` for a demonstation.
+
+Calling the Real Functions While Testing
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+During testing it is sometimes necessary to call the real global
+function instead of the mock global function. CxxTest allows a
+user to do this by creating a special mock object. For a global
+mock function of `time()`, the object `T::Real_time` represents the
+real function. If this class is created, then `T::time()` will be
+redirected to the real function.
+
+Mocking Nonexistent Functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes the tested code calls functions that are not available
+when testing. For example, this can happen when testing driver
+code that calls kernel functions that are not available to a user-mode
+test runner. CxxTest can provide mock global function definitions
+for the test code while using the original functions in the tested code.
+
+
+The `CXXTEST_SUPPLY_GLOBAL` and `CXXTEST_SUPPLY_VOID_GLOBAL` macros are used to provide mock global function definitions. For example, the following declaration creates a mock global function for the Win32 kernel function `IoCallDriver`:
+[source,{cpp}]
+-----
+CXXTEST_SUPPLY_GLOBAL( NTSTATUS, /* Return type */
+ IoCallDriver, /* Name */
+ ( PDEVICE_OBJECT Device, /* Prototype */
+ PIRP Irp ),
+ ( Device, Irp ) /* How to call */ );
+-----
+The tested driver code calls `IoCallDriver()` normally; there is no need for the `T::` syntax.
+The test suite is defined using the `T::Base_IoCallDriver` as with normal mock objects.
+
+CxxTest also provides the macros `CXXTEST_SUPPLY_GLOBAL_C` and
+`CXXTEST_SUPPLY_GLOBAL_VOID_C` that declare the functions with `C`
+linkage (i.e., using `extern "C"`). These macros are used to declare
+function prototypes, since you may not be able to include the header
+files in the test suite that are associated with the mock global function.
+
+
+Functions in Namespaces
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The `CXXTEST_MOCK` macro is used to declare a mock global function that is associated
+with a function in a namespace, including static class member functions.
+For example, consider the function `bool Files::FileExists( const
+String &name )`; the namespace `Files` contains the function
+`FileExists`. The mock class will be called `T::Base_Files_FileExists`
+and the function to implemented would be `fileExists`. The `CXXTEST_MOCK` macro declares this mock global function as follows:
+[source,{cpp}]
+-----
+CXXTEST_MOCK( Files_FileExists, /* Suffix of mock class */
+ bool, /* Return type */
+ fileExists, /* Name of mock member */
+ ( const String &name ), /* Prototype */
+ Files::FileExists, /* Name of real function */
+ ( name ) /* Parameter list */ );
+-----
+Similarly, the `CXXTEST_MOCK_VOID` macro is used to declare a mock global function that returns `void`.
+
+The `CXXTEST_SUPPLY` and `CXXTEST_SUPPLY_VOID` macros are used to provide mock global function definitions for nonexistent functions. For example:
+[source,{cpp}]
+-----
+CXXTEST_SUPPLY( AllocateIrp, /* => T::Base_AllocateIrp */
+ PIRP, /* Return type */
+ allocateIrp, /* Name of mock member */
+ ( CCHAR StackSize ), /* Prototype */
+ IoAllocateIrp, /* Name of real function */
+ ( StackSize ) /* Parameter list */ );
+-----
+Similarly, the `CXXTEST_SUPPLY_C` and `CXXTEST_SUPPLY_VOID_C` macros declare the functions with `C` linkage.
+
+Overloaded Functions
+^^^^^^^^^^^^^^^^^^^^
+
+The `CXXTEST_MOCK` and `CXXTEST_MOCK_VOID` macros have a flexible
+interface that can provide mock global function definitions for
+overloaded functions. The arguments simply need to specify different
+mock class names, mock member names and different prototype definitions.
+These different mock declarations will generate different mock objects that can be explicitly
+referenced in a test suite.
+
+The Mock Namespace
+^^^^^^^^^^^^^^^^^^
+
+The default namespace for mock functions is `T::`. This namespace can be changed by defining the
+`CXXTEST_MOCK_NAMESPACE` macro.
+
+
+[[installation]]
+Installation
+------------
+
+A key feature of CxxTest is that it does has virtually no installation
+process. The +cxxtestgen+ script can be directly executed from the
++cxxtest/bin+ directory. Simply adding this directory to the PATH
+environment of a command shell is sufficient for many applications.
+Beyond that, the build process for test runners simply needs to
+reference the +cxxtest+ root directory to enable proper includes
+during compilation.
+
+The FOG parser requires two Python packages:
+
+ - +ply+
+ - +ordereddict+ (This is needed when running Python 2.4, 2.5 or 2.6)
+
+If these packages are not available, then +cxxtestgen+ will generate an error when the
+FOG parser option is selected.
+If you have
+http://pypi.python.org/pypi/setuptools[setuptools] or
+http://pypi.python.org/pypi/distribute[distribute]
+installed, then
+you can install these packages from PyPI by executing
+[source,bash]
+----
+easy_install ply
+easy_install ordereddict
+----
+
+The +cxxtestgen+ script has been tested with many different versions
+of Python: 2.4 - 3.3, though future releases will not support
+Python 2.4. Note that this script has only been tested with the
+CPython implementation. CxxTest has been tested on Linux and
+Mac platforms using the `g++` and `clang++` compilers.
+
+
+////
+
+WEH - I thought about moving this section into the Getting Started
+section. However, it makes sense to leave this here to reference
+future installations in Debian, Mac Ports, etc. I think that that
+distribution model is very strategic for cxxtest.
+
+////
+
+
+
+[[discussion]]
+Status and Future Plans
+-----------------------
+
+The CxxTest 4.4 release is an incremental release that was driven
+by a variety of bug fixes and minor enhancements. The CxxTest 4.0
+release reflected major changes in the management and focus of
+CxxTest:
+
+ - Perl is no longer used to support CxxTest scripts. Python is now the only scripting language used by CxxTest.
+ - The testing scripts have been rewritten using the PyUnit framework.
+ - The installation process for CxxTest now leverages and integrates with the system Python installation.
+ - A more comprehensive C++ parser is now available, which supports testing of templates.
+ - The CxxTest GUI is no longer supported, and the <> is deprecated.
+ - CxxTest runners now have a command-line interface that facilitates interative use of the test runner.
+ - A new user guide is now available in PDF, HTML and Ebook formats.
+ - Updated the +cxxtestgen+ script to work with Python 2.6 through 3.2
+
+Additionally, CxxTest is now validated with continuous integration
+tests. Yes, the CxxTest developers eat their own dog food!
+
+Although the GUI option for +cxxtestgen+ appears to work fine, this
+GUI is rather primitive. It simply provides a visual summary of
+the test results, and not the interactive test execution that a
+user would expect. This capability is deprecated since none of the
+current developers use this feature. CxxTest users should consider
+using CxxTest with http://jenkins-ci.org/[Jenkins]. The +XUnitPrinter+
+test listener generates XML files that can be easily integrated by
+http://jenkins-ci.org/[Jenkins], which creates a visual summary of
+test results with links to drill-down into test outputs.
+
+This documentation has highlighted the commonly used test listeners.
+There are a variety of other test listeners provided by CxxTest
+that support advanced Cxxtest applications. For example, the
++YesNoRunner+ is perhaps the simplest test listener; it simply
+returns the number of test failures. The +StdioFilePrinter+ is
+used by +StdioPrinter+, but it does not assume that +stdio+ is the
+default output stream. This test listener can be used in contexts
+where a custom output stream must be specified.
+
+////
+WEH - I'd like to say more about future support for CxxTest, but I don't know more basic things like how we should plan to host CxxTest in the future.
+
+Discuss support for ...
+
+ - embedded compilers... (Macros vs templates)
+ - SCONS
+
+Future work:
+
+ - ply cpp
+ - ignore template test classes using the FOG parser
+
+////
+
+////
+NOTE: we do not have test coverage for the following macros:
+CXXTEST_OLD_TEMPLATE_SYNTAX
+CXXTEST_OLD_STD
+CXXTEST_LONGLONG
+////
+
+
+:numbered!:
+
+[[acknowledgements]]
+Acknowledgements
+----------------
+
+CxxTest was originally developed by Erez Volk. The following
+developers contributed to the CxxTest 4.x releases:
+
+* Gašper Ažman
+* Andrey Batyiev
+* Olivier Charloton
+* Dave Elcock
+* Kevin Fitch
+* William Hart
+* Allan Odgaard
+* Lionel Orry
+* John Siirola
+* Jon Schlueter
+* Andrei Korostelev
+* Sebastian Rettenberger
+* Piotr Kasprzyk
+* Gluttton
+* Pawel Tomulik
+
+The CxxTest documentation is generated using
+http://www.methods.co.nz/asciidoc/[AsciiDoc].
+
+A major advancement in CxxTest's capability is the new test discovery
+mechanism that is based on a parser of the Flexible Object Language
+(FOG). FOG generalizes the C++ syntax, which enables CxxTest to
+extract high-level class structure for test discovery. FOG was
+developed by Edward Willink:
+
+* Edward D. Willink. 'Meta-Compilation for C++', PhD Thesis, Computer Science Research Group, University of Surrey, January 2000.
+
+The FOG parser in CxxTest critically relies on the excellent LALR
+parser provided by Dave Beazley's `ply` Python package. The scalable
+performance of `ply` is critical for CxxTest.
+
+CxxTest has greatly benefited from the support of the open source
+community. We would like to thank the following organizations for
+providing web hosting and computing resources: GitHub, SourceForge,
+Tigris.org, Sandia National Laboratories, Google and COIN-OR. The development
+of CxxTest has been partially supported by Sandia National Laboratories.
+Sandia National Laboratories is a multi-program laboratory managed
+and operated by Sandia Corporation, a wholly owned subsidiary of
+Lockheed Martin Corporation, for the U.S. Department of Energy's
+National Nuclear Security Administration under contract DE-AC04-94AL85000.
+
+
+[appendix]
+[[appendix_A]]
+Test Assertion Examples
+-----------------------
+
+[[ts_assert]] TS_ASSERT::
+This is the most basic test assertion, which simply verifies that the +expr+ argument is true:
+[source,{cpp}]
+----
+include::examples/.Assertions_assert.h[]
+----
+[[ts_assert_delta]] TS_ASSERT_DELTA::
+This test assertion verifies two floating point values are within a specified absolute difference:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertDelta.h[]
+----
+
+[[ts_assert_differs]] TS_ASSERT_DIFFERS::
+This test assertion verifies that the two arguments are not equal:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertDiffers.h[]
+----
+
+[[ts_assert_equals]] TS_ASSERT_EQUALS::
+ This test assertion verifies that the two arguments are equal:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertEquals.h[]
+----
+Note that this test is performed using the C++ +==+ operator, whose behavior may be redefined for the two argument types.
+
+[[ts_assert_is_nan]] TS_ASSERT_IS_NAN::
+ This test assertion verifies that the argument is NaN:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertIsNan.h[]
+----
+
+[[ts_assert_is_infinite]] TS_ASSERT_IS_INFINITE::
+ This test assertion verifies that the argument is infinite:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertIsInfinite.h[]
+----
+
+[[ts_assert_less_than]] TS_ASSERT_LESS_THAN::
+This test assertion verifies that the first argument is strictly less than the second argument:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertLessThan.h[]
+----
+
+[[ts_assert_less_than_equals]] TS_ASSERT_LESS_THAN_EQUALS::
+This test assertion verifies that the first argument is less than or equal to the second argument:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertLessThanEquals.h[]
+----
+
+[[ts_assert_predicate]] TS_ASSERT_PREDICATE::
+This test assertion takes as an argument the name of a class, similar to a STL +unary_function+, and evaluates the +operator()+ method:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertPredicate.h[]
+----
+This test assertion can be seen as a generalization of <>, but it
+allows the tester to see the failed value.
+
+[[ts_assert_relation]] TS_ASSERT_RELATION::
+It takes as an argument the name of a class, similar to a STL +binary_function+, and evaluates the +operator()+ method:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertRelation.h[]
+----
+This test assertion can be seen as a generalization of <>, <>, <> and <>.
+This can be used to assert comparisons which are not covered by the builtin test assertions.
+
+[[ts_assert_same_data]] TS_ASSERT_SAME_DATA::
+This test assertion is similar to <>,
+except that it compares the contents of two buffers in memory:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertSameData.h[]
+----
+The standard runner dumps the contents of both buffers as hex values when this test fails.
+
+[[ts_assert_throws]] TS_ASSERT_THROWS::
+This test assertion verifies that the specified exception is thrown when the first argument is executed:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrows.h[]
+----
+
+[[ts_assert_throws_anything]] TS_ASSERT_THROWS_ANYTHING::
+This test assertion verifies that _some_ exception is thrown when the first argument is executed:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrowsAnything.h[]
+----
+
+[[ts_assert_throws_assert]] TS_ASSERT_THROWS_ASSERT::
+This test assertion verifies that an exception is thrown when executing the first argument. The second argument specifies a variable declaration for the exception, and the third argument is executed to test that
+exception value:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrowsAssert.h[]
+----
+Note that this can be viewed as a generalization of <>.
+
+[[ts_assert_throws_equals]] TS_ASSERT_THROWS_EQUALS::
+This test assertion verifies that an exception is thrown when executing the first argument. The second argument specifies a variable declaration for the exception, and the third and fourth arguments are values that are asserted equal after the exception is thrown:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrowsEquals.h[]
+----
+
+[[ts_assert_throws_is_nan]] TS_ASSERT_THROWS_IS_NAN::
+This test assertion verifies that an exception is thrown when executing the first argument. The second argument specifies a variable declaration for the exception, and the third argument is a value that are asserted to be NaN after the exception is thrown:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrowsIsNan.h[]
+----
+
+[[ts_assert_throws_is_infinite]] TS_ASSERT_THROWS_IS_INFINITE::
+This test assertion verifies that an exception is thrown when executing the first argument. The second argument specifies a variable declaration for the exception, and the third argument is a value that are asserted to be infinite after the exception is thrown:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrowsIsInfinite.h[]
+----
+
+[[ts_assert_throws_nothing]] TS_ASSERT_THROWS_NOTHING::
+This test assertion verifies that an exception is _not_ thrown when executing the first argument:
+[source,{cpp}]
+----
+include::examples/.Assertions_assertThrowsNothing.h[]
+----
+
+[[ts_fail]] TS_FAIL::
+This function triggers a test failure with an associated message:
+[source,{cpp}]
+----
+include::examples/.Assertions_fail.h[]
+----
+
+[[ts_skip]] TS_SKIP::
+This function causes the current test to be skipped with an associated warning message:
+[source,{cpp}]
+----
+include::examples/.Assertions_skip.h[]
+----
+
+[[ts_trace]] TS_TRACE::
+This function prints an informational message:
+[source,{cpp}]
+----
+include::examples/.Assertions_trace.h[]
+----
+
+[[ts_warn]] TS_WARN::
+This function prints a message as a warning:
+[source,{cpp}]
+----
+include::examples/.Assertions_warn.h[]
+----
+
+
+[appendix]
+[[appendix_B]]
+Integrating with Your Build Environment
+---------------------------------------
+
+CxxTest can be integrated into a variety of build environments to
+automate the generation, compilation and execution of test runners.
+Here is a rough breakdown of this process:
+
+* Split the application into a library and a main module that just
+ calls the library classes. This way, the test runner will be
+ able to access all your classes through the library.
+* Create another application (or target, or project, or whatever)
+ for the test runner. Make the build tool generate it automatically.
+* Configure the build tool to run the tests automatically.
+
+Unfortunately, different build tools and IDEs need to setup this
+process in different ways. The following sections provide rough
+guidance for doing this for some come use cases.
+
+[NOTE]
+These examples (except for the SCons ones) are not actively maintained and
+tested. Please send suggestions to the CxxTest developers for updating this
+documentation.
+
+[[scons]]
+SCons
+~~~~~
+
+CxxTest provides built-in support for the SCons build system. This part
+documents this feature.
+
+[[scons_installation]]
+Installation
+^^^^^^^^^^^^
+
+The script is located at +build_tools/SCons/cxxtest.py+.
+You need SCons to be able to find this file, so do one of the following:
+
+- add the file to your project site_tools directory (default: +#/site_scons/site_tools/+)
+- link the file to your project site_tools directory
+- add +build_tools/SCons/cxxtest.py+ to your SCons toolpath.
+
+[NOTE]
+'#' means the project root, using the SCons convention of marking it that way.
+
+Preparing the tests for use with the builder
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This builder assumes that tests have a different suffix than other files in your
+project (by default: +.t.h+, configure via 'CXXTEST_SUFFIX'). This isn't a bad
+idea to begin with, since test "header files" are not really header files in the
+traditional sense. This is how it separates files it should run through
+cxxtestgen from the ones it should not.
+
+[NOTE]
+Test header files' filenames should end with +.t.h+.
+
+Compiling and Running the Tests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+By default, you build and run the tests by issuing the following command:
+
+.Building and running the tests in the shell
+===================
+[source,bash]
+scons check
+===================
+
+Of course, the actual name of the target is configurable (+CXXTEST_TARGET+).
+
+Using the Builder
+^^^^^^^^^^^^^^^^^
+
+This section describes what you do in your SConstruct file in order to be able
+to use the builder.
+
+First, you must tell the environment that you want to use the 'cxxtest' tool and
+how it should set itself up.
+
+The easiest way to set the environment up is to pray the defaults are ok.
+The builder does some autodetection and tries its best to figure everything out.
+In the event this works, setting up the environment is as easy as telling SCons
+it should use the 'cxxtest' tool.
+
+.Configuring the environment if defaults are ok
+===================
+[source,python]
+env = Environment(tools = ['default', 'cxxtest'])
+===================
+
+If this doesn't work, the builder tries its best to tell you what went wrong. In
+most cases, it just wasn't able to find where you installed cxxtest. You can fix
+this like so (assuming you have CxxTest in +#/extern_libs/cxxtest/+):
+
+.Configuring the environment: telling the builder where CxxTest is installed
+===================
+[source,python]
+env = Environment(tools = [
+ 'default',
+ ('cxxtest', {'CXXTEST_INSTALL_DIR' : '#/extern_libs/cxxtest/'})
+ ])
+===================
+
+[NOTE]
+If you want to pass other options to the builder, just append them to the
+dictionary.
+
+It is advisable to pass most options to the builder at creation time, although
+the 'CxxTest' call can also accept most of them if you need to do some weird
+thing with a particular test.
+
+You can use the builder the same way you would the 'Program' builder.
+
+.Setting up tests with SCons and the cxxtest builder
+===================
+[source,python]
+---------------------------------------------------------------------------
+# ... set up the environment as above, with your favorite options
+# and then tell the builder to build some tests
+env.CxxTest('my_test_suite', source='mytests.t.h') #<1>
+env.CxxTest('the_other_suite', ['test_header.t.h', '../utilities.cpp']) #<2>
+env.CxxTest('the_third_suite',
+ ['testsuite1.t.h', 'testsuite2.t.h',
+ 'testsuite3.t.h', 'required_libs.cpp']) #<3>
+env.CxxTest('the_fourth_suite',
+ ['reginold_never_checks_for_warnings.t.h'],
+ CXXFLAGS='-Wall -Wextra -Weffc++ -pedantic') #<4>
+---------------------------------------------------------------------------
+
+<1> Normal, 1-source file tests
+<2> This is how a single testsuite needing implementations is compilied
+<3> If you want multiple testsuites in a single runner, this is how it's done
+<4> unrecognised options are passed through to the Program builder unchanged
+
+===================
+
+Configuration Options
+^^^^^^^^^^^^^^^^^^^^^
+
+===== +CXXTEST_RUNNER+
+
+Default: "ErrorPrinter".
+
+This is what is passed to the +--runner+ option of +cxxtestgen+. See the section
+about runners to see what the other options are.
+
+===== +CXXTEST_OPTS+
+
+Default: empty.
+
+Any other commandline options to pass to +cxxtestgen+.
+
+Do not pass +--runner+, +--error-printer+ and friends, and +--root+ or +--part+
+here.
+
+===== +CXXTEST_SUFFIX+
+
+Default: ".t.h"
+
+The suffix test suite files have. Should be different from other header files.
+If you never mean to pass any header files that are not test suites to the
+builder, you can set this to ".h" and use plain ".h" files.
+
+===== +CXXTEST_TARGET+
+
+Default: "check"
+
+This is the target that scons tests are added to in order to run them. If you
+want something else, this is the place.
+
+===== +CXXTEST_INSTALL_DIR+
+
+Default: autodetect
+
+If cxxtest isn't found automatically, you need to set this. Normal SCons path
+expansion rules apply.
+
+===== +CXXTEST_CPPPATH+
+
+Default: autodetect
+
+If you don't want to clutter your normal +CPPPATH+ with CxxTest headers and this
+isn't autodetected even after you set +CXXTEST_INSTALL_DIR+, then set this.
+
+===== +CXXTEST+
+
+Default: autodetect
+
+If +cxxtestgen+ isn't found even after you set +CXXTEST_INSTALL_DIR+, then set
+this to the path of the +cxxtestgen+ script.
+
+===== +CXXTEST_SKIP_ERRORS+
+
+Default: False
+
+When running tests with +scons check+, if you want to continue even if tests
+fail, set this to True.
+
+===== +CXXTEST_PYTHON+
+
+Default: the same python interpreter that is running scons.
+
+If you want to use a particular python interpreter to run +cxxtestgen+, set its
+path here.
+
+===== +CXXTEST_CXXFLAGS_REMOVE+
+
+Default: a list of flags with which no test compiles. Changes as we fix bugs.
+
+Do you want your tests to compile without some flags and don't want gymnastics
+to get them out for tests only? This is the way. Just add them to here and they
+will be stripped. (This is a list, by the way, not a string.)
+
+===== +CXXTEST_CCFLAGS_REMOVE+
+
+Same as above, but for +CCFLAGS+.
+
+===== +CXXTEST_CXXTESTGEN_SCRIPT_NAME+
+
+If you are crazy and have changed the name of the cxxtestgen executable and want
+autodetection to work otherwise, set this to the new name.
+
+
+Using Makefiles
+~~~~~~~~~~~~~~~
+
+Generating the tests with a makefile is pretty straightforward.
+Simply add rules to generate, compile and run the test runner.
+
+[source,{makefile}]
+-----
+all: lib run_tests app
+
+# Rules to build your targets
+lib: ...
+
+app: ...
+
+# A rule that runs the unit tests
+run_tests: runner
+ ./runner
+
+# How to build the test runner
+runner: runner.cpp lib
+ $(CXX) -o $@ $<
+
+# How to generate the test runner
+runner.cpp: SimpleTest.h ComplicatedTest.h
+ cxxtestgen -o $@ --error-printer $^
+-----
+
+
+Using Cons
+~~~~~~~~~~
+
+http://dsmit.com/cons/[Cons] is a powerful and
+versatile make replacement which uses Perl scripts instead of Makefiles.
+
+See `cxxtest/sample/Construct` in the CxxTest distribution for an
+example of building CxxTest test runners with Cons.
+
+
+Using Microsoft Visual Studio
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+See `cxxtest/sample/msvc` in the distribution
+to see a reasonable integration of CxxTest with Microsoft Visual Studio's IDE.
+Basically, the workspace has three
+projects:
+
+* The project `CxxTest_3_Generate` runs `cxxtestgen`.
+* The project `CxxTest_2_Build` compiles the generated file.
+* The project `CxxTest_1_Run` runs the tests.
+
+This method certainly works, and the test results are conveniently
+displayed as compilation errors and warnings (for <>.
+However, there are still a few things missing; to integrate this
+approach with your own project, you usually need to work a little
+bit and tweak some makefiles and project options. The script
+`sample/msvc/FixFiles.bat` can automate some of this process.
+
+
+Using Microsoft Windows DDK
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To use CxxTest with the `build` utility for device drivers, you add
+the generated tests file as an extra dependency using the
+`NTBUILDTARGET0` macro and the `Makefile.inc` file. An example of
+how to do this is in the CxxTest distribution under `sample/winddk`.
+
+
+[appendix]
+[[appendix_C]]
+Testing CxxTest
+---------------
+
+In the +cxxtest/test+ directory, you can execute
+[source,bash]
+----
+python test_cxxtest.py
+----
+to launch all tests. By default, this script executes test suites
+for a variety of compilers if they are found on the user's path:
+`g++`, `clang++`, +cl+ (the Microsoft Visual Studio compiler).
+Additionally, this test script includes separate test suites for
+the default test discovery mechanism as well as test discovery using
+the new FOG parser.
+
+You can execute a specific test suite by giving its name as an
+argument to this test script. For example, the command
+[source,bash]
+----
+python test_cxxtest.py TestGpp
+----
+executes the +TestGpp+ test suite, which tests CxxTest with the
+`g++` compiler. Similarly, the command
+[source,bash]
+----
+python test_cxxtest.py TestGppFOG
+----
+executes the test suite that tests CxxTest using the `g++` compiler
+and the FOG parser.
+
+The +test_cxxtest.py+ script should work with versions Python 2.7
+or newer. If you are running Python 2.6, you will need to install
+the +unittest2+ package. If you have
+http://pypi.python.org/pypi/setuptools[setuptools] or
+http://pypi.python.org/pypi/distribute[distribute]
+installed, then
+you can install this package from PyPI by executing
+[source,bash]
+----
+easy_install unittest2
+----
+Similarly, the tests for this document rely on the `PyUtilib` Python package.
+
+The FOG parser requires two Python packages:
+
+ - +ply+
+ - +ordereddict+ (This is only needed when running Python 2.6)
+
+If these packages are not available, then +test_cxxtest.py+ will skip the FOG tests.
+
+
+[appendix]
+[[appendix_D]]
+include::../Versions[]
+
+// vim: ft=asciidoc
diff --git a/third-party/cxxtest/doc/images/icons/README b/third-party/cxxtest/doc/images/icons/README
new file mode 100644
index 00000000..f12b2a73
--- /dev/null
+++ b/third-party/cxxtest/doc/images/icons/README
@@ -0,0 +1,5 @@
+Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook
+icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency
+from the Jimmac icons to get round MS IE and FOP PNG incompatibilies.
+
+Stuart Rackham
diff --git a/third-party/cxxtest/doc/images/icons/callouts/1.png b/third-party/cxxtest/doc/images/icons/callouts/1.png
new file mode 100644
index 00000000..7d473430
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/1.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/10.png b/third-party/cxxtest/doc/images/icons/callouts/10.png
new file mode 100644
index 00000000..997bbc82
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/10.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/11.png b/third-party/cxxtest/doc/images/icons/callouts/11.png
new file mode 100644
index 00000000..ce47dac3
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/11.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/12.png b/third-party/cxxtest/doc/images/icons/callouts/12.png
new file mode 100644
index 00000000..31daf4e2
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/12.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/13.png b/third-party/cxxtest/doc/images/icons/callouts/13.png
new file mode 100644
index 00000000..14021a89
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/13.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/14.png b/third-party/cxxtest/doc/images/icons/callouts/14.png
new file mode 100644
index 00000000..64014b75
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/14.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/15.png b/third-party/cxxtest/doc/images/icons/callouts/15.png
new file mode 100644
index 00000000..0d65765f
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/15.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/2.png b/third-party/cxxtest/doc/images/icons/callouts/2.png
new file mode 100644
index 00000000..5d09341b
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/2.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/3.png b/third-party/cxxtest/doc/images/icons/callouts/3.png
new file mode 100644
index 00000000..ef7b7004
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/3.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/4.png b/third-party/cxxtest/doc/images/icons/callouts/4.png
new file mode 100644
index 00000000..adb8364e
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/4.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/5.png b/third-party/cxxtest/doc/images/icons/callouts/5.png
new file mode 100644
index 00000000..4d7eb460
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/5.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/6.png b/third-party/cxxtest/doc/images/icons/callouts/6.png
new file mode 100644
index 00000000..0ba694af
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/6.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/7.png b/third-party/cxxtest/doc/images/icons/callouts/7.png
new file mode 100644
index 00000000..472e96f8
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/7.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/8.png b/third-party/cxxtest/doc/images/icons/callouts/8.png
new file mode 100644
index 00000000..5e60973c
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/8.png differ
diff --git a/third-party/cxxtest/doc/images/icons/callouts/9.png b/third-party/cxxtest/doc/images/icons/callouts/9.png
new file mode 100644
index 00000000..a0676d26
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/callouts/9.png differ
diff --git a/third-party/cxxtest/doc/images/icons/caution.png b/third-party/cxxtest/doc/images/icons/caution.png
new file mode 100644
index 00000000..9a8c515a
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/caution.png differ
diff --git a/third-party/cxxtest/doc/images/icons/example.png b/third-party/cxxtest/doc/images/icons/example.png
new file mode 100644
index 00000000..1199e864
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/example.png differ
diff --git a/third-party/cxxtest/doc/images/icons/home.png b/third-party/cxxtest/doc/images/icons/home.png
new file mode 100644
index 00000000..37a5231b
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/home.png differ
diff --git a/third-party/cxxtest/doc/images/icons/important.png b/third-party/cxxtest/doc/images/icons/important.png
new file mode 100644
index 00000000..be685cc4
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/important.png differ
diff --git a/third-party/cxxtest/doc/images/icons/next.png b/third-party/cxxtest/doc/images/icons/next.png
new file mode 100644
index 00000000..64e126bd
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/next.png differ
diff --git a/third-party/cxxtest/doc/images/icons/note.png b/third-party/cxxtest/doc/images/icons/note.png
new file mode 100644
index 00000000..7c1f3e2f
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/note.png differ
diff --git a/third-party/cxxtest/doc/images/icons/prev.png b/third-party/cxxtest/doc/images/icons/prev.png
new file mode 100644
index 00000000..3e8f12fe
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/prev.png differ
diff --git a/third-party/cxxtest/doc/images/icons/tip.png b/third-party/cxxtest/doc/images/icons/tip.png
new file mode 100644
index 00000000..f087c73b
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/tip.png differ
diff --git a/third-party/cxxtest/doc/images/icons/up.png b/third-party/cxxtest/doc/images/icons/up.png
new file mode 100644
index 00000000..2db1ce62
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/up.png differ
diff --git a/third-party/cxxtest/doc/images/icons/warning.png b/third-party/cxxtest/doc/images/icons/warning.png
new file mode 100644
index 00000000..d41edb9a
Binary files /dev/null and b/third-party/cxxtest/doc/images/icons/warning.png differ
diff --git a/third-party/cxxtest/doc/include_anchors.py b/third-party/cxxtest/doc/include_anchors.py
new file mode 100644
index 00000000..8279cadc
--- /dev/null
+++ b/third-party/cxxtest/doc/include_anchors.py
@@ -0,0 +1,90 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+import re
+import sys
+import os.path
+import os
+
+
+pat1a = re.compile('include::([a-zA-Z0-9_\.\-/\/]+\/)\.([^\_]+)\_[a-zA-Z0-9]*\.py\[\]')
+pat1b = re.compile('include::([a-zA-Z0-9_\.\-/\/]+\/)\.([^\_]+)\_[a-zA-Z0-9]*\.sh\[\]')
+pat1c = re.compile('include::([a-zA-Z0-9_\.\-/\/]+\/)\.([^\_]+)\_[a-zA-Z0-9]*\.h\[\]')
+pat1d = re.compile('include::([a-zA-Z0-9_\.\-/\/]+\/)\.([^\_]+)\_[a-zA-Z0-9]*\.cpp\[\]')
+pat2 = re.compile('([^@]+)@([a-zA-Z0-9]+):')
+pat3 = re.compile('([^@]+)@:([a-zA-Z0-9]+)')
+
+processed = set()
+
+def process(dir, root, suffix):
+ #print "PROCESS ",root, suffix
+ bname = "%s%s" % (dir, root)
+ global processed
+ if bname in processed:
+ return
+ #
+ anchors = {}
+ anchors[''] = open('%s.%s_.%s' % (dir, root, suffix), 'w')
+ INPUT = open('%s%s.%s' % (dir, root, suffix), 'r')
+ for line in INPUT:
+ m2 = pat2.match(line)
+ m3 = pat3.match(line)
+ if m2:
+ anchor = m2.group(2)
+ anchors[anchor] = open('%s.%s_%s.%s' % (dir, root, anchor, suffix), 'w')
+ elif m3:
+ anchor = m3.group(2)
+ anchors[anchor].close()
+ del anchors[anchor]
+ else:
+ for anchor in anchors:
+ os.write(anchors[anchor].fileno(), line)
+ INPUT.close()
+ for anchor in anchors:
+ if anchor != '':
+ print "ERROR: anchor '%s' did not terminate" % anchor
+ anchors[anchor].close()
+ #
+ processed.add(bname)
+
+
+for file in sys.argv[1:]:
+ print "Processing file '%s' ..." % file
+ INPUT = open(file, 'r')
+ for line in INPUT:
+ suffix = None
+ m = pat1a.match(line)
+ if m:
+ suffix = 'py'
+ #
+ if suffix is None:
+ m = pat1b.match(line)
+ if m:
+ suffix = 'sh'
+ #
+ if suffix is None:
+ m = pat1c.match(line)
+ if m:
+ suffix = 'h'
+ #
+ if suffix is None:
+ m = pat1d.match(line)
+ if m:
+ suffix = 'cpp'
+ #
+ if not suffix is None:
+ #print "HERE", line, suffix
+ fname = m.group(1)+m.group(2)+'.'+suffix
+ if not os.path.exists(fname):
+ print line
+ print "ERROR: file '%s' does not exist!" % fname
+ sys.exit(1)
+ process(m.group(1), m.group(2), suffix)
+ INPUT.close()
+
diff --git a/third-party/cxxtest/python/README.txt b/third-party/cxxtest/python/README.txt
new file mode 100644
index 00000000..1cd84b90
--- /dev/null
+++ b/third-party/cxxtest/python/README.txt
@@ -0,0 +1,8 @@
+CxxTest Python Package
+======================
+
+The CxxTest Python package includes utilities that are used by the
+CxxTest unit testing framework. Specifically, this Python package
+supports C++ parsing and code generation done in the cxxtestgen
+script.
+
diff --git a/third-party/cxxtest/python/convert.py b/third-party/cxxtest/python/convert.py
new file mode 100644
index 00000000..b7265156
--- /dev/null
+++ b/third-party/cxxtest/python/convert.py
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+#
+# Execute this script to copy the cxxtest/*.py files
+# and run 2to3 to convert them to Python 3.
+#
+
+import glob
+import subprocess
+import os
+import shutil
+
+os.chdir('cxxtest')
+for file in glob.glob('*.py'):
+ shutil.copyfile(file, '../python3/cxxtest/'+file)
+#
+os.chdir('../python3/cxxtest')
+#
+for file in glob.glob('*.py'):
+ subprocess.call('2to3 -w '+file, shell=True)
+
diff --git a/third-party/cxxtest/python/cxxtest/.gitignore b/third-party/cxxtest/python/cxxtest/.gitignore
new file mode 100644
index 00000000..0d20b648
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/third-party/cxxtest/python/cxxtest/__init__.py b/third-party/cxxtest/python/cxxtest/__init__.py
new file mode 100644
index 00000000..669f8bbf
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/__init__.py
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+"""cxxtest: A Python package that supports the CxxTest test framework for C/C++.
+
+.. _CxxTest: http://cxxtest.com/
+
+CxxTest is a unit testing framework for C++ that is similar in
+spirit to JUnit, CppUnit, and xUnit. CxxTest is easy to use because
+it does not require precompiling a CxxTest testing library, it
+employs no advanced features of C++ (e.g. RTTI) and it supports a
+very flexible form of test discovery.
+
+The cxxtest Python package includes capabilities for parsing C/C++ source files and generating
+CxxTest drivers.
+"""
+
+from cxxtest.__release__ import __version__, __date__
+__date__
+__version__
+
+__maintainer__ = "William E. Hart"
+__maintainer_email__ = "whart222@gmail.com"
+__license__ = "LGPL"
+__url__ = "http://cxxtest.com"
+
+from cxxtest.cxxtestgen import *
diff --git a/third-party/cxxtest/python/cxxtest/__release__.py b/third-party/cxxtest/python/cxxtest/__release__.py
new file mode 100644
index 00000000..1369c60c
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/__release__.py
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+""" Release Information for cxxtest """
+
+__version__ = '4.4'
+__date__ = "2014-06-03"
diff --git a/third-party/cxxtest/python/cxxtest/cxx_parser.py b/third-party/cxxtest/python/cxxtest/cxx_parser.py
new file mode 100644
index 00000000..b9761b32
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/cxx_parser.py
@@ -0,0 +1,2204 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+# vim: fileencoding=utf-8
+
+#
+# This is a PLY parser for the entire ANSI C++ grammar. This grammar was
+# adapted from the FOG grammar developed by E. D. Willink. See
+#
+# http://www.computing.surrey.ac.uk/research/dsrg/fog/
+#
+# for further details.
+#
+# The goal of this grammar is to extract information about class, function and
+# class method declarations, along with their associated scope. Thus, this
+# grammar can be used to analyze classes in an inheritance heirarchy, and then
+# enumerate the methods in a derived class.
+#
+# This grammar parses blocks of <>, (), [] and {} in a generic manner. Thus,
+# There are several capabilities that this grammar does not support:
+#
+# 1. Ambiguous template specification. This grammar cannot parse template
+# specifications that do not have paired <>'s in their declaration. In
+# particular, ambiguous declarations like
+#
+# foo();
+#
+# cannot be correctly parsed.
+#
+# 2. Template class specialization. Although the goal of this grammar is to
+# extract class information, specialization of templated classes is
+# not supported. When a template class definition is parsed, it's
+# declaration is archived without information about the template
+# parameters. Class specializations will be stored separately, and
+# thus they can be processed after the fact. However, this grammar
+# does not attempt to correctly process properties of class inheritence
+# when template class specialization is employed.
+#
+
+#
+# TODO: document usage of this file
+#
+
+from __future__ import division
+
+import os
+import ply.lex as lex
+import ply.yacc as yacc
+import re
+try:
+ from collections import OrderedDict
+except ImportError: #pragma: no cover
+ from ordereddict import OrderedDict
+
+# global data
+lexer = None
+scope_lineno = 0
+identifier_lineno = {}
+_parse_info=None
+_parsedata=None
+noExceptionLogic = True
+
+
+def ply_init(data):
+ global _parsedata
+ _parsedata=data
+
+
+class Scope(object):
+
+ def __init__(self,name,abs_name,scope_t,base_classes,lineno):
+ self.function=[]
+ self.name=name
+ self.scope_t=scope_t
+ self.sub_scopes=[]
+ self.base_classes=base_classes
+ self.abs_name=abs_name
+ self.lineno=lineno
+
+ def insert(self,scope):
+ self.sub_scopes.append(scope)
+
+
+class CppInfo(object):
+
+ def __init__(self, filter=None):
+ self.verbose=0
+ if filter is None:
+ self.filter=re.compile("[Tt][Ee][Ss][Tt]|createSuite|destroySuite")
+ else:
+ self.filter=filter
+ self.scopes=[""]
+ self.index=OrderedDict()
+ self.index[""]=Scope("","::","namespace",[],1)
+ self.function=[]
+
+ def push_scope(self,ns,scope_t,base_classes=[]):
+ name = self.scopes[-1]+"::"+ns
+ if self.verbose>=2:
+ print "-- Starting "+scope_t+" "+name
+ self.scopes.append(name)
+ self.index[name] = Scope(ns,name,scope_t,base_classes,scope_lineno-1)
+
+ def pop_scope(self):
+ scope = self.scopes.pop()
+ if self.verbose>=2:
+ print "-- Stopping "+scope
+ return scope
+
+ def add_function(self, fn):
+ fn = str(fn)
+ if self.filter.search(fn):
+ self.index[self.scopes[-1]].function.append((fn, identifier_lineno.get(fn,lexer.lineno-1)))
+ tmp = self.scopes[-1]+"::"+fn
+ if self.verbose==2:
+ print "-- Function declaration "+fn+" "+tmp
+ elif self.verbose==1:
+ print "-- Function declaration "+tmp
+
+ def get_functions(self,name,quiet=False):
+ if name == "::":
+ name = ""
+ scope = self.index[name]
+ fns=scope.function
+ for key in scope.base_classes:
+ cname = self.find_class(key,scope)
+ if cname is None:
+ if not quiet:
+ print "Defined classes: ",list(self.index.keys())
+ print "WARNING: Unknown class "+key
+ else:
+ fns += self.get_functions(cname,quiet)
+ return fns
+
+ def find_class(self,name,scope):
+ if ':' in name:
+ if name in self.index:
+ return name
+ else:
+ return None
+ tmp = scope.abs_name.split(':')
+ name1 = ":".join(tmp[:-1] + [name])
+ if name1 in self.index:
+ return name1
+ name2 = "::"+name
+ if name2 in self.index:
+ return name2
+ return None
+
+ def __repr__(self):
+ return str(self)
+
+ def is_baseclass(self,cls,base):
+ '''Returns true if base is a base-class of cls'''
+ if cls in self.index:
+ bases = self.index[cls]
+ elif "::"+cls in self.index:
+ bases = self.index["::"+cls]
+ else:
+ return False
+ #raise IOError, "Unknown class "+cls
+ if base in bases.base_classes:
+ return True
+ for name in bases.base_classes:
+ if self.is_baseclass(name,base):
+ return True
+ return False
+
+ def __str__(self):
+ ans=""
+ keys = list(self.index.keys())
+ keys.sort()
+ for key in keys:
+ scope = self.index[key]
+ ans += scope.scope_t+" "+scope.abs_name+"\n"
+ if scope.scope_t == "class":
+ ans += " Base Classes: "+str(scope.base_classes)+"\n"
+ for fn in self.get_functions(scope.abs_name):
+ ans += " "+fn+"\n"
+ else:
+ for fn in scope.function:
+ ans += " "+fn+"\n"
+ return ans
+
+
+def flatten(x):
+ """Flatten nested list"""
+ try:
+ strtypes = basestring
+ except: # for python3 etc
+ strtypes = (str, bytes)
+
+ result = []
+ for el in x:
+ if hasattr(el, "__iter__") and not isinstance(el, strtypes):
+ result.extend(flatten(el))
+ else:
+ result.append(el)
+ return result
+
+#
+# The lexer (and/or a preprocessor) is expected to identify the following
+#
+# Punctuation:
+#
+#
+literals = "+-*/%^&|~!<>=:()?.\'\"\\@$;,"
+
+#
+reserved = {
+ 'private' : 'PRIVATE',
+ 'protected' : 'PROTECTED',
+ 'public' : 'PUBLIC',
+
+ 'bool' : 'BOOL',
+ 'char' : 'CHAR',
+ 'double' : 'DOUBLE',
+ 'float' : 'FLOAT',
+ 'int' : 'INT',
+ 'long' : 'LONG',
+ 'short' : 'SHORT',
+ 'signed' : 'SIGNED',
+ 'unsigned' : 'UNSIGNED',
+ 'void' : 'VOID',
+ 'wchar_t' : 'WCHAR_T',
+
+ 'class' : 'CLASS',
+ 'enum' : 'ENUM',
+ 'namespace' : 'NAMESPACE',
+ 'struct' : 'STRUCT',
+ 'typename' : 'TYPENAME',
+ 'union' : 'UNION',
+
+ 'const' : 'CONST',
+ 'volatile' : 'VOLATILE',
+
+ 'auto' : 'AUTO',
+ 'explicit' : 'EXPLICIT',
+ 'export' : 'EXPORT',
+ 'extern' : 'EXTERN',
+ '__extension__' : 'EXTENSION',
+ 'friend' : 'FRIEND',
+ 'inline' : 'INLINE',
+ 'mutable' : 'MUTABLE',
+ 'register' : 'REGISTER',
+ 'static' : 'STATIC',
+ 'template' : 'TEMPLATE',
+ 'typedef' : 'TYPEDEF',
+ 'using' : 'USING',
+ 'virtual' : 'VIRTUAL',
+
+ 'asm' : 'ASM',
+ 'break' : 'BREAK',
+ 'case' : 'CASE',
+ 'catch' : 'CATCH',
+ 'const_cast' : 'CONST_CAST',
+ 'continue' : 'CONTINUE',
+ 'default' : 'DEFAULT',
+ 'delete' : 'DELETE',
+ 'do' : 'DO',
+ 'dynamic_cast' : 'DYNAMIC_CAST',
+ 'else' : 'ELSE',
+ 'false' : 'FALSE',
+ 'for' : 'FOR',
+ 'goto' : 'GOTO',
+ 'if' : 'IF',
+ 'new' : 'NEW',
+ 'operator' : 'OPERATOR',
+ 'reinterpret_cast' : 'REINTERPRET_CAST',
+ 'return' : 'RETURN',
+ 'sizeof' : 'SIZEOF',
+ 'static_cast' : 'STATIC_CAST',
+ 'switch' : 'SWITCH',
+ 'this' : 'THIS',
+ 'throw' : 'THROW',
+ 'true' : 'TRUE',
+ 'try' : 'TRY',
+ 'typeid' : 'TYPEID',
+ 'while' : 'WHILE',
+ '"C"' : 'CLiteral',
+ '"C++"' : 'CppLiteral',
+
+ '__attribute__' : 'ATTRIBUTE',
+ '__cdecl__' : 'CDECL',
+ '__typeof' : 'uTYPEOF',
+ 'typeof' : 'TYPEOF',
+
+ 'CXXTEST_STD' : 'CXXTEST_STD'
+}
+
+tokens = [
+ "CharacterLiteral",
+ "FloatingLiteral",
+ "Identifier",
+ "IntegerLiteral",
+ "StringLiteral",
+ "RBRACE",
+ "LBRACE",
+ "RBRACKET",
+ "LBRACKET",
+ "ARROW",
+ "ARROW_STAR",
+ "DEC",
+ "EQ",
+ "GE",
+ "INC",
+ "LE",
+ "LOG_AND",
+ "LOG_OR",
+ "NE",
+ "SHL",
+ "SHR",
+ "ASS_ADD",
+ "ASS_AND",
+ "ASS_DIV",
+ "ASS_MOD",
+ "ASS_MUL",
+ "ASS_OR",
+ "ASS_SHL",
+ "ASS_SHR",
+ "ASS_SUB",
+ "ASS_XOR",
+ "DOT_STAR",
+ "ELLIPSIS",
+ "SCOPE",
+] + list(reserved.values())
+
+t_ignore = " \t\r"
+
+t_LBRACE = r"(\{)|(<%)"
+t_RBRACE = r"(\})|(%>)"
+t_LBRACKET = r"(\[)|(<:)"
+t_RBRACKET = r"(\])|(:>)"
+t_ARROW = r"->"
+t_ARROW_STAR = r"->\*"
+t_DEC = r"--"
+t_EQ = r"=="
+t_GE = r">="
+t_INC = r"\+\+"
+t_LE = r"<="
+t_LOG_AND = r"&&"
+t_LOG_OR = r"\|\|"
+t_NE = r"!="
+t_SHL = r"<<"
+t_SHR = r">>"
+t_ASS_ADD = r"\+="
+t_ASS_AND = r"&="
+t_ASS_DIV = r"/="
+t_ASS_MOD = r"%="
+t_ASS_MUL = r"\*="
+t_ASS_OR = r"\|="
+t_ASS_SHL = r"<<="
+t_ASS_SHR = r">>="
+t_ASS_SUB = r"-="
+t_ASS_XOR = r"^="
+t_DOT_STAR = r"\.\*"
+t_ELLIPSIS = r"\.\.\."
+t_SCOPE = r"::"
+
+# Discard comments
+def t_COMMENT(t):
+ r'(/\*(.|\n)*?\*/)|(//.*?\n)|(\#.*?\n)'
+ t.lexer.lineno += t.value.count("\n")
+
+t_IntegerLiteral = r'(0x[0-9A-F]+)|([0-9]+(L){0,1})'
+t_FloatingLiteral = r"[0-9]+[eE\.\+-]+[eE\.\+\-0-9]+"
+t_CharacterLiteral = r'\'([^\'\\]|\\.)*\''
+#t_StringLiteral = r'"([^"\\]|\\.)*"'
+def t_StringLiteral(t):
+ r'"([^"\\]|\\.)*"'
+ t.type = reserved.get(t.value,'StringLiteral')
+ return t
+
+def t_Identifier(t):
+ r"[a-zA-Z_][a-zA-Z_0-9\.]*"
+ t.type = reserved.get(t.value,'Identifier')
+ return t
+
+
+def t_error(t):
+ print "Illegal character '%s'" % t.value[0]
+ #raise IOError, "Parse error"
+ #t.lexer.skip()
+
+def t_newline(t):
+ r'[\n]+'
+ t.lexer.lineno += len(t.value)
+
+precedence = (
+ ( 'right', 'SHIFT_THERE', 'REDUCE_HERE_MOSTLY', 'SCOPE'),
+ ( 'nonassoc', 'ELSE', 'INC', 'DEC', '+', '-', '*', '&', 'LBRACKET', 'LBRACE', '<', ':', ')')
+ )
+
+start = 'translation_unit'
+
+#
+# The %prec resolves the 14.2-3 ambiguity:
+# Identifier '<' is forced to go through the is-it-a-template-name test
+# All names absorb TEMPLATE with the name, so that no template_test is
+# performed for them. This requires all potential declarations within an
+# expression to perpetuate this policy and thereby guarantee the ultimate
+# coverage of explicit_instantiation.
+#
+# The %prec also resolves a conflict in identifier : which is forced to be a
+# shift of a label for a labeled-statement rather than a reduction for the
+# name of a bit-field or generalised constructor. This is pretty dubious
+# syntactically but correct for all semantic possibilities. The shift is
+# only activated when the ambiguity exists at the start of a statement.
+# In this context a bit-field declaration or constructor definition are not
+# allowed.
+#
+
+def p_identifier(p):
+ '''identifier : Identifier
+ | CXXTEST_STD '(' Identifier ')'
+ '''
+ if p[1][0] in ('t','T','c','d'):
+ identifier_lineno[p[1]] = p.lineno(1)
+ p[0] = p[1]
+
+def p_id(p):
+ '''id : identifier %prec SHIFT_THERE
+ | template_decl
+ | TEMPLATE id
+ '''
+ p[0] = get_rest(p)
+
+def p_global_scope(p):
+ '''global_scope : SCOPE
+ '''
+ p[0] = get_rest(p)
+
+def p_id_scope(p):
+ '''id_scope : id SCOPE'''
+ p[0] = get_rest(p)
+
+def p_id_scope_seq(p):
+ '''id_scope_seq : id_scope
+ | id_scope id_scope_seq
+ '''
+ p[0] = get_rest(p)
+
+#
+# A :: B :: C; is ambiguous How much is type and how much name ?
+# The %prec maximises the (type) length which is the 7.1-2 semantic constraint.
+#
+def p_nested_id(p):
+ '''nested_id : id %prec SHIFT_THERE
+ | id_scope nested_id
+ '''
+ p[0] = get_rest(p)
+
+def p_scoped_id(p):
+ '''scoped_id : nested_id
+ | global_scope nested_id
+ | id_scope_seq
+ | global_scope id_scope_seq
+ '''
+ global scope_lineno
+ scope_lineno = lexer.lineno
+ data = flatten(get_rest(p))
+ if data[0] != None:
+ p[0] = "".join(data)
+
+#
+# destructor_id has to be held back to avoid a conflict with a one's
+# complement as per 5.3.1-9, It gets put back only when scoped or in a
+# declarator_id, which is only used as an explicit member name.
+# Declarations of an unscoped destructor are always parsed as a one's
+# complement.
+#
+def p_destructor_id(p):
+ '''destructor_id : '~' id
+ | TEMPLATE destructor_id
+ '''
+ p[0]=get_rest(p)
+
+#def p_template_id(p):
+# '''template_id : empty
+# | TEMPLATE
+# '''
+# pass
+
+def p_template_decl(p):
+ '''template_decl : identifier '<' nonlgt_seq_opt '>'
+ '''
+ #
+ # WEH: should we include the lt/gt symbols to indicate that this is a
+ # template class? How is that going to be used later???
+ #
+ #p[0] = [p[1] ,"<",">"]
+ p[0] = p[1]
+
+def p_special_function_id(p):
+ '''special_function_id : conversion_function_id
+ | operator_function_id
+ | TEMPLATE special_function_id
+ '''
+ p[0]=get_rest(p)
+
+def p_nested_special_function_id(p):
+ '''nested_special_function_id : special_function_id
+ | id_scope destructor_id
+ | id_scope nested_special_function_id
+ '''
+ p[0]=get_rest(p)
+
+def p_scoped_special_function_id(p):
+ '''scoped_special_function_id : nested_special_function_id
+ | global_scope nested_special_function_id
+ '''
+ p[0]=get_rest(p)
+
+# declarator-id is all names in all scopes, except reserved words
+def p_declarator_id(p):
+ '''declarator_id : scoped_id
+ | scoped_special_function_id
+ | destructor_id
+ '''
+ p[0]=p[1]
+
+#
+# The standard defines pseudo-destructors in terms of type-name, which is
+# class/enum/typedef, of which class-name is covered by a normal destructor.
+# pseudo-destructors are supposed to support ~int() in templates, so the
+# grammar here covers built-in names. Other names are covered by the lack
+# of identifier/type discrimination.
+#
+def p_built_in_type_id(p):
+ '''built_in_type_id : built_in_type_specifier
+ | built_in_type_id built_in_type_specifier
+ '''
+ pass
+
+def p_pseudo_destructor_id(p):
+ '''pseudo_destructor_id : built_in_type_id SCOPE '~' built_in_type_id
+ | '~' built_in_type_id
+ | TEMPLATE pseudo_destructor_id
+ '''
+ pass
+
+def p_nested_pseudo_destructor_id(p):
+ '''nested_pseudo_destructor_id : pseudo_destructor_id
+ | id_scope nested_pseudo_destructor_id
+ '''
+ pass
+
+def p_scoped_pseudo_destructor_id(p):
+ '''scoped_pseudo_destructor_id : nested_pseudo_destructor_id
+ | global_scope scoped_pseudo_destructor_id
+ '''
+ pass
+
+#-------------------------------------------------------------------------------
+# A.2 Lexical conventions
+#-------------------------------------------------------------------------------
+#
+
+def p_literal(p):
+ '''literal : IntegerLiteral
+ | CharacterLiteral
+ | FloatingLiteral
+ | StringLiteral
+ | TRUE
+ | FALSE
+ '''
+ pass
+
+#-------------------------------------------------------------------------------
+# A.3 Basic concepts
+#-------------------------------------------------------------------------------
+def p_translation_unit(p):
+ '''translation_unit : declaration_seq_opt
+ '''
+ pass
+
+#-------------------------------------------------------------------------------
+# A.4 Expressions
+#-------------------------------------------------------------------------------
+#
+# primary_expression covers an arbitrary sequence of all names with the
+# exception of an unscoped destructor, which is parsed as its unary expression
+# which is the correct disambiguation (when ambiguous). This eliminates the
+# traditional A(B) meaning A B ambiguity, since we never have to tack an A
+# onto the front of something that might start with (. The name length got
+# maximised ab initio. The downside is that semantic interpretation must split
+# the names up again.
+#
+# Unification of the declaration and expression syntax means that unary and
+# binary pointer declarator operators:
+# int * * name
+# are parsed as binary and unary arithmetic operators (int) * (*name). Since
+# type information is not used
+# ambiguities resulting from a cast
+# (cast)*(value)
+# are resolved to favour the binary rather than the cast unary to ease AST
+# clean-up. The cast-call ambiguity must be resolved to the cast to ensure
+# that (a)(b)c can be parsed.
+#
+# The problem of the functional cast ambiguity
+# name(arg)
+# as call or declaration is avoided by maximising the name within the parsing
+# kernel. So primary_id_expression picks up
+# extern long int const var = 5;
+# as an assignment to the syntax parsed as "extern long int const var". The
+# presence of two names is parsed so that "extern long into const" is
+# distinguished from "var" considerably simplifying subsequent
+# semantic resolution.
+#
+# The generalised name is a concatenation of potential type-names (scoped
+# identifiers or built-in sequences) plus optionally one of the special names
+# such as an operator-function-id, conversion-function-id or destructor as the
+# final name.
+#
+
+def get_rest(p):
+ return [p[i] for i in range(1, len(p))]
+
+def p_primary_expression(p):
+ '''primary_expression : literal
+ | THIS
+ | suffix_decl_specified_ids
+ | abstract_expression %prec REDUCE_HERE_MOSTLY
+ '''
+ p[0] = get_rest(p)
+
+#
+# Abstract-expression covers the () and [] of abstract-declarators.
+#
+def p_abstract_expression(p):
+ '''abstract_expression : parenthesis_clause
+ | LBRACKET bexpression_opt RBRACKET
+ | TEMPLATE abstract_expression
+ '''
+ pass
+
+def p_postfix_expression(p):
+ '''postfix_expression : primary_expression
+ | postfix_expression parenthesis_clause
+ | postfix_expression LBRACKET bexpression_opt RBRACKET
+ | postfix_expression LBRACKET bexpression_opt RBRACKET attributes
+ | postfix_expression '.' declarator_id
+ | postfix_expression '.' scoped_pseudo_destructor_id
+ | postfix_expression ARROW declarator_id
+ | postfix_expression ARROW scoped_pseudo_destructor_id
+ | postfix_expression INC
+ | postfix_expression DEC
+ | DYNAMIC_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | STATIC_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | REINTERPRET_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | CONST_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | TYPEID parameters_clause
+ '''
+ #print "HERE",str(p[1])
+ p[0] = get_rest(p)
+
+def p_bexpression_opt(p):
+ '''bexpression_opt : empty
+ | bexpression
+ '''
+ pass
+
+def p_bexpression(p):
+ '''bexpression : nonbracket_seq
+ | nonbracket_seq bexpression_seq bexpression_clause nonbracket_seq_opt
+ | bexpression_seq bexpression_clause nonbracket_seq_opt
+ '''
+ pass
+
+def p_bexpression_seq(p):
+ '''bexpression_seq : empty
+ | bexpression_seq bexpression_clause nonbracket_seq_opt
+ '''
+ pass
+
+def p_bexpression_clause(p):
+ '''bexpression_clause : LBRACKET bexpression_opt RBRACKET
+ '''
+ pass
+
+
+
+def p_expression_list_opt(p):
+ '''expression_list_opt : empty
+ | expression_list
+ '''
+ pass
+
+def p_expression_list(p):
+ '''expression_list : assignment_expression
+ | expression_list ',' assignment_expression
+ '''
+ pass
+
+def p_unary_expression(p):
+ '''unary_expression : postfix_expression
+ | INC cast_expression
+ | DEC cast_expression
+ | ptr_operator cast_expression
+ | suffix_decl_specified_scope star_ptr_operator cast_expression
+ | '+' cast_expression
+ | '-' cast_expression
+ | '!' cast_expression
+ | '~' cast_expression
+ | SIZEOF unary_expression
+ | new_expression
+ | global_scope new_expression
+ | delete_expression
+ | global_scope delete_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_delete_expression(p):
+ '''delete_expression : DELETE cast_expression
+ '''
+ pass
+
+def p_new_expression(p):
+ '''new_expression : NEW new_type_id new_initializer_opt
+ | NEW parameters_clause new_type_id new_initializer_opt
+ | NEW parameters_clause
+ | NEW parameters_clause parameters_clause new_initializer_opt
+ '''
+ pass
+
+def p_new_type_id(p):
+ '''new_type_id : type_specifier ptr_operator_seq_opt
+ | type_specifier new_declarator
+ | type_specifier new_type_id
+ '''
+ pass
+
+def p_new_declarator(p):
+ '''new_declarator : ptr_operator new_declarator
+ | direct_new_declarator
+ '''
+ pass
+
+def p_direct_new_declarator(p):
+ '''direct_new_declarator : LBRACKET bexpression_opt RBRACKET
+ | direct_new_declarator LBRACKET bexpression RBRACKET
+ '''
+ pass
+
+def p_new_initializer_opt(p):
+ '''new_initializer_opt : empty
+ | '(' expression_list_opt ')'
+ '''
+ pass
+
+#
+# cast-expression is generalised to support a [] as well as a () prefix. This covers the omission of
+# DELETE[] which when followed by a parenthesised expression was ambiguous. It also covers the gcc
+# indexed array initialisation for free.
+#
+def p_cast_expression(p):
+ '''cast_expression : unary_expression
+ | abstract_expression cast_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_pm_expression(p):
+ '''pm_expression : cast_expression
+ | pm_expression DOT_STAR cast_expression
+ | pm_expression ARROW_STAR cast_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_multiplicative_expression(p):
+ '''multiplicative_expression : pm_expression
+ | multiplicative_expression star_ptr_operator pm_expression
+ | multiplicative_expression '/' pm_expression
+ | multiplicative_expression '%' pm_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_additive_expression(p):
+ '''additive_expression : multiplicative_expression
+ | additive_expression '+' multiplicative_expression
+ | additive_expression '-' multiplicative_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_shift_expression(p):
+ '''shift_expression : additive_expression
+ | shift_expression SHL additive_expression
+ | shift_expression SHR additive_expression
+ '''
+ p[0] = get_rest(p)
+
+# | relational_expression '<' shift_expression
+# | relational_expression '>' shift_expression
+# | relational_expression LE shift_expression
+# | relational_expression GE shift_expression
+def p_relational_expression(p):
+ '''relational_expression : shift_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_equality_expression(p):
+ '''equality_expression : relational_expression
+ | equality_expression EQ relational_expression
+ | equality_expression NE relational_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_and_expression(p):
+ '''and_expression : equality_expression
+ | and_expression '&' equality_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_exclusive_or_expression(p):
+ '''exclusive_or_expression : and_expression
+ | exclusive_or_expression '^' and_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_inclusive_or_expression(p):
+ '''inclusive_or_expression : exclusive_or_expression
+ | inclusive_or_expression '|' exclusive_or_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_logical_and_expression(p):
+ '''logical_and_expression : inclusive_or_expression
+ | logical_and_expression LOG_AND inclusive_or_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_logical_or_expression(p):
+ '''logical_or_expression : logical_and_expression
+ | logical_or_expression LOG_OR logical_and_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_conditional_expression(p):
+ '''conditional_expression : logical_or_expression
+ | logical_or_expression '?' expression ':' assignment_expression
+ '''
+ p[0] = get_rest(p)
+
+
+#
+# assignment-expression is generalised to cover the simple assignment of a braced initializer in order to
+# contribute to the coverage of parameter-declaration and init-declaration.
+#
+# | logical_or_expression assignment_operator assignment_expression
+def p_assignment_expression(p):
+ '''assignment_expression : conditional_expression
+ | logical_or_expression assignment_operator nonsemicolon_seq
+ | logical_or_expression '=' braced_initializer
+ | throw_expression
+ '''
+ p[0]=get_rest(p)
+
+def p_assignment_operator(p):
+ '''assignment_operator : '='
+ | ASS_ADD
+ | ASS_AND
+ | ASS_DIV
+ | ASS_MOD
+ | ASS_MUL
+ | ASS_OR
+ | ASS_SHL
+ | ASS_SHR
+ | ASS_SUB
+ | ASS_XOR
+ '''
+ pass
+
+#
+# expression is widely used and usually single-element, so the reductions are arranged so that a
+# single-element expression is returned as is. Multi-element expressions are parsed as a list that
+# may then behave polymorphically as an element or be compacted to an element.
+#
+
+def p_expression(p):
+ '''expression : assignment_expression
+ | expression_list ',' assignment_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_constant_expression(p):
+ '''constant_expression : conditional_expression
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.5 Statements
+#---------------------------------------------------------------------------------------------------
+# Parsing statements is easy once simple_declaration has been generalised to cover expression_statement.
+#
+#
+# The use of extern here is a hack. The 'extern "C" {}' block gets parsed
+# as a function, so when nested 'extern "C"' declarations exist, they don't
+# work because the block is viewed as a list of statements... :(
+#
+def p_statement(p):
+ '''statement : compound_statement
+ | declaration_statement
+ | try_block
+ | labeled_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ '''
+ pass
+
+def p_compound_statement(p):
+ '''compound_statement : LBRACE statement_seq_opt RBRACE
+ '''
+ pass
+
+def p_statement_seq_opt(p):
+ '''statement_seq_opt : empty
+ | statement_seq_opt statement
+ '''
+ pass
+
+#
+# The dangling else conflict is resolved to the innermost if.
+#
+def p_selection_statement(p):
+ '''selection_statement : IF '(' condition ')' statement %prec SHIFT_THERE
+ | IF '(' condition ')' statement ELSE statement
+ | SWITCH '(' condition ')' statement
+ '''
+ pass
+
+def p_condition_opt(p):
+ '''condition_opt : empty
+ | condition
+ '''
+ pass
+
+def p_condition(p):
+ '''condition : nonparen_seq
+ | nonparen_seq condition_seq parameters_clause nonparen_seq_opt
+ | condition_seq parameters_clause nonparen_seq_opt
+ '''
+ pass
+
+def p_condition_seq(p):
+ '''condition_seq : empty
+ | condition_seq parameters_clause nonparen_seq_opt
+ '''
+ pass
+
+def p_labeled_statement(p):
+ '''labeled_statement : identifier ':' statement
+ | CASE constant_expression ':' statement
+ | DEFAULT ':' statement
+ '''
+ pass
+
+def p_try_block(p):
+ '''try_block : TRY compound_statement handler_seq
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_jump_statement(p):
+ '''jump_statement : BREAK ';'
+ | CONTINUE ';'
+ | RETURN nonsemicolon_seq ';'
+ | GOTO identifier ';'
+ '''
+ pass
+
+def p_iteration_statement(p):
+ '''iteration_statement : WHILE '(' condition ')' statement
+ | DO statement WHILE '(' expression ')' ';'
+ | FOR '(' nonparen_seq_opt ')' statement
+ '''
+ pass
+
+def p_declaration_statement(p):
+ '''declaration_statement : block_declaration
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.6 Declarations
+#---------------------------------------------------------------------------------------------------
+def p_compound_declaration(p):
+ '''compound_declaration : LBRACE declaration_seq_opt RBRACE
+ '''
+ pass
+
+def p_declaration_seq_opt(p):
+ '''declaration_seq_opt : empty
+ | declaration_seq_opt declaration
+ '''
+ pass
+
+def p_declaration(p):
+ '''declaration : block_declaration
+ | function_definition
+ | template_declaration
+ | explicit_specialization
+ | specialised_declaration
+ '''
+ pass
+
+def p_specialised_declaration(p):
+ '''specialised_declaration : linkage_specification
+ | namespace_definition
+ | TEMPLATE specialised_declaration
+ '''
+ pass
+
+def p_block_declaration(p):
+ '''block_declaration : simple_declaration
+ | specialised_block_declaration
+ '''
+ pass
+
+def p_specialised_block_declaration(p):
+ '''specialised_block_declaration : asm_definition
+ | namespace_alias_definition
+ | using_declaration
+ | using_directive
+ | TEMPLATE specialised_block_declaration
+ '''
+ pass
+
+def p_simple_declaration(p):
+ '''simple_declaration : ';'
+ | init_declaration ';'
+ | init_declarations ';'
+ | decl_specifier_prefix simple_declaration
+ '''
+ global _parse_info
+ if len(p) == 3:
+ if p[2] == ";":
+ decl = p[1]
+ else:
+ decl = p[2]
+ if decl is not None:
+ fp = flatten(decl)
+ if len(fp) >= 2 and fp[0] is not None and fp[0]!="operator" and fp[1] == '(':
+ p[0] = fp[0]
+ _parse_info.add_function(fp[0])
+
+#
+# A decl-specifier following a ptr_operator provokes a shift-reduce conflict for * const name which is resolved in favour of the pointer, and implemented by providing versions of decl-specifier guaranteed not to start with a cv_qualifier. decl-specifiers are implemented type-centrically. That is the semantic constraint that there must be a type is exploited to impose structure, but actually eliminate very little syntax. built-in types are multi-name and so need a different policy.
+#
+# non-type decl-specifiers are bound to the left-most type in a decl-specifier-seq, by parsing from the right and attaching suffixes to the right-hand type. Finally residual prefixes attach to the left.
+#
+def p_suffix_built_in_decl_specifier_raw(p):
+ '''suffix_built_in_decl_specifier_raw : built_in_type_specifier
+ | suffix_built_in_decl_specifier_raw built_in_type_specifier
+ | suffix_built_in_decl_specifier_raw decl_specifier_suffix
+ '''
+ pass
+
+def p_suffix_built_in_decl_specifier(p):
+ '''suffix_built_in_decl_specifier : suffix_built_in_decl_specifier_raw
+ | TEMPLATE suffix_built_in_decl_specifier
+ '''
+ pass
+
+# | id_scope_seq
+# | SCOPE id_scope_seq
+def p_suffix_named_decl_specifier(p):
+ '''suffix_named_decl_specifier : scoped_id
+ | elaborate_type_specifier
+ | suffix_named_decl_specifier decl_specifier_suffix
+ '''
+ p[0]=get_rest(p)
+
+def p_suffix_named_decl_specifier_bi(p):
+ '''suffix_named_decl_specifier_bi : suffix_named_decl_specifier
+ | suffix_named_decl_specifier suffix_built_in_decl_specifier_raw
+ '''
+ p[0] = get_rest(p)
+ #print "HERE",get_rest(p)
+
+def p_suffix_named_decl_specifiers(p):
+ '''suffix_named_decl_specifiers : suffix_named_decl_specifier_bi
+ | suffix_named_decl_specifiers suffix_named_decl_specifier_bi
+ '''
+ p[0] = get_rest(p)
+
+def p_suffix_named_decl_specifiers_sf(p):
+ '''suffix_named_decl_specifiers_sf : scoped_special_function_id
+ | suffix_named_decl_specifiers
+ | suffix_named_decl_specifiers scoped_special_function_id
+ '''
+ #print "HERE",get_rest(p)
+ p[0] = get_rest(p)
+
+def p_suffix_decl_specified_ids(p):
+ '''suffix_decl_specified_ids : suffix_built_in_decl_specifier
+ | suffix_built_in_decl_specifier suffix_named_decl_specifiers_sf
+ | suffix_named_decl_specifiers_sf
+ '''
+ if len(p) == 3:
+ p[0] = p[2]
+ else:
+ p[0] = p[1]
+
+def p_suffix_decl_specified_scope(p):
+ '''suffix_decl_specified_scope : suffix_named_decl_specifiers SCOPE
+ | suffix_built_in_decl_specifier suffix_named_decl_specifiers SCOPE
+ | suffix_built_in_decl_specifier SCOPE
+ '''
+ p[0] = get_rest(p)
+
+def p_decl_specifier_affix(p):
+ '''decl_specifier_affix : storage_class_specifier
+ | function_specifier
+ | FRIEND
+ | TYPEDEF
+ | cv_qualifier
+ '''
+ pass
+
+def p_decl_specifier_suffix(p):
+ '''decl_specifier_suffix : decl_specifier_affix
+ '''
+ pass
+
+def p_decl_specifier_prefix(p):
+ '''decl_specifier_prefix : decl_specifier_affix
+ | TEMPLATE decl_specifier_prefix
+ '''
+ pass
+
+def p_storage_class_specifier(p):
+ '''storage_class_specifier : REGISTER
+ | STATIC
+ | MUTABLE
+ | EXTERN %prec SHIFT_THERE
+ | EXTENSION
+ | AUTO
+ '''
+ pass
+
+def p_function_specifier(p):
+ '''function_specifier : EXPLICIT
+ | INLINE
+ | VIRTUAL
+ '''
+ pass
+
+def p_type_specifier(p):
+ '''type_specifier : simple_type_specifier
+ | elaborate_type_specifier
+ | cv_qualifier
+ '''
+ pass
+
+def p_elaborate_type_specifier(p):
+ '''elaborate_type_specifier : class_specifier
+ | enum_specifier
+ | elaborated_type_specifier
+ | TEMPLATE elaborate_type_specifier
+ '''
+ pass
+
+def p_simple_type_specifier(p):
+ '''simple_type_specifier : scoped_id
+ | scoped_id attributes
+ | built_in_type_specifier
+ '''
+ p[0] = p[1]
+
+def p_built_in_type_specifier(p):
+ '''built_in_type_specifier : Xbuilt_in_type_specifier
+ | Xbuilt_in_type_specifier attributes
+ '''
+ pass
+
+def p_attributes(p):
+ '''attributes : attribute
+ | attributes attribute
+ '''
+ pass
+
+def p_attribute(p):
+ '''attribute : ATTRIBUTE '(' parameters_clause ')'
+ '''
+
+def p_Xbuilt_in_type_specifier(p):
+ '''Xbuilt_in_type_specifier : CHAR
+ | WCHAR_T
+ | BOOL
+ | SHORT
+ | INT
+ | LONG
+ | SIGNED
+ | UNSIGNED
+ | FLOAT
+ | DOUBLE
+ | VOID
+ | uTYPEOF parameters_clause
+ | TYPEOF parameters_clause
+ '''
+ pass
+
+#
+# The over-general use of declaration_expression to cover decl-specifier-seq_opt declarator in a function-definition means that
+# class X { };
+# could be a function-definition or a class-specifier.
+# enum X { };
+# could be a function-definition or an enum-specifier.
+# The function-definition is not syntactically valid so resolving the false conflict in favour of the
+# elaborated_type_specifier is correct.
+#
+def p_elaborated_type_specifier(p):
+ '''elaborated_type_specifier : class_key scoped_id %prec SHIFT_THERE
+ | elaborated_enum_specifier
+ | TYPENAME scoped_id
+ '''
+ pass
+
+def p_elaborated_enum_specifier(p):
+ '''elaborated_enum_specifier : ENUM scoped_id %prec SHIFT_THERE
+ '''
+ pass
+
+def p_enum_specifier(p):
+ '''enum_specifier : ENUM scoped_id enumerator_clause
+ | ENUM enumerator_clause
+ '''
+ pass
+
+def p_enumerator_clause(p):
+ '''enumerator_clause : LBRACE enumerator_list_ecarb
+ | LBRACE enumerator_list enumerator_list_ecarb
+ | LBRACE enumerator_list ',' enumerator_definition_ecarb
+ '''
+ pass
+
+def p_enumerator_list_ecarb(p):
+ '''enumerator_list_ecarb : RBRACE
+ '''
+ pass
+
+def p_enumerator_definition_ecarb(p):
+ '''enumerator_definition_ecarb : RBRACE
+ '''
+ pass
+
+def p_enumerator_definition_filler(p):
+ '''enumerator_definition_filler : empty
+ '''
+ pass
+
+def p_enumerator_list_head(p):
+ '''enumerator_list_head : enumerator_definition_filler
+ | enumerator_list ',' enumerator_definition_filler
+ '''
+ pass
+
+def p_enumerator_list(p):
+ '''enumerator_list : enumerator_list_head enumerator_definition
+ '''
+ pass
+
+def p_enumerator_definition(p):
+ '''enumerator_definition : enumerator
+ | enumerator '=' constant_expression
+ '''
+ pass
+
+def p_enumerator(p):
+ '''enumerator : identifier
+ '''
+ pass
+
+def p_namespace_definition(p):
+ '''namespace_definition : NAMESPACE scoped_id push_scope compound_declaration
+ | NAMESPACE push_scope compound_declaration
+ '''
+ global _parse_info
+ scope = _parse_info.pop_scope()
+
+def p_namespace_alias_definition(p):
+ '''namespace_alias_definition : NAMESPACE scoped_id '=' scoped_id ';'
+ '''
+ pass
+
+def p_push_scope(p):
+ '''push_scope : empty'''
+ global _parse_info
+ if p[-2] == "namespace":
+ scope=p[-1]
+ else:
+ scope=""
+ _parse_info.push_scope(scope,"namespace")
+
+def p_using_declaration(p):
+ '''using_declaration : USING declarator_id ';'
+ | USING TYPENAME declarator_id ';'
+ '''
+ pass
+
+def p_using_directive(p):
+ '''using_directive : USING NAMESPACE scoped_id ';'
+ '''
+ pass
+
+# '''asm_definition : ASM '(' StringLiteral ')' ';'
+def p_asm_definition(p):
+ '''asm_definition : ASM '(' nonparen_seq_opt ')' ';'
+ '''
+ pass
+
+def p_linkage_specification(p):
+ '''linkage_specification : EXTERN CLiteral declaration
+ | EXTERN CLiteral compound_declaration
+ | EXTERN CppLiteral declaration
+ | EXTERN CppLiteral compound_declaration
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.7 Declarators
+#---------------------------------------------------------------------------------------------------
+#
+# init-declarator is named init_declaration to reflect the embedded decl-specifier-seq_opt
+#
+
+def p_init_declarations(p):
+ '''init_declarations : assignment_expression ',' init_declaration
+ | init_declarations ',' init_declaration
+ '''
+ p[0]=get_rest(p)
+
+def p_init_declaration(p):
+ '''init_declaration : assignment_expression
+ '''
+ p[0]=get_rest(p)
+
+def p_star_ptr_operator(p):
+ '''star_ptr_operator : '*'
+ | star_ptr_operator cv_qualifier
+ '''
+ pass
+
+def p_nested_ptr_operator(p):
+ '''nested_ptr_operator : star_ptr_operator
+ | id_scope nested_ptr_operator
+ '''
+ pass
+
+def p_ptr_operator(p):
+ '''ptr_operator : '&'
+ | nested_ptr_operator
+ | global_scope nested_ptr_operator
+ '''
+ pass
+
+def p_ptr_operator_seq(p):
+ '''ptr_operator_seq : ptr_operator
+ | ptr_operator ptr_operator_seq
+ '''
+ pass
+
+#
+# Independently coded to localise the shift-reduce conflict: sharing just needs another %prec
+#
+def p_ptr_operator_seq_opt(p):
+ '''ptr_operator_seq_opt : empty %prec SHIFT_THERE
+ | ptr_operator ptr_operator_seq_opt
+ '''
+ pass
+
+def p_cv_qualifier_seq_opt(p):
+ '''cv_qualifier_seq_opt : empty
+ | cv_qualifier_seq_opt cv_qualifier
+ '''
+ pass
+
+# TODO: verify that we should include attributes here
+def p_cv_qualifier(p):
+ '''cv_qualifier : CONST
+ | VOLATILE
+ | attributes
+ '''
+ pass
+
+def p_type_id(p):
+ '''type_id : type_specifier abstract_declarator_opt
+ | type_specifier type_id
+ '''
+ pass
+
+def p_abstract_declarator_opt(p):
+ '''abstract_declarator_opt : empty
+ | ptr_operator abstract_declarator_opt
+ | direct_abstract_declarator
+ '''
+ pass
+
+def p_direct_abstract_declarator_opt(p):
+ '''direct_abstract_declarator_opt : empty
+ | direct_abstract_declarator
+ '''
+ pass
+
+def p_direct_abstract_declarator(p):
+ '''direct_abstract_declarator : direct_abstract_declarator_opt parenthesis_clause
+ | direct_abstract_declarator_opt LBRACKET RBRACKET
+ | direct_abstract_declarator_opt LBRACKET bexpression RBRACKET
+ '''
+ pass
+
+def p_parenthesis_clause(p):
+ '''parenthesis_clause : parameters_clause cv_qualifier_seq_opt
+ | parameters_clause cv_qualifier_seq_opt exception_specification
+ '''
+ p[0] = ['(',')']
+
+def p_parameters_clause(p):
+ '''parameters_clause : '(' condition_opt ')'
+ '''
+ p[0] = ['(',')']
+
+#
+# A typed abstract qualifier such as
+# Class * ...
+# looks like a multiply, so pointers are parsed as their binary operation equivalents that
+# ultimately terminate with a degenerate right hand term.
+#
+def p_abstract_pointer_declaration(p):
+ '''abstract_pointer_declaration : ptr_operator_seq
+ | multiplicative_expression star_ptr_operator ptr_operator_seq_opt
+ '''
+ pass
+
+def p_abstract_parameter_declaration(p):
+ '''abstract_parameter_declaration : abstract_pointer_declaration
+ | and_expression '&'
+ | and_expression '&' abstract_pointer_declaration
+ '''
+ pass
+
+def p_special_parameter_declaration(p):
+ '''special_parameter_declaration : abstract_parameter_declaration
+ | abstract_parameter_declaration '=' assignment_expression
+ | ELLIPSIS
+ '''
+ pass
+
+def p_parameter_declaration(p):
+ '''parameter_declaration : assignment_expression
+ | special_parameter_declaration
+ | decl_specifier_prefix parameter_declaration
+ '''
+ pass
+
+#
+# function_definition includes constructor, destructor, implicit int definitions too. A local destructor is successfully parsed as a function-declaration but the ~ was treated as a unary operator. constructor_head is the prefix ambiguity between a constructor and a member-init-list starting with a bit-field.
+#
+def p_function_definition(p):
+ '''function_definition : ctor_definition
+ | func_definition
+ '''
+ pass
+
+def p_func_definition(p):
+ '''func_definition : assignment_expression function_try_block
+ | assignment_expression function_body
+ | decl_specifier_prefix func_definition
+ '''
+ global _parse_info
+ if p[2] is not None and p[2][0] == '{':
+ decl = flatten(p[1])
+ #print "HERE",decl
+ if decl[-1] == ')':
+ decl=decl[-3]
+ else:
+ decl=decl[-1]
+ p[0] = decl
+ if decl != "operator":
+ _parse_info.add_function(decl)
+ else:
+ p[0] = p[2]
+
+def p_ctor_definition(p):
+ '''ctor_definition : constructor_head function_try_block
+ | constructor_head function_body
+ | decl_specifier_prefix ctor_definition
+ '''
+ if p[2] is None or p[2][0] == "try" or p[2][0] == '{':
+ p[0]=p[1]
+ else:
+ p[0]=p[1]
+
+def p_constructor_head(p):
+ '''constructor_head : bit_field_init_declaration
+ | constructor_head ',' assignment_expression
+ '''
+ p[0]=p[1]
+
+def p_function_try_block(p):
+ '''function_try_block : TRY function_block handler_seq
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+ p[0] = ['try']
+
+def p_function_block(p):
+ '''function_block : ctor_initializer_opt function_body
+ '''
+ pass
+
+def p_function_body(p):
+ '''function_body : LBRACE nonbrace_seq_opt RBRACE
+ '''
+ p[0] = ['{','}']
+
+def p_initializer_clause(p):
+ '''initializer_clause : assignment_expression
+ | braced_initializer
+ '''
+ pass
+
+def p_braced_initializer(p):
+ '''braced_initializer : LBRACE initializer_list RBRACE
+ | LBRACE initializer_list ',' RBRACE
+ | LBRACE RBRACE
+ '''
+ pass
+
+def p_initializer_list(p):
+ '''initializer_list : initializer_clause
+ | initializer_list ',' initializer_clause
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.8 Classes
+#---------------------------------------------------------------------------------------------------
+#
+# An anonymous bit-field declaration may look very like inheritance:
+# const int B = 3;
+# class A : B ;
+# The two usages are too distant to try to create and enforce a common prefix so we have to resort to
+# a parser hack by backtracking. Inheritance is much the most likely so we mark the input stream context
+# and try to parse a base-clause. If we successfully reach a { the base-clause is ok and inheritance was
+# the correct choice so we unmark and continue. If we fail to find the { an error token causes
+# back-tracking to the alternative parse in elaborated_type_specifier which regenerates the : and
+# declares unconditional success.
+#
+
+def p_class_specifier_head(p):
+ '''class_specifier_head : class_key scoped_id ':' base_specifier_list LBRACE
+ | class_key ':' base_specifier_list LBRACE
+ | class_key scoped_id LBRACE
+ | class_key LBRACE
+ '''
+ global _parse_info
+ base_classes=[]
+ if len(p) == 6:
+ scope = p[2]
+ base_classes = p[4]
+ elif len(p) == 4:
+ scope = p[2]
+ elif len(p) == 5:
+ base_classes = p[3]
+ else:
+ scope = ""
+ _parse_info.push_scope(scope,p[1],base_classes)
+
+
+def p_class_key(p):
+ '''class_key : CLASS
+ | STRUCT
+ | UNION
+ '''
+ p[0] = p[1]
+
+def p_class_specifier(p):
+ '''class_specifier : class_specifier_head member_specification_opt RBRACE
+ '''
+ scope = _parse_info.pop_scope()
+
+def p_member_specification_opt(p):
+ '''member_specification_opt : empty
+ | member_specification_opt member_declaration
+ '''
+ pass
+
+def p_member_declaration(p):
+ '''member_declaration : accessibility_specifier
+ | simple_member_declaration
+ | function_definition
+ | using_declaration
+ | template_declaration
+ '''
+ p[0] = get_rest(p)
+ #print "Decl",get_rest(p)
+
+#
+# The generality of constructor names (there need be no parenthesised argument list) means that that
+# name : f(g), h(i)
+# could be the start of a constructor or the start of an anonymous bit-field. An ambiguity is avoided by
+# parsing the ctor-initializer of a function_definition as a bit-field.
+#
+def p_simple_member_declaration(p):
+ '''simple_member_declaration : ';'
+ | assignment_expression ';'
+ | constructor_head ';'
+ | member_init_declarations ';'
+ | decl_specifier_prefix simple_member_declaration
+ '''
+ global _parse_info
+ decl = flatten(get_rest(p))
+ if len(decl) >= 4 and decl[-3] == "(":
+ _parse_info.add_function(decl[-4])
+
+def p_member_init_declarations(p):
+ '''member_init_declarations : assignment_expression ',' member_init_declaration
+ | constructor_head ',' bit_field_init_declaration
+ | member_init_declarations ',' member_init_declaration
+ '''
+ pass
+
+def p_member_init_declaration(p):
+ '''member_init_declaration : assignment_expression
+ | bit_field_init_declaration
+ '''
+ pass
+
+def p_accessibility_specifier(p):
+ '''accessibility_specifier : access_specifier ':'
+ '''
+ pass
+
+def p_bit_field_declaration(p):
+ '''bit_field_declaration : assignment_expression ':' bit_field_width
+ | ':' bit_field_width
+ '''
+ if len(p) == 4:
+ p[0]=p[1]
+
+def p_bit_field_width(p):
+ '''bit_field_width : logical_or_expression
+ | logical_or_expression '?' bit_field_width ':' bit_field_width
+ '''
+ pass
+
+def p_bit_field_init_declaration(p):
+ '''bit_field_init_declaration : bit_field_declaration
+ | bit_field_declaration '=' initializer_clause
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.9 Derived classes
+#---------------------------------------------------------------------------------------------------
+def p_base_specifier_list(p):
+ '''base_specifier_list : base_specifier
+ | base_specifier_list ',' base_specifier
+ '''
+ if len(p) == 2:
+ p[0] = [p[1]]
+ else:
+ p[0] = p[1]+[p[3]]
+
+def p_base_specifier(p):
+ '''base_specifier : scoped_id
+ | access_specifier base_specifier
+ | VIRTUAL base_specifier
+ '''
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = p[2]
+
+def p_access_specifier(p):
+ '''access_specifier : PRIVATE
+ | PROTECTED
+ | PUBLIC
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.10 Special member functions
+#---------------------------------------------------------------------------------------------------
+def p_conversion_function_id(p):
+ '''conversion_function_id : OPERATOR conversion_type_id
+ '''
+ p[0] = ['operator']
+
+def p_conversion_type_id(p):
+ '''conversion_type_id : type_specifier ptr_operator_seq_opt
+ | type_specifier conversion_type_id
+ '''
+ pass
+
+#
+# Ctor-initialisers can look like a bit field declaration, given the generalisation of names:
+# Class(Type) : m1(1), m2(2) { }
+# NonClass(bit_field) : int(2), second_variable, ...
+# The grammar below is used within a function_try_block or function_definition.
+# See simple_member_declaration for use in normal member function_definition.
+#
+def p_ctor_initializer_opt(p):
+ '''ctor_initializer_opt : empty
+ | ctor_initializer
+ '''
+ pass
+
+def p_ctor_initializer(p):
+ '''ctor_initializer : ':' mem_initializer_list
+ '''
+ pass
+
+def p_mem_initializer_list(p):
+ '''mem_initializer_list : mem_initializer
+ | mem_initializer_list_head mem_initializer
+ '''
+ pass
+
+def p_mem_initializer_list_head(p):
+ '''mem_initializer_list_head : mem_initializer_list ','
+ '''
+ pass
+
+def p_mem_initializer(p):
+ '''mem_initializer : mem_initializer_id '(' expression_list_opt ')'
+ '''
+ pass
+
+def p_mem_initializer_id(p):
+ '''mem_initializer_id : scoped_id
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.11 Overloading
+#---------------------------------------------------------------------------------------------------
+
+def p_operator_function_id(p):
+ '''operator_function_id : OPERATOR operator
+ | OPERATOR '(' ')'
+ | OPERATOR LBRACKET RBRACKET
+ | OPERATOR '<'
+ | OPERATOR '>'
+ | OPERATOR operator '<' nonlgt_seq_opt '>'
+ '''
+ p[0] = ["operator"]
+
+#
+# It is not clear from the ANSI standard whether spaces are permitted in delete[]. If not then it can
+# be recognised and returned as DELETE_ARRAY by the lexer. Assuming spaces are permitted there is an
+# ambiguity created by the over generalised nature of expressions. operator new is a valid delarator-id
+# which we may have an undimensioned array of. Semantic rubbish, but syntactically valid. Since the
+# array form is covered by the declarator consideration we can exclude the operator here. The need
+# for a semantic rescue can be eliminated at the expense of a couple of shift-reduce conflicts by
+# removing the comments on the next four lines.
+#
+def p_operator(p):
+ '''operator : NEW
+ | DELETE
+ | '+'
+ | '-'
+ | '*'
+ | '/'
+ | '%'
+ | '^'
+ | '&'
+ | '|'
+ | '~'
+ | '!'
+ | '='
+ | ASS_ADD
+ | ASS_SUB
+ | ASS_MUL
+ | ASS_DIV
+ | ASS_MOD
+ | ASS_XOR
+ | ASS_AND
+ | ASS_OR
+ | SHL
+ | SHR
+ | ASS_SHR
+ | ASS_SHL
+ | EQ
+ | NE
+ | LE
+ | GE
+ | LOG_AND
+ | LOG_OR
+ | INC
+ | DEC
+ | ','
+ | ARROW_STAR
+ | ARROW
+ '''
+ p[0]=p[1]
+
+# | IF
+# | SWITCH
+# | WHILE
+# | FOR
+# | DO
+def p_reserved(p):
+ '''reserved : PRIVATE
+ | CLiteral
+ | CppLiteral
+ | IF
+ | SWITCH
+ | WHILE
+ | FOR
+ | DO
+ | PROTECTED
+ | PUBLIC
+ | BOOL
+ | CHAR
+ | DOUBLE
+ | FLOAT
+ | INT
+ | LONG
+ | SHORT
+ | SIGNED
+ | UNSIGNED
+ | VOID
+ | WCHAR_T
+ | CLASS
+ | ENUM
+ | NAMESPACE
+ | STRUCT
+ | TYPENAME
+ | UNION
+ | CONST
+ | VOLATILE
+ | AUTO
+ | EXPLICIT
+ | EXPORT
+ | EXTERN
+ | FRIEND
+ | INLINE
+ | MUTABLE
+ | REGISTER
+ | STATIC
+ | TEMPLATE
+ | TYPEDEF
+ | USING
+ | VIRTUAL
+ | ASM
+ | BREAK
+ | CASE
+ | CATCH
+ | CONST_CAST
+ | CONTINUE
+ | DEFAULT
+ | DYNAMIC_CAST
+ | ELSE
+ | FALSE
+ | GOTO
+ | OPERATOR
+ | REINTERPRET_CAST
+ | RETURN
+ | SIZEOF
+ | STATIC_CAST
+ | THIS
+ | THROW
+ | TRUE
+ | TRY
+ | TYPEID
+ | ATTRIBUTE
+ | CDECL
+ | TYPEOF
+ | uTYPEOF
+ '''
+ if p[1] in ('try', 'catch', 'throw'):
+ global noExceptionLogic
+ noExceptionLogic=False
+
+#---------------------------------------------------------------------------------------------------
+# A.12 Templates
+#---------------------------------------------------------------------------------------------------
+def p_template_declaration(p):
+ '''template_declaration : template_parameter_clause declaration
+ | EXPORT template_declaration
+ '''
+ pass
+
+def p_template_parameter_clause(p):
+ '''template_parameter_clause : TEMPLATE '<' nonlgt_seq_opt '>'
+ '''
+ pass
+
+#
+# Generalised naming makes identifier a valid declaration, so TEMPLATE identifier is too.
+# The TEMPLATE prefix is therefore folded into all names, parenthesis_clause and decl_specifier_prefix.
+#
+# explicit_instantiation: TEMPLATE declaration
+#
+def p_explicit_specialization(p):
+ '''explicit_specialization : TEMPLATE '<' '>' declaration
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.13 Exception Handling
+#---------------------------------------------------------------------------------------------------
+def p_handler_seq(p):
+ '''handler_seq : handler
+ | handler handler_seq
+ '''
+ pass
+
+def p_handler(p):
+ '''handler : CATCH '(' exception_declaration ')' compound_statement
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_exception_declaration(p):
+ '''exception_declaration : parameter_declaration
+ '''
+ pass
+
+def p_throw_expression(p):
+ '''throw_expression : THROW
+ | THROW assignment_expression
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_exception_specification(p):
+ '''exception_specification : THROW '(' ')'
+ | THROW '(' type_id_list ')'
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_type_id_list(p):
+ '''type_id_list : type_id
+ | type_id_list ',' type_id
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# Misc productions
+#---------------------------------------------------------------------------------------------------
+def p_nonsemicolon_seq(p):
+ '''nonsemicolon_seq : empty
+ | nonsemicolon_seq nonsemicolon
+ '''
+ pass
+
+def p_nonsemicolon(p):
+ '''nonsemicolon : misc
+ | '('
+ | ')'
+ | '<'
+ | '>'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonparen_seq_opt(p):
+ '''nonparen_seq_opt : empty
+ | nonparen_seq_opt nonparen
+ '''
+ pass
+
+def p_nonparen_seq(p):
+ '''nonparen_seq : nonparen
+ | nonparen_seq nonparen
+ '''
+ pass
+
+def p_nonparen(p):
+ '''nonparen : misc
+ | '<'
+ | '>'
+ | ';'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonbracket_seq_opt(p):
+ '''nonbracket_seq_opt : empty
+ | nonbracket_seq_opt nonbracket
+ '''
+ pass
+
+def p_nonbracket_seq(p):
+ '''nonbracket_seq : nonbracket
+ | nonbracket_seq nonbracket
+ '''
+ pass
+
+def p_nonbracket(p):
+ '''nonbracket : misc
+ | '<'
+ | '>'
+ | '('
+ | ')'
+ | ';'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonbrace_seq_opt(p):
+ '''nonbrace_seq_opt : empty
+ | nonbrace_seq_opt nonbrace
+ '''
+ pass
+
+def p_nonbrace(p):
+ '''nonbrace : misc
+ | '<'
+ | '>'
+ | '('
+ | ')'
+ | ';'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonlgt_seq_opt(p):
+ '''nonlgt_seq_opt : empty
+ | nonlgt_seq_opt nonlgt
+ '''
+ pass
+
+def p_nonlgt(p):
+ '''nonlgt : misc
+ | '('
+ | ')'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | '<' nonlgt_seq_opt '>'
+ | ';'
+ '''
+ pass
+
+def p_misc(p):
+ '''misc : operator
+ | identifier
+ | IntegerLiteral
+ | CharacterLiteral
+ | FloatingLiteral
+ | StringLiteral
+ | reserved
+ | '?'
+ | ':'
+ | '.'
+ | SCOPE
+ | ELLIPSIS
+ | EXTENSION
+ '''
+ pass
+
+def p_empty(p):
+ '''empty : '''
+ pass
+
+
+
+#
+# Compute column.
+# input is the input text string
+# token is a token instance
+#
+def _find_column(input,token):
+ ''' TODO '''
+ i = token.lexpos
+ while i > 0:
+ if input[i] == '\n': break
+ i -= 1
+ column = (token.lexpos - i)+1
+ return column
+
+def p_error(p):
+ if p is None:
+ tmp = "Syntax error at end of file."
+ else:
+ tmp = "Syntax error at token "
+ if p.type is "":
+ tmp = tmp + "''"
+ else:
+ tmp = tmp + str(p.type)
+ tmp = tmp + " with value '"+str(p.value)+"'"
+ tmp = tmp + " in line " + str(lexer.lineno-1)
+ tmp = tmp + " at column "+str(_find_column(_parsedata,p))
+ raise IOError( tmp )
+
+
+
+#
+# The function that performs the parsing
+#
+def parse_cpp(data=None, filename=None, debug=0, optimize=0, verbose=False, func_filter=None):
+ #
+ # Reset global data
+ #
+ global lexer
+ lexer = None
+ global scope_lineno
+ scope_lineno = 0
+ global indentifier_lineno
+ identifier_lineno = {}
+ global _parse_info
+ _parse_info=None
+ global _parsedata
+ _parsedata=None
+ global noExceptionLogic
+ noExceptionLogic = True
+ #
+ if debug > 0:
+ print "Debugging parse_cpp!"
+ #
+ # Always remove the parser.out file, which is generated to create debugging
+ #
+ if os.path.exists("parser.out"):
+ os.remove("parser.out")
+ #
+ # Remove the parsetab.py* files. These apparently need to be removed
+ # to ensure the creation of a parser.out file.
+ #
+ if os.path.exists("parsetab.py"):
+ os.remove("parsetab.py")
+ if os.path.exists("parsetab.pyc"):
+ os.remove("parsetab.pyc")
+ global debugging
+ debugging=True
+ #
+ # Build lexer
+ #
+ lexer = lex.lex()
+ #
+ # Initialize parse object
+ #
+ _parse_info = CppInfo(filter=func_filter)
+ _parse_info.verbose=verbose
+ #
+ # Build yaccer
+ #
+ write_table = not os.path.exists("parsetab.py")
+ yacc.yacc(debug=debug, optimize=optimize, write_tables=write_table)
+ #
+ # Parse the file
+ #
+ if not data is None:
+ _parsedata=data
+ ply_init(_parsedata)
+ yacc.parse(data,debug=debug)
+ elif not filename is None:
+ f = open(filename)
+ data = f.read()
+ f.close()
+ _parsedata=data
+ ply_init(_parsedata)
+ yacc.parse(data, debug=debug)
+ else:
+ return None
+ #
+ if not noExceptionLogic:
+ _parse_info.noExceptionLogic = False
+ else:
+ for key in identifier_lineno:
+ if 'ASSERT_THROWS' in key:
+ _parse_info.noExceptionLogic = False
+ break
+ _parse_info.noExceptionLogic = True
+ #
+ return _parse_info
+
+
+
+import sys
+
+if __name__ == '__main__': #pragma: no cover
+ #
+ # This MAIN routine parses a sequence of files provided at the command
+ # line. If '-v' is included, then a verbose parsing output is
+ # generated.
+ #
+ for arg in sys.argv[1:]:
+ if arg == "-v":
+ continue
+ print "Parsing file '"+arg+"'"
+ if '-v' in sys.argv:
+ parse_cpp(filename=arg,debug=2,verbose=2)
+ else:
+ parse_cpp(filename=arg,verbose=2)
+ #
+ # Print the _parse_info object summary for this file.
+ # This illustrates how class inheritance can be used to
+ # deduce class members.
+ #
+ print str(_parse_info)
+
diff --git a/third-party/cxxtest/python/cxxtest/cxxtest_fog.py b/third-party/cxxtest/python/cxxtest/cxxtest_fog.py
new file mode 100644
index 00000000..a157b683
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/cxxtest_fog.py
@@ -0,0 +1,99 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+#
+# TODO: add line number info
+# TODO: add test function names
+#
+
+from __future__ import division
+
+import sys
+import re
+from cxxtest_misc import abort
+import cxx_parser
+import re
+
+def cstr( str ):
+ '''Convert a string to its C representation'''
+ return '"' + re.sub('\\\\', '\\\\\\\\', str ) + '"'
+
+def scanInputFiles(files, _options):
+ '''Scan all input files for test suites'''
+ suites=[]
+ for file in files:
+ try:
+ print "Parsing file "+file,
+ sys.stdout.flush()
+ parse_info = cxx_parser.parse_cpp(filename=file,optimize=1)
+ except IOError, err:
+ print " error."
+ print str(err)
+ continue
+ print "done."
+ sys.stdout.flush()
+ #
+ # WEH: see if it really makes sense to use parse information to
+ # initialize this data. I don't think so...
+ #
+ _options.haveStandardLibrary=1
+ if not parse_info.noExceptionLogic:
+ _options.haveExceptionHandling=1
+ #
+ keys = list(parse_info.index.keys())
+ tpat = re.compile("[Tt][Ee][Ss][Tt]")
+ for key in keys:
+ if parse_info.index[key].scope_t == "class" and parse_info.is_baseclass(key,"CxxTest::TestSuite"):
+ name=parse_info.index[key].name
+ if key.startswith('::'):
+ fullname = key[2:]
+ else:
+ fullname = key
+ suite = {
+ 'fullname' : fullname,
+ 'name' : name,
+ 'file' : file,
+ 'cfile' : cstr(file),
+ 'line' : str(parse_info.index[key].lineno),
+ 'generated' : 0,
+ 'object' : 'suite_%s' % fullname.replace('::','_'),
+ 'dobject' : 'suiteDescription_%s' % fullname.replace('::','_'),
+ 'tlist' : 'Tests_%s' % fullname.replace('::','_'),
+ 'tests' : [],
+ 'lines' : [] }
+ for fn in parse_info.get_functions(key,quiet=True):
+ tname = fn[0]
+ lineno = str(fn[1])
+ if tname.startswith('createSuite'):
+ # Indicate that we're using a dynamically generated test suite
+ suite['create'] = str(lineno) # (unknown line)
+ if tname.startswith('destroySuite'):
+ # Indicate that we're using a dynamically generated test suite
+ suite['destroy'] = str(lineno) # (unknown line)
+ if not tpat.match(tname):
+ # Skip non-test methods
+ continue
+ test = { 'name' : tname,
+ 'suite' : suite,
+ 'class' : 'TestDescription_suite_%s_%s' % (suite['fullname'].replace('::','_'), tname),
+ 'object' : 'testDescription_suite_%s_%s' % (suite['fullname'].replace('::','_'), tname),
+ 'line' : lineno,
+ }
+ suite['tests'].append(test)
+ suites.append(suite)
+
+ if not _options.root:
+ ntests = 0
+ for suite in suites:
+ ntests += len(suite['tests'])
+ if ntests == 0:
+ abort( 'No tests defined' )
+ #
+ return [_options, suites]
+
diff --git a/third-party/cxxtest/python/cxxtest/cxxtest_misc.py b/third-party/cxxtest/python/cxxtest/cxxtest_misc.py
new file mode 100755
index 00000000..c9d337e2
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/cxxtest_misc.py
@@ -0,0 +1,78 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+import sys
+import os
+
+def abort( problem ):
+ '''Print error message and exit'''
+ sys.stderr.write( '\n' )
+ sys.stderr.write( problem )
+ sys.stderr.write( '\n\n' )
+ sys.exit(2)
+
+if sys.version_info < (2,6): #pragma: no cover
+ def resolve_symlinks(orig_path):
+ drive,tmp = os.path.splitdrive(os.path.normpath(orig_path))
+ if not drive:
+ drive = os.path.sep
+ parts = tmp.split(os.path.sep)
+ actual_path = [drive]
+ while parts:
+ actual_path.append(parts.pop(0))
+ if not os.path.islink(os.path.join(*actual_path)):
+ continue
+ actual_path[-1] = os.readlink(os.path.join(*actual_path))
+ tmp_drive, tmp_path = os.path.splitdrive(
+ dereference_path(os.path.join(*actual_path)) )
+ if tmp_drive:
+ drive = tmp_drive
+ actual_path = [drive] + tmp_path.split(os.path.sep)
+ return os.path.join(*actual_path)
+
+ def relpath(path, start=None):
+ """Return a relative version of a path.
+ (provides compatibility with Python < 2.6)"""
+ # Some notes on implementation:
+ # - We rely on resolve_symlinks to correctly resolve any symbolic
+ # links that may be present in the paths
+ # - The explicit handling od the drive name is critical for proper
+ # function on Windows (because os.path.join('c:','foo') yields
+ # "c:foo"!).
+ if not start:
+ start = os.getcwd()
+ ref_drive, ref_path = os.path.splitdrive(
+ resolve_symlinks(os.path.abspath(start)) )
+ if not ref_drive:
+ ref_drive = os.path.sep
+ start = [ref_drive] + ref_path.split(os.path.sep)
+ while '' in start:
+ start.remove('')
+
+ pth_drive, pth_path = os.path.splitdrive(
+ resolve_symlinks(os.path.abspath(path)) )
+ if not pth_drive:
+ pth_drive = os.path.sep
+ path = [pth_drive] + pth_path.split(os.path.sep)
+ while '' in path:
+ path.remove('')
+
+ i = 0
+ max = min(len(path), len(start))
+ while i < max and path[i] == start[i]:
+ i += 1
+
+ if i < 2:
+ return os.path.join(*path)
+ else:
+ rel = ['..']*(len(start)-i) + path[i:]
+ if rel:
+ return os.path.join(*rel)
+ else:
+ return '.'
diff --git a/third-party/cxxtest/python/cxxtest/cxxtest_parser.py b/third-party/cxxtest/python/cxxtest/cxxtest_parser.py
new file mode 100644
index 00000000..d7c8f205
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/cxxtest_parser.py
@@ -0,0 +1,254 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+from __future__ import division
+
+import codecs
+import re
+import sys
+from cxxtest.cxxtest_misc import abort
+
+# Global variables
+suites = []
+suite = None
+inBlock = 0
+options=None
+
+def scanInputFiles(files, _options):
+ '''Scan all input files for test suites'''
+ #
+ # Reset global data
+ #
+ global options
+ options=_options
+ global suites
+ suites = []
+ global suite
+ suite = None
+ global inBlock
+ inBlock = 0
+ #
+ for file in files:
+ scanInputFile(file)
+ if len(suites) is 0 and not options.root:
+ abort( 'No tests defined' )
+ return [options,suites]
+
+lineCont_re = re.compile('(.*)\\\s*$')
+def scanInputFile(fileName):
+ '''Scan single input file for test suites'''
+ # mode 'rb' is problematic in python3 - byte arrays don't behave the same as
+ # strings.
+ # As far as the choice of the default encoding: utf-8 chews through
+ # everything that the previous ascii codec could, plus most of new code.
+ # TODO: figure out how to do this properly - like autodetect encoding from
+ # file header.
+ file = codecs.open(fileName, mode='r', encoding='utf-8')
+ prev = ""
+ lineNo = 0
+ contNo = 0
+ while 1:
+ try:
+ line = file.readline()
+ except UnicodeDecodeError:
+ sys.stderr.write("Could not decode unicode character at %s:%s\n" % (fileName, lineNo + 1));
+ raise
+ if not line:
+ break
+ lineNo += 1
+
+ m = lineCont_re.match(line)
+ if m:
+ prev += m.group(1) + " "
+ contNo += 1
+ else:
+ scanInputLine( fileName, lineNo - contNo, prev + line )
+ contNo = 0
+ prev = ""
+ if contNo:
+ scanInputLine( fileName, lineNo - contNo, prev + line )
+
+ closeSuite()
+ file.close()
+
+def scanInputLine( fileName, lineNo, line ):
+ '''Scan single input line for interesting stuff'''
+ scanLineForExceptionHandling( line )
+ scanLineForStandardLibrary( line )
+
+ scanLineForSuiteStart( fileName, lineNo, line )
+
+ global suite
+ if suite:
+ scanLineInsideSuite( suite, lineNo, line )
+
+def scanLineInsideSuite( suite, lineNo, line ):
+ '''Analyze line which is part of a suite'''
+ global inBlock
+ if lineBelongsToSuite( suite, lineNo, line ):
+ scanLineForTest( suite, lineNo, line )
+ scanLineForCreate( suite, lineNo, line )
+ scanLineForDestroy( suite, lineNo, line )
+
+def lineBelongsToSuite( suite, lineNo, line ):
+ '''Returns whether current line is part of the current suite.
+ This can be false when we are in a generated suite outside of CXXTEST_CODE() blocks
+ If the suite is generated, adds the line to the list of lines'''
+ if not suite['generated']:
+ return 1
+
+ global inBlock
+ if not inBlock:
+ inBlock = lineStartsBlock( line )
+ if inBlock:
+ inBlock = addLineToBlock( suite, lineNo, line )
+ return inBlock
+
+
+std_re = re.compile( r"\b(std\s*::|CXXTEST_STD|using\s+namespace\s+std\b|^\s*\#\s*include\s+<[a-z0-9]+>)" )
+def scanLineForStandardLibrary( line ):
+ '''Check if current line uses standard library'''
+ global options
+ if not options.haveStandardLibrary and std_re.search(line):
+ if not options.noStandardLibrary:
+ options.haveStandardLibrary = 1
+
+exception_re = re.compile( r"\b(throw|try|catch|TSM?_ASSERT_THROWS[A-Z_]*)\b" )
+def scanLineForExceptionHandling( line ):
+ '''Check if current line uses exception handling'''
+ global options
+ if not options.haveExceptionHandling and exception_re.search(line):
+ if not options.noExceptionHandling:
+ options.haveExceptionHandling = 1
+
+classdef = '(?:::\s*)?(?:\w+\s*::\s*)*\w+'
+baseclassdef = '(?:public|private|protected)\s+%s' % (classdef,)
+general_suite = r"\bclass\s+(%s)\s*:(?:\s*%s\s*,)*\s*public\s+" \
+ % (classdef, baseclassdef,)
+testsuite = '(?:(?:::)?\s*CxxTest\s*::\s*)?TestSuite'
+suites_re = { re.compile( general_suite + testsuite ) : None }
+generatedSuite_re = re.compile( r'\bCXXTEST_SUITE\s*\(\s*(\w*)\s*\)' )
+def scanLineForSuiteStart( fileName, lineNo, line ):
+ '''Check if current line starts a new test suite'''
+ for i in list(suites_re.items()):
+ m = i[0].search( line )
+ if m:
+ suite = startSuite( m.group(1), fileName, lineNo, 0 )
+ if i[1] is not None:
+ for test in i[1]['tests']:
+ addTest(suite, test['name'], test['line'])
+ break
+ m = generatedSuite_re.search( line )
+ if m:
+ sys.stdout.write( "%s:%s: Warning: Inline test suites are deprecated.\n" % (fileName, lineNo) )
+ startSuite( m.group(1), fileName, lineNo, 1 )
+
+def startSuite( name, file, line, generated ):
+ '''Start scanning a new suite'''
+ global suite
+ closeSuite()
+ object_name = name.replace(':',"_")
+ suite = { 'fullname' : name,
+ 'name' : name,
+ 'file' : file,
+ 'cfile' : cstr(file),
+ 'line' : line,
+ 'generated' : generated,
+ 'object' : 'suite_%s' % object_name,
+ 'dobject' : 'suiteDescription_%s' % object_name,
+ 'tlist' : 'Tests_%s' % object_name,
+ 'tests' : [],
+ 'lines' : [] }
+ suites_re[re.compile( general_suite + name )] = suite
+ return suite
+
+def lineStartsBlock( line ):
+ '''Check if current line starts a new CXXTEST_CODE() block'''
+ return re.search( r'\bCXXTEST_CODE\s*\(', line ) is not None
+
+test_re = re.compile( r'^([^/]|/[^/])*\bvoid\s+([Tt]est\w+)\s*\(\s*(void)?\s*\)' )
+def scanLineForTest( suite, lineNo, line ):
+ '''Check if current line starts a test'''
+ m = test_re.search( line )
+ if m:
+ addTest( suite, m.group(2), lineNo )
+
+def addTest( suite, name, line ):
+ '''Add a test function to the current suite'''
+ test = { 'name' : name,
+ 'suite' : suite,
+ 'class' : 'TestDescription_%s_%s' % (suite['object'], name),
+ 'object' : 'testDescription_%s_%s' % (suite['object'], name),
+ 'line' : line,
+ }
+ suite['tests'].append( test )
+
+def addLineToBlock( suite, lineNo, line ):
+ '''Append the line to the current CXXTEST_CODE() block'''
+ line = fixBlockLine( suite, lineNo, line )
+ line = re.sub( r'^.*\{\{', '', line )
+
+ e = re.search( r'\}\}', line )
+ if e:
+ line = line[:e.start()]
+ suite['lines'].append( line )
+ return e is None
+
+def fixBlockLine( suite, lineNo, line):
+ '''Change all [E]TS_ macros used in a line to _[E]TS_ macros with the correct file/line'''
+ return re.sub( r'\b(E?TSM?_(ASSERT[A-Z_]*|FAIL))\s*\(',
+ r'_\1(%s,%s,' % (suite['cfile'], lineNo),
+ line, 0 )
+
+create_re = re.compile( r'\bstatic\s+\w+\s*\*\s*createSuite\s*\(\s*(void)?\s*\)' )
+def scanLineForCreate( suite, lineNo, line ):
+ '''Check if current line defines a createSuite() function'''
+ if create_re.search( line ):
+ addSuiteCreateDestroy( suite, 'create', lineNo )
+
+destroy_re = re.compile( r'\bstatic\s+void\s+destroySuite\s*\(\s*\w+\s*\*\s*\w*\s*\)' )
+def scanLineForDestroy( suite, lineNo, line ):
+ '''Check if current line defines a destroySuite() function'''
+ if destroy_re.search( line ):
+ addSuiteCreateDestroy( suite, 'destroy', lineNo )
+
+def cstr( s ):
+ '''Convert a string to its C representation'''
+ return '"' + s.replace( '\\', '\\\\' ) + '"'
+
+
+def addSuiteCreateDestroy( suite, which, line ):
+ '''Add createSuite()/destroySuite() to current suite'''
+ if which in suite:
+ abort( '%s:%s: %sSuite() already declared' % ( suite['file'], str(line), which ) )
+ suite[which] = line
+
+def closeSuite():
+ '''Close current suite and add it to the list if valid'''
+ global suite
+ if suite is not None:
+ if len(suite['tests']) is not 0:
+ verifySuite(suite)
+ rememberSuite(suite)
+ suite = None
+
+def verifySuite(suite):
+ '''Verify current suite is legal'''
+ if 'create' in suite and 'destroy' not in suite:
+ abort( '%s:%s: Suite %s has createSuite() but no destroySuite()' %
+ (suite['file'], suite['create'], suite['name']) )
+ elif 'destroy' in suite and 'create' not in suite:
+ abort( '%s:%s: Suite %s has destroySuite() but no createSuite()' %
+ (suite['file'], suite['destroy'], suite['name']) )
+
+def rememberSuite(suite):
+ '''Add current suite to list'''
+ global suites
+ suites.append( suite )
+
diff --git a/third-party/cxxtest/python/cxxtest/cxxtestgen.py b/third-party/cxxtest/python/cxxtest/cxxtestgen.py
new file mode 100644
index 00000000..99437cd8
--- /dev/null
+++ b/third-party/cxxtest/python/cxxtest/cxxtestgen.py
@@ -0,0 +1,630 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+# vim: fileencoding=utf-8
+
+from __future__ import division
+# the above import important for forward-compatibility with python3,
+# which is already the default in archlinux!
+
+__all__ = ['main', 'create_manpage']
+
+import __release__
+import os
+import sys
+import re
+import glob
+from optparse import OptionParser
+import cxxtest_parser
+from string import Template
+
+try:
+ import cxxtest_fog
+ imported_fog=True
+except ImportError:
+ imported_fog=False
+
+from cxxtest_misc import abort
+
+try:
+ from os.path import relpath
+except ImportError:
+ from cxxtest_misc import relpath
+
+# Global data is initialized by main()
+options = []
+suites = []
+wrotePreamble = 0
+wroteWorld = 0
+lastIncluded = ''
+
+
+def main(args=sys.argv, catch=False):
+ '''The main program'''
+ #
+ # Reset global state
+ #
+ global wrotePreamble
+ wrotePreamble=0
+ global wroteWorld
+ wroteWorld=0
+ global lastIncluded
+ lastIncluded = ''
+ global suites
+ suites = []
+ global options
+ options = []
+ #
+ try:
+ files = parseCommandline(args)
+ if imported_fog and options.fog:
+ [options,suites] = cxxtest_fog.scanInputFiles( files, options )
+ else:
+ [options,suites] = cxxtest_parser.scanInputFiles( files, options )
+ writeOutput()
+ except SystemExit:
+ if not catch:
+ raise
+
+def create_parser(asciidoc=False):
+ parser = OptionParser("cxxtestgen [options] [ ...]")
+ if asciidoc:
+ parser.description="The cxxtestgen command processes C++ header files to perform test discovery, and then it creates files for the CxxTest test runner."
+ else:
+ parser.description="The 'cxxtestgen' command processes C++ header files to perform test discovery, and then it creates files for the 'CxxTest' test runner."
+
+ parser.add_option("--version",
+ action="store_true", dest="version", default=False,
+ help="Write the CxxTest version.")
+ parser.add_option("-o", "--output",
+ dest="outputFileName", default=None, metavar="NAME",
+ help="Write output to file NAME.")
+ parser.add_option("-w","--world", dest="world", default="cxxtest",
+ help="The label of the tests, used to name the XML results.")
+ parser.add_option("", "--include", action="append",
+ dest="headers", default=[], metavar="HEADER",
+ help="Include file HEADER in the test runner before other headers.")
+ parser.add_option("", "--abort-on-fail",
+ action="store_true", dest="abortOnFail", default=False,
+ help="Abort tests on failed asserts (like xUnit).")
+ parser.add_option("", "--main",
+ action="store", dest="main", default="main",
+ help="Specify an alternative name for the main() function.")
+ parser.add_option("", "--headers",
+ action="store", dest="header_filename", default=None,
+ help="Specify a filename that contains a list of header files that are processed to generate a test runner.")
+ parser.add_option("", "--runner",
+ dest="runner", default="", metavar="CLASS",
+ help="Create a test runner that processes test events using the class CxxTest::CLASS.")
+ parser.add_option("", "--gui",
+ dest="gui", metavar="CLASS",
+ help="Create a GUI test runner that processes test events using the class CxxTest::CLASS. (deprecated)")
+ parser.add_option("", "--error-printer",
+ action="store_true", dest="error_printer", default=False,
+ help="Create a test runner using the ErrorPrinter class, and allow the use of the standard library.")
+ parser.add_option("", "--xunit-printer",
+ action="store_true", dest="xunit_printer", default=False,
+ help="Create a test runner using the XUnitPrinter class.")
+ parser.add_option("", "--xunit-file", dest="xunit_file", default="",
+ help="The file to which the XML summary is written for test runners using the XUnitPrinter class. The default XML filename is TEST-.xml, where is the value of the --world option. (default: cxxtest)")
+ parser.add_option("", "--have-std",
+ action="store_true", dest="haveStandardLibrary", default=False,
+ help="Use the standard library (even if not found in tests).")
+ parser.add_option("", "--no-std",
+ action="store_true", dest="noStandardLibrary", default=False,
+ help="Do not use standard library (even if found in tests).")
+ parser.add_option("", "--have-eh",
+ action="store_true", dest="haveExceptionHandling", default=False,
+ help="Use exception handling (even if not found in tests).")
+ parser.add_option("", "--no-eh",
+ action="store_true", dest="noExceptionHandling", default=False,
+ help="Do not use exception handling (even if found in tests).")
+ parser.add_option("", "--longlong",
+ dest="longlong", default=None, metavar="TYPE",
+ help="Use TYPE as for long long integers. (default: not supported)")
+ parser.add_option("", "--no-static-init",
+ action="store_true", dest="noStaticInit", default=False,
+ help="Do not rely on static initialization in the test runner.")
+ parser.add_option("", "--template",
+ dest="templateFileName", default=None, metavar="TEMPLATE",
+ help="Generate the test runner using file TEMPLATE to define a template.")
+ parser.add_option("", "--root",
+ action="store_true", dest="root", default=False,
+ help="Write the main() function and global data for a test runner.")
+ parser.add_option("", "--part",
+ action="store_true", dest="part", default=False,
+ help="Write the tester classes for a test runner.")
+ #parser.add_option("", "--factor",
+ #action="store_true", dest="factor", default=False,
+ #help="Declare the _CXXTEST_FACTOR macro. (deprecated)")
+ if imported_fog:
+ fog_help = "Use new FOG C++ parser"
+ else:
+ fog_help = "Use new FOG C++ parser (disabled)"
+ parser.add_option("-f", "--fog-parser",
+ action="store_true",
+ dest="fog",
+ default=False,
+ help=fog_help
+ )
+ return parser
+
+def parseCommandline(args):
+ '''Analyze command line arguments'''
+ global imported_fog
+ global options
+
+ parser = create_parser()
+ (options, args) = parser.parse_args(args=args)
+ if not options.header_filename is None:
+ if not os.path.exists(options.header_filename):
+ abort( "ERROR: the file '%s' does not exist!" % options.header_filename )
+ INPUT = open(options.header_filename)
+ headers = [line.strip() for line in INPUT]
+ args.extend( headers )
+ INPUT.close()
+
+ if options.fog and not imported_fog:
+ abort( "Cannot use the FOG parser. Check that the 'ply' package is installed. The 'ordereddict' package is also required if running Python 2.6")
+
+ if options.version:
+ printVersion()
+
+ # the cxxtest builder relies on this behaviour! don't remove
+ if options.runner == 'none':
+ options.runner = None
+
+ if options.xunit_printer or options.runner == "XUnitPrinter":
+ options.xunit_printer=True
+ options.runner="XUnitPrinter"
+ if len(args) > 1:
+ if options.xunit_file == "":
+ if options.world == "":
+ options.world = "cxxtest"
+ options.xunit_file="TEST-"+options.world+".xml"
+ elif options.xunit_file == "":
+ if options.world == "":
+ options.world = "cxxtest"
+ options.xunit_file="TEST-"+options.world+".xml"
+
+ if options.error_printer:
+ options.runner= "ErrorPrinter"
+ options.haveStandardLibrary = True
+
+ if options.noStaticInit and (options.root or options.part):
+ abort( '--no-static-init cannot be used with --root/--part' )
+
+ if options.gui and not options.runner:
+ options.runner = 'StdioPrinter'
+
+ files = setFiles(args[1:])
+ if len(files) == 0 and not options.root:
+ sys.stderr.write(parser.error("No input files found"))
+
+ return files
+
+
+def printVersion():
+ '''Print CxxTest version and exit'''
+ sys.stdout.write( "This is CxxTest version %s.\n" % __release__.__version__ )
+ sys.exit(0)
+
+def setFiles(patterns ):
+ '''Set input files specified on command line'''
+ files = expandWildcards( patterns )
+ return files
+
+def expandWildcards( patterns ):
+ '''Expand all wildcards in an array (glob)'''
+ fileNames = []
+ for pathName in patterns:
+ patternFiles = glob.glob( pathName )
+ for fileName in patternFiles:
+ fileNames.append( fixBackslashes( fileName ) )
+ return fileNames
+
+def fixBackslashes( fileName ):
+ '''Convert backslashes to slashes in file name'''
+ return re.sub( r'\\', '/', fileName, 0 )
+
+
+def writeOutput():
+ '''Create output file'''
+ if options.templateFileName:
+ writeTemplateOutput()
+ else:
+ writeSimpleOutput()
+
+def writeSimpleOutput():
+ '''Create output not based on template'''
+ output = startOutputFile()
+ writePreamble( output )
+ if options.root or not options.part:
+ writeMain( output )
+
+ if len(suites) > 0:
+ output.write("bool "+suites[0]['object']+"_init = false;\n")
+
+ writeWorld( output )
+ output.close()
+
+include_re = re.compile( r"\s*\#\s*include\s+\s*$" )
+world_re = re.compile( r"^\s*\s*$" )
+def writeTemplateOutput():
+ '''Create output based on template file'''
+ template = open(options.templateFileName)
+ output = startOutputFile()
+ while 1:
+ line = template.readline()
+ if not line:
+ break;
+ if include_re.search( line ):
+ writePreamble( output )
+ output.write( line )
+ elif preamble_re.search( line ):
+ writePreamble( output )
+ elif world_re.search( line ):
+ if len(suites) > 0:
+ output.write("bool "+suites[0]['object']+"_init = false;\n")
+ writeWorld( output )
+ else:
+ output.write( line )
+ template.close()
+ output.close()
+
+def startOutputFile():
+ '''Create output file and write header'''
+ if options.outputFileName is not None:
+ output = open( options.outputFileName, 'w' )
+ else:
+ output = sys.stdout
+ output.write( "/* Generated file, do not edit */\n\n" )
+ return output
+
+def writePreamble( output ):
+ '''Write the CxxTest header (#includes and #defines)'''
+ global wrotePreamble
+ if wrotePreamble: return
+ output.write( "#ifndef CXXTEST_RUNNING\n" )
+ output.write( "#define CXXTEST_RUNNING\n" )
+ output.write( "#endif\n" )
+ output.write( "\n" )
+ if options.xunit_printer:
+ output.write( "#include \n" )
+ if options.haveStandardLibrary:
+ output.write( "#define _CXXTEST_HAVE_STD\n" )
+ if options.haveExceptionHandling:
+ output.write( "#define _CXXTEST_HAVE_EH\n" )
+ if options.abortOnFail:
+ output.write( "#define _CXXTEST_ABORT_TEST_ON_FAIL\n" )
+ if options.longlong:
+ output.write( "#define _CXXTEST_LONGLONG %s\n" % options.longlong )
+ #if options.factor:
+ #output.write( "#define _CXXTEST_FACTOR\n" )
+ for header in options.headers:
+ output.write( "#include \"%s\"\n" % header )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ if options.runner:
+ output.write( "#include \n" % options.runner )
+ if options.gui:
+ output.write( "#include \n" % options.gui )
+ output.write( "\n" )
+ wrotePreamble = 1
+
+def writeMain( output ):
+ '''Write the main() function for the test runner'''
+ if not (options.gui or options.runner):
+ return
+ output.write( 'int %s( int argc, char *argv[] ) {\n' % options.main )
+ output.write( ' int status;\n' )
+ if options.noStaticInit:
+ output.write( ' CxxTest::initialize();\n' )
+ if options.gui:
+ tester_t = "CxxTest::GuiTuiRunner " % (options.gui, options.runner)
+ else:
+ tester_t = "CxxTest::%s" % (options.runner)
+ if options.xunit_printer:
+ output.write( ' std::ofstream ofstr("%s");\n' % options.xunit_file )
+ output.write( ' %s tmp(ofstr);\n' % tester_t )
+ else:
+ output.write( ' %s tmp;\n' % tester_t )
+ output.write( ' CxxTest::RealWorldDescription::_worldName = "%s";\n' % options.world )
+ output.write( ' status = CxxTest::Main< %s >( tmp, argc, argv );\n' % tester_t )
+ output.write( ' return status;\n')
+ output.write( '}\n' )
+
+
+def writeWorld( output ):
+ '''Write the world definitions'''
+ global wroteWorld
+ if wroteWorld: return
+ writePreamble( output )
+ writeSuites( output )
+ if options.root or not options.part:
+ writeRoot( output )
+ writeWorldDescr( output )
+ if options.noStaticInit:
+ writeInitialize( output )
+ wroteWorld = 1
+
+def writeSuites(output):
+ '''Write all TestDescriptions and SuiteDescriptions'''
+ for suite in suites:
+ writeInclude( output, suite['file'] )
+ if isGenerated(suite):
+ generateSuite( output, suite )
+ if not options.noStaticInit:
+ if isDynamic(suite):
+ writeSuitePointer( output, suite )
+ else:
+ writeSuiteObject( output, suite )
+ writeTestList( output, suite )
+ writeSuiteDescription( output, suite )
+ writeTestDescriptions( output, suite )
+
+def isGenerated(suite):
+ '''Checks whether a suite class should be created'''
+ return suite['generated']
+
+def isDynamic(suite):
+ '''Checks whether a suite is dynamic'''
+ return 'create' in suite
+
+def writeInclude(output, file):
+ '''Add #include "file" statement'''
+ global lastIncluded
+ if options.outputFileName:
+ dirname = os.path.split(options.outputFileName)[0]
+ tfile = relpath(file, dirname)
+ if os.path.exists(tfile):
+ if tfile == lastIncluded: return
+ output.writelines( [ '#include "', tfile, '"\n\n' ] )
+ lastIncluded = tfile
+ return
+ #
+ # Use an absolute path if the relative path failed
+ #
+ tfile = os.path.abspath(file)
+ if os.path.exists(tfile):
+ if tfile == lastIncluded: return
+ output.writelines( [ '#include "', tfile, '"\n\n' ] )
+ lastIncluded = tfile
+ return
+
+def generateSuite( output, suite ):
+ '''Write a suite declared with CXXTEST_SUITE()'''
+ output.write( 'class %s : public CxxTest::TestSuite {\n' % suite['fullname'] )
+ output.write( 'public:\n' )
+ for line in suite['lines']:
+ output.write(line)
+ output.write( '};\n\n' )
+
+def writeSuitePointer( output, suite ):
+ '''Create static suite pointer object for dynamic suites'''
+ if options.noStaticInit:
+ output.write( 'static %s* %s;\n\n' % (suite['fullname'], suite['object']) )
+ else:
+ output.write( 'static %s* %s = 0;\n\n' % (suite['fullname'], suite['object']) )
+
+def writeSuiteObject( output, suite ):
+ '''Create static suite object for non-dynamic suites'''
+ output.writelines( [ "static ", suite['fullname'], " ", suite['object'], ";\n\n" ] )
+
+def writeTestList( output, suite ):
+ '''Write the head of the test linked list for a suite'''
+ if options.noStaticInit:
+ output.write( 'static CxxTest::List %s;\n' % suite['tlist'] )
+ else:
+ output.write( 'static CxxTest::List %s = { 0, 0 };\n' % suite['tlist'] )
+
+def writeWorldDescr( output ):
+ '''Write the static name of the world name'''
+ if options.noStaticInit:
+ output.write( 'const char* CxxTest::RealWorldDescription::_worldName;\n' )
+ else:
+ output.write( 'const char* CxxTest::RealWorldDescription::_worldName = "cxxtest";\n' )
+
+def writeTestDescriptions( output, suite ):
+ '''Write all test descriptions for a suite'''
+ for test in suite['tests']:
+ writeTestDescription( output, suite, test )
+
+def writeTestDescription( output, suite, test ):
+ '''Write test description object'''
+ if not options.noStaticInit:
+ output.write( 'static class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
+ else:
+ output.write( 'class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
+ #
+ output.write( 'public:\n' )
+ if not options.noStaticInit:
+ output.write( ' %s() : CxxTest::RealTestDescription( %s, %s, %s, "%s" ) {}\n' %
+ (test['class'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
+ else:
+ if isDynamic(suite):
+ output.write( ' %s(%s* _%s) : %s(_%s) { }\n' %
+ (test['class'], suite['fullname'], suite['object'], suite['object'], suite['object']) )
+ output.write( ' %s* %s;\n' % (suite['fullname'], suite['object']) )
+ else:
+ output.write( ' %s(%s& _%s) : %s(_%s) { }\n' %
+ (test['class'], suite['fullname'], suite['object'], suite['object'], suite['object']) )
+ output.write( ' %s& %s;\n' % (suite['fullname'], suite['object']) )
+ output.write( ' void runTest() { %s }\n' % runBody( suite, test ) )
+ #
+ if not options.noStaticInit:
+ output.write( '} %s;\n\n' % test['object'] )
+ else:
+ output.write( '};\n\n' )
+
+def runBody( suite, test ):
+ '''Body of TestDescription::run()'''
+ if isDynamic(suite): return dynamicRun( suite, test )
+ else: return staticRun( suite, test )
+
+def dynamicRun( suite, test ):
+ '''Body of TestDescription::run() for test in a dynamic suite'''
+ return 'if ( ' + suite['object'] + ' ) ' + suite['object'] + '->' + test['name'] + '();'
+
+def staticRun( suite, test ):
+ '''Body of TestDescription::run() for test in a non-dynamic suite'''
+ return suite['object'] + '.' + test['name'] + '();'
+
+def writeSuiteDescription( output, suite ):
+ '''Write SuiteDescription object'''
+ if isDynamic( suite ):
+ writeDynamicDescription( output, suite )
+ else:
+ writeStaticDescription( output, suite )
+
+def writeDynamicDescription( output, suite ):
+ '''Write SuiteDescription for a dynamic suite'''
+ output.write( 'CxxTest::DynamicSuiteDescription< %s > %s' % (suite['fullname'], suite['dobject']) )
+ if not options.noStaticInit:
+ output.write( '( %s, %s, "%s", %s, %s, %s, %s )' %
+ (suite['cfile'], suite['line'], suite['fullname'], suite['tlist'],
+ suite['object'], suite['create'], suite['destroy']) )
+ output.write( ';\n\n' )
+
+def writeStaticDescription( output, suite ):
+ '''Write SuiteDescription for a static suite'''
+ output.write( 'CxxTest::StaticSuiteDescription %s' % suite['dobject'] )
+ if not options.noStaticInit:
+ output.write( '( %s, %s, "%s", %s, %s )' %
+ (suite['cfile'], suite['line'], suite['fullname'], suite['object'], suite['tlist']) )
+ output.write( ';\n\n' )
+
+def writeRoot(output):
+ '''Write static members of CxxTest classes'''
+ output.write( '#include \n' )
+
+def writeInitialize(output):
+ '''Write CxxTest::initialize(), which replaces static initialization'''
+ output.write( 'namespace CxxTest {\n' )
+ output.write( ' void initialize()\n' )
+ output.write( ' {\n' )
+ for suite in suites:
+ #print "HERE", suite
+ writeTestList( output, suite )
+ output.write( ' %s.initialize();\n' % suite['tlist'] )
+ #writeSuiteObject( output, suite )
+ if isDynamic(suite):
+ writeSuitePointer( output, suite )
+ output.write( ' %s = 0;\n' % suite['object'])
+ else:
+ writeSuiteObject( output, suite )
+ output.write( ' static ')
+ writeSuiteDescription( output, suite )
+ if isDynamic(suite):
+ #output.write( ' %s = %s.suite();\n' % (suite['object'],suite['dobject']) )
+ output.write( ' %s.initialize( %s, %s, "%s", %s, %s, %s, %s );\n' %
+ (suite['dobject'], suite['cfile'], suite['line'], suite['fullname'],
+ suite['tlist'], suite['object'], suite['create'], suite['destroy']) )
+ output.write( ' %s.setUp();\n' % suite['dobject'])
+ else:
+ output.write( ' %s.initialize( %s, %s, "%s", %s, %s );\n' %
+ (suite['dobject'], suite['cfile'], suite['line'], suite['fullname'],
+ suite['object'], suite['tlist']) )
+
+ for test in suite['tests']:
+ output.write( ' static %s %s(%s);\n' %
+ (test['class'], test['object'], suite['object']) )
+ output.write( ' %s.initialize( %s, %s, %s, "%s" );\n' %
+ (test['object'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
+
+ output.write( ' }\n' )
+ output.write( '}\n' )
+
+man_template=Template("""CXXTESTGEN(1)
+=============
+:doctype: manpage
+
+
+NAME
+----
+cxxtestgen - performs test discovery to create a CxxTest test runner
+
+
+SYNOPSIS
+--------
+${usage}
+
+
+DESCRIPTION
+-----------
+${description}
+
+
+OPTIONS
+-------
+${options}
+
+
+EXIT STATUS
+-----------
+*0*::
+ Success
+
+*1*::
+ Failure (syntax or usage error; configuration error; document
+ processing failure; unexpected error).
+
+
+BUGS
+----
+See the CxxTest Home Page for the link to the CxxTest ticket repository.
+
+
+AUTHOR
+------
+CxxTest was originally written by Erez Volk. Many people have
+contributed to it.
+
+
+RESOURCES
+---------
+Home page:
+
+CxxTest User Guide:
+
+
+
+COPYING
+-------
+Copyright (c) 2008 Sandia Corporation. This software is distributed
+under the Lesser GNU General Public License (LGPL) v3
+""")
+
+def create_manpage():
+ """Write ASCIIDOC manpage file"""
+ parser = create_parser(asciidoc=True)
+ #
+ usage = parser.usage
+ description = parser.description
+ options=""
+ for opt in parser.option_list:
+ opts = opt._short_opts + opt._long_opts
+ optstr = '*' + ', '.join(opts) + '*'
+ if not opt.metavar is None:
+ optstr += "='%s'" % opt.metavar
+ optstr += '::\n'
+ options += optstr
+ #
+ options += opt.help
+ options += '\n\n'
+ #
+ OUTPUT = open('cxxtestgen.1.txt','w')
+ OUTPUT.write( man_template.substitute(usage=usage, description=description, options=options) )
+ OUTPUT.close()
+
+
diff --git a/third-party/cxxtest/python/python3/cxxtest/__init__.py b/third-party/cxxtest/python/python3/cxxtest/__init__.py
new file mode 100644
index 00000000..669f8bbf
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/__init__.py
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+"""cxxtest: A Python package that supports the CxxTest test framework for C/C++.
+
+.. _CxxTest: http://cxxtest.com/
+
+CxxTest is a unit testing framework for C++ that is similar in
+spirit to JUnit, CppUnit, and xUnit. CxxTest is easy to use because
+it does not require precompiling a CxxTest testing library, it
+employs no advanced features of C++ (e.g. RTTI) and it supports a
+very flexible form of test discovery.
+
+The cxxtest Python package includes capabilities for parsing C/C++ source files and generating
+CxxTest drivers.
+"""
+
+from cxxtest.__release__ import __version__, __date__
+__date__
+__version__
+
+__maintainer__ = "William E. Hart"
+__maintainer_email__ = "whart222@gmail.com"
+__license__ = "LGPL"
+__url__ = "http://cxxtest.com"
+
+from cxxtest.cxxtestgen import *
diff --git a/third-party/cxxtest/python/python3/cxxtest/__release__.py b/third-party/cxxtest/python/python3/cxxtest/__release__.py
new file mode 100644
index 00000000..1369c60c
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/__release__.py
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+""" Release Information for cxxtest """
+
+__version__ = '4.4'
+__date__ = "2014-06-03"
diff --git a/third-party/cxxtest/python/python3/cxxtest/cxx_parser.py b/third-party/cxxtest/python/python3/cxxtest/cxx_parser.py
new file mode 100644
index 00000000..c3b7561e
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/cxx_parser.py
@@ -0,0 +1,2204 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+# vim: fileencoding=utf-8
+
+#
+# This is a PLY parser for the entire ANSI C++ grammar. This grammar was
+# adapted from the FOG grammar developed by E. D. Willink. See
+#
+# http://www.computing.surrey.ac.uk/research/dsrg/fog/
+#
+# for further details.
+#
+# The goal of this grammar is to extract information about class, function and
+# class method declarations, along with their associated scope. Thus, this
+# grammar can be used to analyze classes in an inheritance heirarchy, and then
+# enumerate the methods in a derived class.
+#
+# This grammar parses blocks of <>, (), [] and {} in a generic manner. Thus,
+# There are several capabilities that this grammar does not support:
+#
+# 1. Ambiguous template specification. This grammar cannot parse template
+# specifications that do not have paired <>'s in their declaration. In
+# particular, ambiguous declarations like
+#
+# foo();
+#
+# cannot be correctly parsed.
+#
+# 2. Template class specialization. Although the goal of this grammar is to
+# extract class information, specialization of templated classes is
+# not supported. When a template class definition is parsed, it's
+# declaration is archived without information about the template
+# parameters. Class specializations will be stored separately, and
+# thus they can be processed after the fact. However, this grammar
+# does not attempt to correctly process properties of class inheritence
+# when template class specialization is employed.
+#
+
+#
+# TODO: document usage of this file
+#
+
+
+
+import os
+import ply.lex as lex
+import ply.yacc as yacc
+import re
+try:
+ from collections import OrderedDict
+except ImportError: #pragma: no cover
+ from ordereddict import OrderedDict
+
+# global data
+lexer = None
+scope_lineno = 0
+identifier_lineno = {}
+_parse_info=None
+_parsedata=None
+noExceptionLogic = True
+
+
+def ply_init(data):
+ global _parsedata
+ _parsedata=data
+
+
+class Scope(object):
+
+ def __init__(self,name,abs_name,scope_t,base_classes,lineno):
+ self.function=[]
+ self.name=name
+ self.scope_t=scope_t
+ self.sub_scopes=[]
+ self.base_classes=base_classes
+ self.abs_name=abs_name
+ self.lineno=lineno
+
+ def insert(self,scope):
+ self.sub_scopes.append(scope)
+
+
+class CppInfo(object):
+
+ def __init__(self, filter=None):
+ self.verbose=0
+ if filter is None:
+ self.filter=re.compile("[Tt][Ee][Ss][Tt]|createSuite|destroySuite")
+ else:
+ self.filter=filter
+ self.scopes=[""]
+ self.index=OrderedDict()
+ self.index[""]=Scope("","::","namespace",[],1)
+ self.function=[]
+
+ def push_scope(self,ns,scope_t,base_classes=[]):
+ name = self.scopes[-1]+"::"+ns
+ if self.verbose>=2:
+ print("-- Starting "+scope_t+" "+name)
+ self.scopes.append(name)
+ self.index[name] = Scope(ns,name,scope_t,base_classes,scope_lineno-1)
+
+ def pop_scope(self):
+ scope = self.scopes.pop()
+ if self.verbose>=2:
+ print("-- Stopping "+scope)
+ return scope
+
+ def add_function(self, fn):
+ fn = str(fn)
+ if self.filter.search(fn):
+ self.index[self.scopes[-1]].function.append((fn, identifier_lineno.get(fn,lexer.lineno-1)))
+ tmp = self.scopes[-1]+"::"+fn
+ if self.verbose==2:
+ print("-- Function declaration "+fn+" "+tmp)
+ elif self.verbose==1:
+ print("-- Function declaration "+tmp)
+
+ def get_functions(self,name,quiet=False):
+ if name == "::":
+ name = ""
+ scope = self.index[name]
+ fns=scope.function
+ for key in scope.base_classes:
+ cname = self.find_class(key,scope)
+ if cname is None:
+ if not quiet:
+ print("Defined classes: ",list(self.index.keys()))
+ print("WARNING: Unknown class "+key)
+ else:
+ fns += self.get_functions(cname,quiet)
+ return fns
+
+ def find_class(self,name,scope):
+ if ':' in name:
+ if name in self.index:
+ return name
+ else:
+ return None
+ tmp = scope.abs_name.split(':')
+ name1 = ":".join(tmp[:-1] + [name])
+ if name1 in self.index:
+ return name1
+ name2 = "::"+name
+ if name2 in self.index:
+ return name2
+ return None
+
+ def __repr__(self):
+ return str(self)
+
+ def is_baseclass(self,cls,base):
+ '''Returns true if base is a base-class of cls'''
+ if cls in self.index:
+ bases = self.index[cls]
+ elif "::"+cls in self.index:
+ bases = self.index["::"+cls]
+ else:
+ return False
+ #raise IOError, "Unknown class "+cls
+ if base in bases.base_classes:
+ return True
+ for name in bases.base_classes:
+ if self.is_baseclass(name,base):
+ return True
+ return False
+
+ def __str__(self):
+ ans=""
+ keys = list(self.index.keys())
+ keys.sort()
+ for key in keys:
+ scope = self.index[key]
+ ans += scope.scope_t+" "+scope.abs_name+"\n"
+ if scope.scope_t == "class":
+ ans += " Base Classes: "+str(scope.base_classes)+"\n"
+ for fn in self.get_functions(scope.abs_name):
+ ans += " "+fn+"\n"
+ else:
+ for fn in scope.function:
+ ans += " "+fn+"\n"
+ return ans
+
+
+def flatten(x):
+ """Flatten nested list"""
+ try:
+ strtypes = str
+ except: # for python3 etc
+ strtypes = (str, bytes)
+
+ result = []
+ for el in x:
+ if hasattr(el, "__iter__") and not isinstance(el, strtypes):
+ result.extend(flatten(el))
+ else:
+ result.append(el)
+ return result
+
+#
+# The lexer (and/or a preprocessor) is expected to identify the following
+#
+# Punctuation:
+#
+#
+literals = "+-*/%^&|~!<>=:()?.\'\"\\@$;,"
+
+#
+reserved = {
+ 'private' : 'PRIVATE',
+ 'protected' : 'PROTECTED',
+ 'public' : 'PUBLIC',
+
+ 'bool' : 'BOOL',
+ 'char' : 'CHAR',
+ 'double' : 'DOUBLE',
+ 'float' : 'FLOAT',
+ 'int' : 'INT',
+ 'long' : 'LONG',
+ 'short' : 'SHORT',
+ 'signed' : 'SIGNED',
+ 'unsigned' : 'UNSIGNED',
+ 'void' : 'VOID',
+ 'wchar_t' : 'WCHAR_T',
+
+ 'class' : 'CLASS',
+ 'enum' : 'ENUM',
+ 'namespace' : 'NAMESPACE',
+ 'struct' : 'STRUCT',
+ 'typename' : 'TYPENAME',
+ 'union' : 'UNION',
+
+ 'const' : 'CONST',
+ 'volatile' : 'VOLATILE',
+
+ 'auto' : 'AUTO',
+ 'explicit' : 'EXPLICIT',
+ 'export' : 'EXPORT',
+ 'extern' : 'EXTERN',
+ '__extension__' : 'EXTENSION',
+ 'friend' : 'FRIEND',
+ 'inline' : 'INLINE',
+ 'mutable' : 'MUTABLE',
+ 'register' : 'REGISTER',
+ 'static' : 'STATIC',
+ 'template' : 'TEMPLATE',
+ 'typedef' : 'TYPEDEF',
+ 'using' : 'USING',
+ 'virtual' : 'VIRTUAL',
+
+ 'asm' : 'ASM',
+ 'break' : 'BREAK',
+ 'case' : 'CASE',
+ 'catch' : 'CATCH',
+ 'const_cast' : 'CONST_CAST',
+ 'continue' : 'CONTINUE',
+ 'default' : 'DEFAULT',
+ 'delete' : 'DELETE',
+ 'do' : 'DO',
+ 'dynamic_cast' : 'DYNAMIC_CAST',
+ 'else' : 'ELSE',
+ 'false' : 'FALSE',
+ 'for' : 'FOR',
+ 'goto' : 'GOTO',
+ 'if' : 'IF',
+ 'new' : 'NEW',
+ 'operator' : 'OPERATOR',
+ 'reinterpret_cast' : 'REINTERPRET_CAST',
+ 'return' : 'RETURN',
+ 'sizeof' : 'SIZEOF',
+ 'static_cast' : 'STATIC_CAST',
+ 'switch' : 'SWITCH',
+ 'this' : 'THIS',
+ 'throw' : 'THROW',
+ 'true' : 'TRUE',
+ 'try' : 'TRY',
+ 'typeid' : 'TYPEID',
+ 'while' : 'WHILE',
+ '"C"' : 'CLiteral',
+ '"C++"' : 'CppLiteral',
+
+ '__attribute__' : 'ATTRIBUTE',
+ '__cdecl__' : 'CDECL',
+ '__typeof' : 'uTYPEOF',
+ 'typeof' : 'TYPEOF',
+
+ 'CXXTEST_STD' : 'CXXTEST_STD'
+}
+
+tokens = [
+ "CharacterLiteral",
+ "FloatingLiteral",
+ "Identifier",
+ "IntegerLiteral",
+ "StringLiteral",
+ "RBRACE",
+ "LBRACE",
+ "RBRACKET",
+ "LBRACKET",
+ "ARROW",
+ "ARROW_STAR",
+ "DEC",
+ "EQ",
+ "GE",
+ "INC",
+ "LE",
+ "LOG_AND",
+ "LOG_OR",
+ "NE",
+ "SHL",
+ "SHR",
+ "ASS_ADD",
+ "ASS_AND",
+ "ASS_DIV",
+ "ASS_MOD",
+ "ASS_MUL",
+ "ASS_OR",
+ "ASS_SHL",
+ "ASS_SHR",
+ "ASS_SUB",
+ "ASS_XOR",
+ "DOT_STAR",
+ "ELLIPSIS",
+ "SCOPE",
+] + list(reserved.values())
+
+t_ignore = " \t\r"
+
+t_LBRACE = r"(\{)|(<%)"
+t_RBRACE = r"(\})|(%>)"
+t_LBRACKET = r"(\[)|(<:)"
+t_RBRACKET = r"(\])|(:>)"
+t_ARROW = r"->"
+t_ARROW_STAR = r"->\*"
+t_DEC = r"--"
+t_EQ = r"=="
+t_GE = r">="
+t_INC = r"\+\+"
+t_LE = r"<="
+t_LOG_AND = r"&&"
+t_LOG_OR = r"\|\|"
+t_NE = r"!="
+t_SHL = r"<<"
+t_SHR = r">>"
+t_ASS_ADD = r"\+="
+t_ASS_AND = r"&="
+t_ASS_DIV = r"/="
+t_ASS_MOD = r"%="
+t_ASS_MUL = r"\*="
+t_ASS_OR = r"\|="
+t_ASS_SHL = r"<<="
+t_ASS_SHR = r">>="
+t_ASS_SUB = r"-="
+t_ASS_XOR = r"^="
+t_DOT_STAR = r"\.\*"
+t_ELLIPSIS = r"\.\.\."
+t_SCOPE = r"::"
+
+# Discard comments
+def t_COMMENT(t):
+ r'(/\*(.|\n)*?\*/)|(//.*?\n)|(\#.*?\n)'
+ t.lexer.lineno += t.value.count("\n")
+
+t_IntegerLiteral = r'(0x[0-9A-F]+)|([0-9]+(L){0,1})'
+t_FloatingLiteral = r"[0-9]+[eE\.\+-]+[eE\.\+\-0-9]+"
+t_CharacterLiteral = r'\'([^\'\\]|\\.)*\''
+#t_StringLiteral = r'"([^"\\]|\\.)*"'
+def t_StringLiteral(t):
+ r'"([^"\\]|\\.)*"'
+ t.type = reserved.get(t.value,'StringLiteral')
+ return t
+
+def t_Identifier(t):
+ r"[a-zA-Z_][a-zA-Z_0-9\.]*"
+ t.type = reserved.get(t.value,'Identifier')
+ return t
+
+
+def t_error(t):
+ print("Illegal character '%s'" % t.value[0])
+ #raise IOError, "Parse error"
+ #t.lexer.skip()
+
+def t_newline(t):
+ r'[\n]+'
+ t.lexer.lineno += len(t.value)
+
+precedence = (
+ ( 'right', 'SHIFT_THERE', 'REDUCE_HERE_MOSTLY', 'SCOPE'),
+ ( 'nonassoc', 'ELSE', 'INC', 'DEC', '+', '-', '*', '&', 'LBRACKET', 'LBRACE', '<', ':', ')')
+ )
+
+start = 'translation_unit'
+
+#
+# The %prec resolves the 14.2-3 ambiguity:
+# Identifier '<' is forced to go through the is-it-a-template-name test
+# All names absorb TEMPLATE with the name, so that no template_test is
+# performed for them. This requires all potential declarations within an
+# expression to perpetuate this policy and thereby guarantee the ultimate
+# coverage of explicit_instantiation.
+#
+# The %prec also resolves a conflict in identifier : which is forced to be a
+# shift of a label for a labeled-statement rather than a reduction for the
+# name of a bit-field or generalised constructor. This is pretty dubious
+# syntactically but correct for all semantic possibilities. The shift is
+# only activated when the ambiguity exists at the start of a statement.
+# In this context a bit-field declaration or constructor definition are not
+# allowed.
+#
+
+def p_identifier(p):
+ '''identifier : Identifier
+ | CXXTEST_STD '(' Identifier ')'
+ '''
+ if p[1][0] in ('t','T','c','d'):
+ identifier_lineno[p[1]] = p.lineno(1)
+ p[0] = p[1]
+
+def p_id(p):
+ '''id : identifier %prec SHIFT_THERE
+ | template_decl
+ | TEMPLATE id
+ '''
+ p[0] = get_rest(p)
+
+def p_global_scope(p):
+ '''global_scope : SCOPE
+ '''
+ p[0] = get_rest(p)
+
+def p_id_scope(p):
+ '''id_scope : id SCOPE'''
+ p[0] = get_rest(p)
+
+def p_id_scope_seq(p):
+ '''id_scope_seq : id_scope
+ | id_scope id_scope_seq
+ '''
+ p[0] = get_rest(p)
+
+#
+# A :: B :: C; is ambiguous How much is type and how much name ?
+# The %prec maximises the (type) length which is the 7.1-2 semantic constraint.
+#
+def p_nested_id(p):
+ '''nested_id : id %prec SHIFT_THERE
+ | id_scope nested_id
+ '''
+ p[0] = get_rest(p)
+
+def p_scoped_id(p):
+ '''scoped_id : nested_id
+ | global_scope nested_id
+ | id_scope_seq
+ | global_scope id_scope_seq
+ '''
+ global scope_lineno
+ scope_lineno = lexer.lineno
+ data = flatten(get_rest(p))
+ if data[0] != None:
+ p[0] = "".join(data)
+
+#
+# destructor_id has to be held back to avoid a conflict with a one's
+# complement as per 5.3.1-9, It gets put back only when scoped or in a
+# declarator_id, which is only used as an explicit member name.
+# Declarations of an unscoped destructor are always parsed as a one's
+# complement.
+#
+def p_destructor_id(p):
+ '''destructor_id : '~' id
+ | TEMPLATE destructor_id
+ '''
+ p[0]=get_rest(p)
+
+#def p_template_id(p):
+# '''template_id : empty
+# | TEMPLATE
+# '''
+# pass
+
+def p_template_decl(p):
+ '''template_decl : identifier '<' nonlgt_seq_opt '>'
+ '''
+ #
+ # WEH: should we include the lt/gt symbols to indicate that this is a
+ # template class? How is that going to be used later???
+ #
+ #p[0] = [p[1] ,"<",">"]
+ p[0] = p[1]
+
+def p_special_function_id(p):
+ '''special_function_id : conversion_function_id
+ | operator_function_id
+ | TEMPLATE special_function_id
+ '''
+ p[0]=get_rest(p)
+
+def p_nested_special_function_id(p):
+ '''nested_special_function_id : special_function_id
+ | id_scope destructor_id
+ | id_scope nested_special_function_id
+ '''
+ p[0]=get_rest(p)
+
+def p_scoped_special_function_id(p):
+ '''scoped_special_function_id : nested_special_function_id
+ | global_scope nested_special_function_id
+ '''
+ p[0]=get_rest(p)
+
+# declarator-id is all names in all scopes, except reserved words
+def p_declarator_id(p):
+ '''declarator_id : scoped_id
+ | scoped_special_function_id
+ | destructor_id
+ '''
+ p[0]=p[1]
+
+#
+# The standard defines pseudo-destructors in terms of type-name, which is
+# class/enum/typedef, of which class-name is covered by a normal destructor.
+# pseudo-destructors are supposed to support ~int() in templates, so the
+# grammar here covers built-in names. Other names are covered by the lack
+# of identifier/type discrimination.
+#
+def p_built_in_type_id(p):
+ '''built_in_type_id : built_in_type_specifier
+ | built_in_type_id built_in_type_specifier
+ '''
+ pass
+
+def p_pseudo_destructor_id(p):
+ '''pseudo_destructor_id : built_in_type_id SCOPE '~' built_in_type_id
+ | '~' built_in_type_id
+ | TEMPLATE pseudo_destructor_id
+ '''
+ pass
+
+def p_nested_pseudo_destructor_id(p):
+ '''nested_pseudo_destructor_id : pseudo_destructor_id
+ | id_scope nested_pseudo_destructor_id
+ '''
+ pass
+
+def p_scoped_pseudo_destructor_id(p):
+ '''scoped_pseudo_destructor_id : nested_pseudo_destructor_id
+ | global_scope scoped_pseudo_destructor_id
+ '''
+ pass
+
+#-------------------------------------------------------------------------------
+# A.2 Lexical conventions
+#-------------------------------------------------------------------------------
+#
+
+def p_literal(p):
+ '''literal : IntegerLiteral
+ | CharacterLiteral
+ | FloatingLiteral
+ | StringLiteral
+ | TRUE
+ | FALSE
+ '''
+ pass
+
+#-------------------------------------------------------------------------------
+# A.3 Basic concepts
+#-------------------------------------------------------------------------------
+def p_translation_unit(p):
+ '''translation_unit : declaration_seq_opt
+ '''
+ pass
+
+#-------------------------------------------------------------------------------
+# A.4 Expressions
+#-------------------------------------------------------------------------------
+#
+# primary_expression covers an arbitrary sequence of all names with the
+# exception of an unscoped destructor, which is parsed as its unary expression
+# which is the correct disambiguation (when ambiguous). This eliminates the
+# traditional A(B) meaning A B ambiguity, since we never have to tack an A
+# onto the front of something that might start with (. The name length got
+# maximised ab initio. The downside is that semantic interpretation must split
+# the names up again.
+#
+# Unification of the declaration and expression syntax means that unary and
+# binary pointer declarator operators:
+# int * * name
+# are parsed as binary and unary arithmetic operators (int) * (*name). Since
+# type information is not used
+# ambiguities resulting from a cast
+# (cast)*(value)
+# are resolved to favour the binary rather than the cast unary to ease AST
+# clean-up. The cast-call ambiguity must be resolved to the cast to ensure
+# that (a)(b)c can be parsed.
+#
+# The problem of the functional cast ambiguity
+# name(arg)
+# as call or declaration is avoided by maximising the name within the parsing
+# kernel. So primary_id_expression picks up
+# extern long int const var = 5;
+# as an assignment to the syntax parsed as "extern long int const var". The
+# presence of two names is parsed so that "extern long into const" is
+# distinguished from "var" considerably simplifying subsequent
+# semantic resolution.
+#
+# The generalised name is a concatenation of potential type-names (scoped
+# identifiers or built-in sequences) plus optionally one of the special names
+# such as an operator-function-id, conversion-function-id or destructor as the
+# final name.
+#
+
+def get_rest(p):
+ return [p[i] for i in range(1, len(p))]
+
+def p_primary_expression(p):
+ '''primary_expression : literal
+ | THIS
+ | suffix_decl_specified_ids
+ | abstract_expression %prec REDUCE_HERE_MOSTLY
+ '''
+ p[0] = get_rest(p)
+
+#
+# Abstract-expression covers the () and [] of abstract-declarators.
+#
+def p_abstract_expression(p):
+ '''abstract_expression : parenthesis_clause
+ | LBRACKET bexpression_opt RBRACKET
+ | TEMPLATE abstract_expression
+ '''
+ pass
+
+def p_postfix_expression(p):
+ '''postfix_expression : primary_expression
+ | postfix_expression parenthesis_clause
+ | postfix_expression LBRACKET bexpression_opt RBRACKET
+ | postfix_expression LBRACKET bexpression_opt RBRACKET attributes
+ | postfix_expression '.' declarator_id
+ | postfix_expression '.' scoped_pseudo_destructor_id
+ | postfix_expression ARROW declarator_id
+ | postfix_expression ARROW scoped_pseudo_destructor_id
+ | postfix_expression INC
+ | postfix_expression DEC
+ | DYNAMIC_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | STATIC_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | REINTERPRET_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | CONST_CAST '<' nonlgt_seq_opt '>' '(' expression ')'
+ | TYPEID parameters_clause
+ '''
+ #print "HERE",str(p[1])
+ p[0] = get_rest(p)
+
+def p_bexpression_opt(p):
+ '''bexpression_opt : empty
+ | bexpression
+ '''
+ pass
+
+def p_bexpression(p):
+ '''bexpression : nonbracket_seq
+ | nonbracket_seq bexpression_seq bexpression_clause nonbracket_seq_opt
+ | bexpression_seq bexpression_clause nonbracket_seq_opt
+ '''
+ pass
+
+def p_bexpression_seq(p):
+ '''bexpression_seq : empty
+ | bexpression_seq bexpression_clause nonbracket_seq_opt
+ '''
+ pass
+
+def p_bexpression_clause(p):
+ '''bexpression_clause : LBRACKET bexpression_opt RBRACKET
+ '''
+ pass
+
+
+
+def p_expression_list_opt(p):
+ '''expression_list_opt : empty
+ | expression_list
+ '''
+ pass
+
+def p_expression_list(p):
+ '''expression_list : assignment_expression
+ | expression_list ',' assignment_expression
+ '''
+ pass
+
+def p_unary_expression(p):
+ '''unary_expression : postfix_expression
+ | INC cast_expression
+ | DEC cast_expression
+ | ptr_operator cast_expression
+ | suffix_decl_specified_scope star_ptr_operator cast_expression
+ | '+' cast_expression
+ | '-' cast_expression
+ | '!' cast_expression
+ | '~' cast_expression
+ | SIZEOF unary_expression
+ | new_expression
+ | global_scope new_expression
+ | delete_expression
+ | global_scope delete_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_delete_expression(p):
+ '''delete_expression : DELETE cast_expression
+ '''
+ pass
+
+def p_new_expression(p):
+ '''new_expression : NEW new_type_id new_initializer_opt
+ | NEW parameters_clause new_type_id new_initializer_opt
+ | NEW parameters_clause
+ | NEW parameters_clause parameters_clause new_initializer_opt
+ '''
+ pass
+
+def p_new_type_id(p):
+ '''new_type_id : type_specifier ptr_operator_seq_opt
+ | type_specifier new_declarator
+ | type_specifier new_type_id
+ '''
+ pass
+
+def p_new_declarator(p):
+ '''new_declarator : ptr_operator new_declarator
+ | direct_new_declarator
+ '''
+ pass
+
+def p_direct_new_declarator(p):
+ '''direct_new_declarator : LBRACKET bexpression_opt RBRACKET
+ | direct_new_declarator LBRACKET bexpression RBRACKET
+ '''
+ pass
+
+def p_new_initializer_opt(p):
+ '''new_initializer_opt : empty
+ | '(' expression_list_opt ')'
+ '''
+ pass
+
+#
+# cast-expression is generalised to support a [] as well as a () prefix. This covers the omission of
+# DELETE[] which when followed by a parenthesised expression was ambiguous. It also covers the gcc
+# indexed array initialisation for free.
+#
+def p_cast_expression(p):
+ '''cast_expression : unary_expression
+ | abstract_expression cast_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_pm_expression(p):
+ '''pm_expression : cast_expression
+ | pm_expression DOT_STAR cast_expression
+ | pm_expression ARROW_STAR cast_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_multiplicative_expression(p):
+ '''multiplicative_expression : pm_expression
+ | multiplicative_expression star_ptr_operator pm_expression
+ | multiplicative_expression '/' pm_expression
+ | multiplicative_expression '%' pm_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_additive_expression(p):
+ '''additive_expression : multiplicative_expression
+ | additive_expression '+' multiplicative_expression
+ | additive_expression '-' multiplicative_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_shift_expression(p):
+ '''shift_expression : additive_expression
+ | shift_expression SHL additive_expression
+ | shift_expression SHR additive_expression
+ '''
+ p[0] = get_rest(p)
+
+# | relational_expression '<' shift_expression
+# | relational_expression '>' shift_expression
+# | relational_expression LE shift_expression
+# | relational_expression GE shift_expression
+def p_relational_expression(p):
+ '''relational_expression : shift_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_equality_expression(p):
+ '''equality_expression : relational_expression
+ | equality_expression EQ relational_expression
+ | equality_expression NE relational_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_and_expression(p):
+ '''and_expression : equality_expression
+ | and_expression '&' equality_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_exclusive_or_expression(p):
+ '''exclusive_or_expression : and_expression
+ | exclusive_or_expression '^' and_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_inclusive_or_expression(p):
+ '''inclusive_or_expression : exclusive_or_expression
+ | inclusive_or_expression '|' exclusive_or_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_logical_and_expression(p):
+ '''logical_and_expression : inclusive_or_expression
+ | logical_and_expression LOG_AND inclusive_or_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_logical_or_expression(p):
+ '''logical_or_expression : logical_and_expression
+ | logical_or_expression LOG_OR logical_and_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_conditional_expression(p):
+ '''conditional_expression : logical_or_expression
+ | logical_or_expression '?' expression ':' assignment_expression
+ '''
+ p[0] = get_rest(p)
+
+
+#
+# assignment-expression is generalised to cover the simple assignment of a braced initializer in order to
+# contribute to the coverage of parameter-declaration and init-declaration.
+#
+# | logical_or_expression assignment_operator assignment_expression
+def p_assignment_expression(p):
+ '''assignment_expression : conditional_expression
+ | logical_or_expression assignment_operator nonsemicolon_seq
+ | logical_or_expression '=' braced_initializer
+ | throw_expression
+ '''
+ p[0]=get_rest(p)
+
+def p_assignment_operator(p):
+ '''assignment_operator : '='
+ | ASS_ADD
+ | ASS_AND
+ | ASS_DIV
+ | ASS_MOD
+ | ASS_MUL
+ | ASS_OR
+ | ASS_SHL
+ | ASS_SHR
+ | ASS_SUB
+ | ASS_XOR
+ '''
+ pass
+
+#
+# expression is widely used and usually single-element, so the reductions are arranged so that a
+# single-element expression is returned as is. Multi-element expressions are parsed as a list that
+# may then behave polymorphically as an element or be compacted to an element.
+#
+
+def p_expression(p):
+ '''expression : assignment_expression
+ | expression_list ',' assignment_expression
+ '''
+ p[0] = get_rest(p)
+
+def p_constant_expression(p):
+ '''constant_expression : conditional_expression
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.5 Statements
+#---------------------------------------------------------------------------------------------------
+# Parsing statements is easy once simple_declaration has been generalised to cover expression_statement.
+#
+#
+# The use of extern here is a hack. The 'extern "C" {}' block gets parsed
+# as a function, so when nested 'extern "C"' declarations exist, they don't
+# work because the block is viewed as a list of statements... :(
+#
+def p_statement(p):
+ '''statement : compound_statement
+ | declaration_statement
+ | try_block
+ | labeled_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ '''
+ pass
+
+def p_compound_statement(p):
+ '''compound_statement : LBRACE statement_seq_opt RBRACE
+ '''
+ pass
+
+def p_statement_seq_opt(p):
+ '''statement_seq_opt : empty
+ | statement_seq_opt statement
+ '''
+ pass
+
+#
+# The dangling else conflict is resolved to the innermost if.
+#
+def p_selection_statement(p):
+ '''selection_statement : IF '(' condition ')' statement %prec SHIFT_THERE
+ | IF '(' condition ')' statement ELSE statement
+ | SWITCH '(' condition ')' statement
+ '''
+ pass
+
+def p_condition_opt(p):
+ '''condition_opt : empty
+ | condition
+ '''
+ pass
+
+def p_condition(p):
+ '''condition : nonparen_seq
+ | nonparen_seq condition_seq parameters_clause nonparen_seq_opt
+ | condition_seq parameters_clause nonparen_seq_opt
+ '''
+ pass
+
+def p_condition_seq(p):
+ '''condition_seq : empty
+ | condition_seq parameters_clause nonparen_seq_opt
+ '''
+ pass
+
+def p_labeled_statement(p):
+ '''labeled_statement : identifier ':' statement
+ | CASE constant_expression ':' statement
+ | DEFAULT ':' statement
+ '''
+ pass
+
+def p_try_block(p):
+ '''try_block : TRY compound_statement handler_seq
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_jump_statement(p):
+ '''jump_statement : BREAK ';'
+ | CONTINUE ';'
+ | RETURN nonsemicolon_seq ';'
+ | GOTO identifier ';'
+ '''
+ pass
+
+def p_iteration_statement(p):
+ '''iteration_statement : WHILE '(' condition ')' statement
+ | DO statement WHILE '(' expression ')' ';'
+ | FOR '(' nonparen_seq_opt ')' statement
+ '''
+ pass
+
+def p_declaration_statement(p):
+ '''declaration_statement : block_declaration
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.6 Declarations
+#---------------------------------------------------------------------------------------------------
+def p_compound_declaration(p):
+ '''compound_declaration : LBRACE declaration_seq_opt RBRACE
+ '''
+ pass
+
+def p_declaration_seq_opt(p):
+ '''declaration_seq_opt : empty
+ | declaration_seq_opt declaration
+ '''
+ pass
+
+def p_declaration(p):
+ '''declaration : block_declaration
+ | function_definition
+ | template_declaration
+ | explicit_specialization
+ | specialised_declaration
+ '''
+ pass
+
+def p_specialised_declaration(p):
+ '''specialised_declaration : linkage_specification
+ | namespace_definition
+ | TEMPLATE specialised_declaration
+ '''
+ pass
+
+def p_block_declaration(p):
+ '''block_declaration : simple_declaration
+ | specialised_block_declaration
+ '''
+ pass
+
+def p_specialised_block_declaration(p):
+ '''specialised_block_declaration : asm_definition
+ | namespace_alias_definition
+ | using_declaration
+ | using_directive
+ | TEMPLATE specialised_block_declaration
+ '''
+ pass
+
+def p_simple_declaration(p):
+ '''simple_declaration : ';'
+ | init_declaration ';'
+ | init_declarations ';'
+ | decl_specifier_prefix simple_declaration
+ '''
+ global _parse_info
+ if len(p) == 3:
+ if p[2] == ";":
+ decl = p[1]
+ else:
+ decl = p[2]
+ if decl is not None:
+ fp = flatten(decl)
+ if len(fp) >= 2 and fp[0] is not None and fp[0]!="operator" and fp[1] == '(':
+ p[0] = fp[0]
+ _parse_info.add_function(fp[0])
+
+#
+# A decl-specifier following a ptr_operator provokes a shift-reduce conflict for * const name which is resolved in favour of the pointer, and implemented by providing versions of decl-specifier guaranteed not to start with a cv_qualifier. decl-specifiers are implemented type-centrically. That is the semantic constraint that there must be a type is exploited to impose structure, but actually eliminate very little syntax. built-in types are multi-name and so need a different policy.
+#
+# non-type decl-specifiers are bound to the left-most type in a decl-specifier-seq, by parsing from the right and attaching suffixes to the right-hand type. Finally residual prefixes attach to the left.
+#
+def p_suffix_built_in_decl_specifier_raw(p):
+ '''suffix_built_in_decl_specifier_raw : built_in_type_specifier
+ | suffix_built_in_decl_specifier_raw built_in_type_specifier
+ | suffix_built_in_decl_specifier_raw decl_specifier_suffix
+ '''
+ pass
+
+def p_suffix_built_in_decl_specifier(p):
+ '''suffix_built_in_decl_specifier : suffix_built_in_decl_specifier_raw
+ | TEMPLATE suffix_built_in_decl_specifier
+ '''
+ pass
+
+# | id_scope_seq
+# | SCOPE id_scope_seq
+def p_suffix_named_decl_specifier(p):
+ '''suffix_named_decl_specifier : scoped_id
+ | elaborate_type_specifier
+ | suffix_named_decl_specifier decl_specifier_suffix
+ '''
+ p[0]=get_rest(p)
+
+def p_suffix_named_decl_specifier_bi(p):
+ '''suffix_named_decl_specifier_bi : suffix_named_decl_specifier
+ | suffix_named_decl_specifier suffix_built_in_decl_specifier_raw
+ '''
+ p[0] = get_rest(p)
+ #print "HERE",get_rest(p)
+
+def p_suffix_named_decl_specifiers(p):
+ '''suffix_named_decl_specifiers : suffix_named_decl_specifier_bi
+ | suffix_named_decl_specifiers suffix_named_decl_specifier_bi
+ '''
+ p[0] = get_rest(p)
+
+def p_suffix_named_decl_specifiers_sf(p):
+ '''suffix_named_decl_specifiers_sf : scoped_special_function_id
+ | suffix_named_decl_specifiers
+ | suffix_named_decl_specifiers scoped_special_function_id
+ '''
+ #print "HERE",get_rest(p)
+ p[0] = get_rest(p)
+
+def p_suffix_decl_specified_ids(p):
+ '''suffix_decl_specified_ids : suffix_built_in_decl_specifier
+ | suffix_built_in_decl_specifier suffix_named_decl_specifiers_sf
+ | suffix_named_decl_specifiers_sf
+ '''
+ if len(p) == 3:
+ p[0] = p[2]
+ else:
+ p[0] = p[1]
+
+def p_suffix_decl_specified_scope(p):
+ '''suffix_decl_specified_scope : suffix_named_decl_specifiers SCOPE
+ | suffix_built_in_decl_specifier suffix_named_decl_specifiers SCOPE
+ | suffix_built_in_decl_specifier SCOPE
+ '''
+ p[0] = get_rest(p)
+
+def p_decl_specifier_affix(p):
+ '''decl_specifier_affix : storage_class_specifier
+ | function_specifier
+ | FRIEND
+ | TYPEDEF
+ | cv_qualifier
+ '''
+ pass
+
+def p_decl_specifier_suffix(p):
+ '''decl_specifier_suffix : decl_specifier_affix
+ '''
+ pass
+
+def p_decl_specifier_prefix(p):
+ '''decl_specifier_prefix : decl_specifier_affix
+ | TEMPLATE decl_specifier_prefix
+ '''
+ pass
+
+def p_storage_class_specifier(p):
+ '''storage_class_specifier : REGISTER
+ | STATIC
+ | MUTABLE
+ | EXTERN %prec SHIFT_THERE
+ | EXTENSION
+ | AUTO
+ '''
+ pass
+
+def p_function_specifier(p):
+ '''function_specifier : EXPLICIT
+ | INLINE
+ | VIRTUAL
+ '''
+ pass
+
+def p_type_specifier(p):
+ '''type_specifier : simple_type_specifier
+ | elaborate_type_specifier
+ | cv_qualifier
+ '''
+ pass
+
+def p_elaborate_type_specifier(p):
+ '''elaborate_type_specifier : class_specifier
+ | enum_specifier
+ | elaborated_type_specifier
+ | TEMPLATE elaborate_type_specifier
+ '''
+ pass
+
+def p_simple_type_specifier(p):
+ '''simple_type_specifier : scoped_id
+ | scoped_id attributes
+ | built_in_type_specifier
+ '''
+ p[0] = p[1]
+
+def p_built_in_type_specifier(p):
+ '''built_in_type_specifier : Xbuilt_in_type_specifier
+ | Xbuilt_in_type_specifier attributes
+ '''
+ pass
+
+def p_attributes(p):
+ '''attributes : attribute
+ | attributes attribute
+ '''
+ pass
+
+def p_attribute(p):
+ '''attribute : ATTRIBUTE '(' parameters_clause ')'
+ '''
+
+def p_Xbuilt_in_type_specifier(p):
+ '''Xbuilt_in_type_specifier : CHAR
+ | WCHAR_T
+ | BOOL
+ | SHORT
+ | INT
+ | LONG
+ | SIGNED
+ | UNSIGNED
+ | FLOAT
+ | DOUBLE
+ | VOID
+ | uTYPEOF parameters_clause
+ | TYPEOF parameters_clause
+ '''
+ pass
+
+#
+# The over-general use of declaration_expression to cover decl-specifier-seq_opt declarator in a function-definition means that
+# class X { };
+# could be a function-definition or a class-specifier.
+# enum X { };
+# could be a function-definition or an enum-specifier.
+# The function-definition is not syntactically valid so resolving the false conflict in favour of the
+# elaborated_type_specifier is correct.
+#
+def p_elaborated_type_specifier(p):
+ '''elaborated_type_specifier : class_key scoped_id %prec SHIFT_THERE
+ | elaborated_enum_specifier
+ | TYPENAME scoped_id
+ '''
+ pass
+
+def p_elaborated_enum_specifier(p):
+ '''elaborated_enum_specifier : ENUM scoped_id %prec SHIFT_THERE
+ '''
+ pass
+
+def p_enum_specifier(p):
+ '''enum_specifier : ENUM scoped_id enumerator_clause
+ | ENUM enumerator_clause
+ '''
+ pass
+
+def p_enumerator_clause(p):
+ '''enumerator_clause : LBRACE enumerator_list_ecarb
+ | LBRACE enumerator_list enumerator_list_ecarb
+ | LBRACE enumerator_list ',' enumerator_definition_ecarb
+ '''
+ pass
+
+def p_enumerator_list_ecarb(p):
+ '''enumerator_list_ecarb : RBRACE
+ '''
+ pass
+
+def p_enumerator_definition_ecarb(p):
+ '''enumerator_definition_ecarb : RBRACE
+ '''
+ pass
+
+def p_enumerator_definition_filler(p):
+ '''enumerator_definition_filler : empty
+ '''
+ pass
+
+def p_enumerator_list_head(p):
+ '''enumerator_list_head : enumerator_definition_filler
+ | enumerator_list ',' enumerator_definition_filler
+ '''
+ pass
+
+def p_enumerator_list(p):
+ '''enumerator_list : enumerator_list_head enumerator_definition
+ '''
+ pass
+
+def p_enumerator_definition(p):
+ '''enumerator_definition : enumerator
+ | enumerator '=' constant_expression
+ '''
+ pass
+
+def p_enumerator(p):
+ '''enumerator : identifier
+ '''
+ pass
+
+def p_namespace_definition(p):
+ '''namespace_definition : NAMESPACE scoped_id push_scope compound_declaration
+ | NAMESPACE push_scope compound_declaration
+ '''
+ global _parse_info
+ scope = _parse_info.pop_scope()
+
+def p_namespace_alias_definition(p):
+ '''namespace_alias_definition : NAMESPACE scoped_id '=' scoped_id ';'
+ '''
+ pass
+
+def p_push_scope(p):
+ '''push_scope : empty'''
+ global _parse_info
+ if p[-2] == "namespace":
+ scope=p[-1]
+ else:
+ scope=""
+ _parse_info.push_scope(scope,"namespace")
+
+def p_using_declaration(p):
+ '''using_declaration : USING declarator_id ';'
+ | USING TYPENAME declarator_id ';'
+ '''
+ pass
+
+def p_using_directive(p):
+ '''using_directive : USING NAMESPACE scoped_id ';'
+ '''
+ pass
+
+# '''asm_definition : ASM '(' StringLiteral ')' ';'
+def p_asm_definition(p):
+ '''asm_definition : ASM '(' nonparen_seq_opt ')' ';'
+ '''
+ pass
+
+def p_linkage_specification(p):
+ '''linkage_specification : EXTERN CLiteral declaration
+ | EXTERN CLiteral compound_declaration
+ | EXTERN CppLiteral declaration
+ | EXTERN CppLiteral compound_declaration
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.7 Declarators
+#---------------------------------------------------------------------------------------------------
+#
+# init-declarator is named init_declaration to reflect the embedded decl-specifier-seq_opt
+#
+
+def p_init_declarations(p):
+ '''init_declarations : assignment_expression ',' init_declaration
+ | init_declarations ',' init_declaration
+ '''
+ p[0]=get_rest(p)
+
+def p_init_declaration(p):
+ '''init_declaration : assignment_expression
+ '''
+ p[0]=get_rest(p)
+
+def p_star_ptr_operator(p):
+ '''star_ptr_operator : '*'
+ | star_ptr_operator cv_qualifier
+ '''
+ pass
+
+def p_nested_ptr_operator(p):
+ '''nested_ptr_operator : star_ptr_operator
+ | id_scope nested_ptr_operator
+ '''
+ pass
+
+def p_ptr_operator(p):
+ '''ptr_operator : '&'
+ | nested_ptr_operator
+ | global_scope nested_ptr_operator
+ '''
+ pass
+
+def p_ptr_operator_seq(p):
+ '''ptr_operator_seq : ptr_operator
+ | ptr_operator ptr_operator_seq
+ '''
+ pass
+
+#
+# Independently coded to localise the shift-reduce conflict: sharing just needs another %prec
+#
+def p_ptr_operator_seq_opt(p):
+ '''ptr_operator_seq_opt : empty %prec SHIFT_THERE
+ | ptr_operator ptr_operator_seq_opt
+ '''
+ pass
+
+def p_cv_qualifier_seq_opt(p):
+ '''cv_qualifier_seq_opt : empty
+ | cv_qualifier_seq_opt cv_qualifier
+ '''
+ pass
+
+# TODO: verify that we should include attributes here
+def p_cv_qualifier(p):
+ '''cv_qualifier : CONST
+ | VOLATILE
+ | attributes
+ '''
+ pass
+
+def p_type_id(p):
+ '''type_id : type_specifier abstract_declarator_opt
+ | type_specifier type_id
+ '''
+ pass
+
+def p_abstract_declarator_opt(p):
+ '''abstract_declarator_opt : empty
+ | ptr_operator abstract_declarator_opt
+ | direct_abstract_declarator
+ '''
+ pass
+
+def p_direct_abstract_declarator_opt(p):
+ '''direct_abstract_declarator_opt : empty
+ | direct_abstract_declarator
+ '''
+ pass
+
+def p_direct_abstract_declarator(p):
+ '''direct_abstract_declarator : direct_abstract_declarator_opt parenthesis_clause
+ | direct_abstract_declarator_opt LBRACKET RBRACKET
+ | direct_abstract_declarator_opt LBRACKET bexpression RBRACKET
+ '''
+ pass
+
+def p_parenthesis_clause(p):
+ '''parenthesis_clause : parameters_clause cv_qualifier_seq_opt
+ | parameters_clause cv_qualifier_seq_opt exception_specification
+ '''
+ p[0] = ['(',')']
+
+def p_parameters_clause(p):
+ '''parameters_clause : '(' condition_opt ')'
+ '''
+ p[0] = ['(',')']
+
+#
+# A typed abstract qualifier such as
+# Class * ...
+# looks like a multiply, so pointers are parsed as their binary operation equivalents that
+# ultimately terminate with a degenerate right hand term.
+#
+def p_abstract_pointer_declaration(p):
+ '''abstract_pointer_declaration : ptr_operator_seq
+ | multiplicative_expression star_ptr_operator ptr_operator_seq_opt
+ '''
+ pass
+
+def p_abstract_parameter_declaration(p):
+ '''abstract_parameter_declaration : abstract_pointer_declaration
+ | and_expression '&'
+ | and_expression '&' abstract_pointer_declaration
+ '''
+ pass
+
+def p_special_parameter_declaration(p):
+ '''special_parameter_declaration : abstract_parameter_declaration
+ | abstract_parameter_declaration '=' assignment_expression
+ | ELLIPSIS
+ '''
+ pass
+
+def p_parameter_declaration(p):
+ '''parameter_declaration : assignment_expression
+ | special_parameter_declaration
+ | decl_specifier_prefix parameter_declaration
+ '''
+ pass
+
+#
+# function_definition includes constructor, destructor, implicit int definitions too. A local destructor is successfully parsed as a function-declaration but the ~ was treated as a unary operator. constructor_head is the prefix ambiguity between a constructor and a member-init-list starting with a bit-field.
+#
+def p_function_definition(p):
+ '''function_definition : ctor_definition
+ | func_definition
+ '''
+ pass
+
+def p_func_definition(p):
+ '''func_definition : assignment_expression function_try_block
+ | assignment_expression function_body
+ | decl_specifier_prefix func_definition
+ '''
+ global _parse_info
+ if p[2] is not None and p[2][0] == '{':
+ decl = flatten(p[1])
+ #print "HERE",decl
+ if decl[-1] == ')':
+ decl=decl[-3]
+ else:
+ decl=decl[-1]
+ p[0] = decl
+ if decl != "operator":
+ _parse_info.add_function(decl)
+ else:
+ p[0] = p[2]
+
+def p_ctor_definition(p):
+ '''ctor_definition : constructor_head function_try_block
+ | constructor_head function_body
+ | decl_specifier_prefix ctor_definition
+ '''
+ if p[2] is None or p[2][0] == "try" or p[2][0] == '{':
+ p[0]=p[1]
+ else:
+ p[0]=p[1]
+
+def p_constructor_head(p):
+ '''constructor_head : bit_field_init_declaration
+ | constructor_head ',' assignment_expression
+ '''
+ p[0]=p[1]
+
+def p_function_try_block(p):
+ '''function_try_block : TRY function_block handler_seq
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+ p[0] = ['try']
+
+def p_function_block(p):
+ '''function_block : ctor_initializer_opt function_body
+ '''
+ pass
+
+def p_function_body(p):
+ '''function_body : LBRACE nonbrace_seq_opt RBRACE
+ '''
+ p[0] = ['{','}']
+
+def p_initializer_clause(p):
+ '''initializer_clause : assignment_expression
+ | braced_initializer
+ '''
+ pass
+
+def p_braced_initializer(p):
+ '''braced_initializer : LBRACE initializer_list RBRACE
+ | LBRACE initializer_list ',' RBRACE
+ | LBRACE RBRACE
+ '''
+ pass
+
+def p_initializer_list(p):
+ '''initializer_list : initializer_clause
+ | initializer_list ',' initializer_clause
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.8 Classes
+#---------------------------------------------------------------------------------------------------
+#
+# An anonymous bit-field declaration may look very like inheritance:
+# const int B = 3;
+# class A : B ;
+# The two usages are too distant to try to create and enforce a common prefix so we have to resort to
+# a parser hack by backtracking. Inheritance is much the most likely so we mark the input stream context
+# and try to parse a base-clause. If we successfully reach a { the base-clause is ok and inheritance was
+# the correct choice so we unmark and continue. If we fail to find the { an error token causes
+# back-tracking to the alternative parse in elaborated_type_specifier which regenerates the : and
+# declares unconditional success.
+#
+
+def p_class_specifier_head(p):
+ '''class_specifier_head : class_key scoped_id ':' base_specifier_list LBRACE
+ | class_key ':' base_specifier_list LBRACE
+ | class_key scoped_id LBRACE
+ | class_key LBRACE
+ '''
+ global _parse_info
+ base_classes=[]
+ if len(p) == 6:
+ scope = p[2]
+ base_classes = p[4]
+ elif len(p) == 4:
+ scope = p[2]
+ elif len(p) == 5:
+ base_classes = p[3]
+ else:
+ scope = ""
+ _parse_info.push_scope(scope,p[1],base_classes)
+
+
+def p_class_key(p):
+ '''class_key : CLASS
+ | STRUCT
+ | UNION
+ '''
+ p[0] = p[1]
+
+def p_class_specifier(p):
+ '''class_specifier : class_specifier_head member_specification_opt RBRACE
+ '''
+ scope = _parse_info.pop_scope()
+
+def p_member_specification_opt(p):
+ '''member_specification_opt : empty
+ | member_specification_opt member_declaration
+ '''
+ pass
+
+def p_member_declaration(p):
+ '''member_declaration : accessibility_specifier
+ | simple_member_declaration
+ | function_definition
+ | using_declaration
+ | template_declaration
+ '''
+ p[0] = get_rest(p)
+ #print "Decl",get_rest(p)
+
+#
+# The generality of constructor names (there need be no parenthesised argument list) means that that
+# name : f(g), h(i)
+# could be the start of a constructor or the start of an anonymous bit-field. An ambiguity is avoided by
+# parsing the ctor-initializer of a function_definition as a bit-field.
+#
+def p_simple_member_declaration(p):
+ '''simple_member_declaration : ';'
+ | assignment_expression ';'
+ | constructor_head ';'
+ | member_init_declarations ';'
+ | decl_specifier_prefix simple_member_declaration
+ '''
+ global _parse_info
+ decl = flatten(get_rest(p))
+ if len(decl) >= 4 and decl[-3] == "(":
+ _parse_info.add_function(decl[-4])
+
+def p_member_init_declarations(p):
+ '''member_init_declarations : assignment_expression ',' member_init_declaration
+ | constructor_head ',' bit_field_init_declaration
+ | member_init_declarations ',' member_init_declaration
+ '''
+ pass
+
+def p_member_init_declaration(p):
+ '''member_init_declaration : assignment_expression
+ | bit_field_init_declaration
+ '''
+ pass
+
+def p_accessibility_specifier(p):
+ '''accessibility_specifier : access_specifier ':'
+ '''
+ pass
+
+def p_bit_field_declaration(p):
+ '''bit_field_declaration : assignment_expression ':' bit_field_width
+ | ':' bit_field_width
+ '''
+ if len(p) == 4:
+ p[0]=p[1]
+
+def p_bit_field_width(p):
+ '''bit_field_width : logical_or_expression
+ | logical_or_expression '?' bit_field_width ':' bit_field_width
+ '''
+ pass
+
+def p_bit_field_init_declaration(p):
+ '''bit_field_init_declaration : bit_field_declaration
+ | bit_field_declaration '=' initializer_clause
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.9 Derived classes
+#---------------------------------------------------------------------------------------------------
+def p_base_specifier_list(p):
+ '''base_specifier_list : base_specifier
+ | base_specifier_list ',' base_specifier
+ '''
+ if len(p) == 2:
+ p[0] = [p[1]]
+ else:
+ p[0] = p[1]+[p[3]]
+
+def p_base_specifier(p):
+ '''base_specifier : scoped_id
+ | access_specifier base_specifier
+ | VIRTUAL base_specifier
+ '''
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = p[2]
+
+def p_access_specifier(p):
+ '''access_specifier : PRIVATE
+ | PROTECTED
+ | PUBLIC
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.10 Special member functions
+#---------------------------------------------------------------------------------------------------
+def p_conversion_function_id(p):
+ '''conversion_function_id : OPERATOR conversion_type_id
+ '''
+ p[0] = ['operator']
+
+def p_conversion_type_id(p):
+ '''conversion_type_id : type_specifier ptr_operator_seq_opt
+ | type_specifier conversion_type_id
+ '''
+ pass
+
+#
+# Ctor-initialisers can look like a bit field declaration, given the generalisation of names:
+# Class(Type) : m1(1), m2(2) { }
+# NonClass(bit_field) : int(2), second_variable, ...
+# The grammar below is used within a function_try_block or function_definition.
+# See simple_member_declaration for use in normal member function_definition.
+#
+def p_ctor_initializer_opt(p):
+ '''ctor_initializer_opt : empty
+ | ctor_initializer
+ '''
+ pass
+
+def p_ctor_initializer(p):
+ '''ctor_initializer : ':' mem_initializer_list
+ '''
+ pass
+
+def p_mem_initializer_list(p):
+ '''mem_initializer_list : mem_initializer
+ | mem_initializer_list_head mem_initializer
+ '''
+ pass
+
+def p_mem_initializer_list_head(p):
+ '''mem_initializer_list_head : mem_initializer_list ','
+ '''
+ pass
+
+def p_mem_initializer(p):
+ '''mem_initializer : mem_initializer_id '(' expression_list_opt ')'
+ '''
+ pass
+
+def p_mem_initializer_id(p):
+ '''mem_initializer_id : scoped_id
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.11 Overloading
+#---------------------------------------------------------------------------------------------------
+
+def p_operator_function_id(p):
+ '''operator_function_id : OPERATOR operator
+ | OPERATOR '(' ')'
+ | OPERATOR LBRACKET RBRACKET
+ | OPERATOR '<'
+ | OPERATOR '>'
+ | OPERATOR operator '<' nonlgt_seq_opt '>'
+ '''
+ p[0] = ["operator"]
+
+#
+# It is not clear from the ANSI standard whether spaces are permitted in delete[]. If not then it can
+# be recognised and returned as DELETE_ARRAY by the lexer. Assuming spaces are permitted there is an
+# ambiguity created by the over generalised nature of expressions. operator new is a valid delarator-id
+# which we may have an undimensioned array of. Semantic rubbish, but syntactically valid. Since the
+# array form is covered by the declarator consideration we can exclude the operator here. The need
+# for a semantic rescue can be eliminated at the expense of a couple of shift-reduce conflicts by
+# removing the comments on the next four lines.
+#
+def p_operator(p):
+ '''operator : NEW
+ | DELETE
+ | '+'
+ | '-'
+ | '*'
+ | '/'
+ | '%'
+ | '^'
+ | '&'
+ | '|'
+ | '~'
+ | '!'
+ | '='
+ | ASS_ADD
+ | ASS_SUB
+ | ASS_MUL
+ | ASS_DIV
+ | ASS_MOD
+ | ASS_XOR
+ | ASS_AND
+ | ASS_OR
+ | SHL
+ | SHR
+ | ASS_SHR
+ | ASS_SHL
+ | EQ
+ | NE
+ | LE
+ | GE
+ | LOG_AND
+ | LOG_OR
+ | INC
+ | DEC
+ | ','
+ | ARROW_STAR
+ | ARROW
+ '''
+ p[0]=p[1]
+
+# | IF
+# | SWITCH
+# | WHILE
+# | FOR
+# | DO
+def p_reserved(p):
+ '''reserved : PRIVATE
+ | CLiteral
+ | CppLiteral
+ | IF
+ | SWITCH
+ | WHILE
+ | FOR
+ | DO
+ | PROTECTED
+ | PUBLIC
+ | BOOL
+ | CHAR
+ | DOUBLE
+ | FLOAT
+ | INT
+ | LONG
+ | SHORT
+ | SIGNED
+ | UNSIGNED
+ | VOID
+ | WCHAR_T
+ | CLASS
+ | ENUM
+ | NAMESPACE
+ | STRUCT
+ | TYPENAME
+ | UNION
+ | CONST
+ | VOLATILE
+ | AUTO
+ | EXPLICIT
+ | EXPORT
+ | EXTERN
+ | FRIEND
+ | INLINE
+ | MUTABLE
+ | REGISTER
+ | STATIC
+ | TEMPLATE
+ | TYPEDEF
+ | USING
+ | VIRTUAL
+ | ASM
+ | BREAK
+ | CASE
+ | CATCH
+ | CONST_CAST
+ | CONTINUE
+ | DEFAULT
+ | DYNAMIC_CAST
+ | ELSE
+ | FALSE
+ | GOTO
+ | OPERATOR
+ | REINTERPRET_CAST
+ | RETURN
+ | SIZEOF
+ | STATIC_CAST
+ | THIS
+ | THROW
+ | TRUE
+ | TRY
+ | TYPEID
+ | ATTRIBUTE
+ | CDECL
+ | TYPEOF
+ | uTYPEOF
+ '''
+ if p[1] in ('try', 'catch', 'throw'):
+ global noExceptionLogic
+ noExceptionLogic=False
+
+#---------------------------------------------------------------------------------------------------
+# A.12 Templates
+#---------------------------------------------------------------------------------------------------
+def p_template_declaration(p):
+ '''template_declaration : template_parameter_clause declaration
+ | EXPORT template_declaration
+ '''
+ pass
+
+def p_template_parameter_clause(p):
+ '''template_parameter_clause : TEMPLATE '<' nonlgt_seq_opt '>'
+ '''
+ pass
+
+#
+# Generalised naming makes identifier a valid declaration, so TEMPLATE identifier is too.
+# The TEMPLATE prefix is therefore folded into all names, parenthesis_clause and decl_specifier_prefix.
+#
+# explicit_instantiation: TEMPLATE declaration
+#
+def p_explicit_specialization(p):
+ '''explicit_specialization : TEMPLATE '<' '>' declaration
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# A.13 Exception Handling
+#---------------------------------------------------------------------------------------------------
+def p_handler_seq(p):
+ '''handler_seq : handler
+ | handler handler_seq
+ '''
+ pass
+
+def p_handler(p):
+ '''handler : CATCH '(' exception_declaration ')' compound_statement
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_exception_declaration(p):
+ '''exception_declaration : parameter_declaration
+ '''
+ pass
+
+def p_throw_expression(p):
+ '''throw_expression : THROW
+ | THROW assignment_expression
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_exception_specification(p):
+ '''exception_specification : THROW '(' ')'
+ | THROW '(' type_id_list ')'
+ '''
+ global noExceptionLogic
+ noExceptionLogic=False
+
+def p_type_id_list(p):
+ '''type_id_list : type_id
+ | type_id_list ',' type_id
+ '''
+ pass
+
+#---------------------------------------------------------------------------------------------------
+# Misc productions
+#---------------------------------------------------------------------------------------------------
+def p_nonsemicolon_seq(p):
+ '''nonsemicolon_seq : empty
+ | nonsemicolon_seq nonsemicolon
+ '''
+ pass
+
+def p_nonsemicolon(p):
+ '''nonsemicolon : misc
+ | '('
+ | ')'
+ | '<'
+ | '>'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonparen_seq_opt(p):
+ '''nonparen_seq_opt : empty
+ | nonparen_seq_opt nonparen
+ '''
+ pass
+
+def p_nonparen_seq(p):
+ '''nonparen_seq : nonparen
+ | nonparen_seq nonparen
+ '''
+ pass
+
+def p_nonparen(p):
+ '''nonparen : misc
+ | '<'
+ | '>'
+ | ';'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonbracket_seq_opt(p):
+ '''nonbracket_seq_opt : empty
+ | nonbracket_seq_opt nonbracket
+ '''
+ pass
+
+def p_nonbracket_seq(p):
+ '''nonbracket_seq : nonbracket
+ | nonbracket_seq nonbracket
+ '''
+ pass
+
+def p_nonbracket(p):
+ '''nonbracket : misc
+ | '<'
+ | '>'
+ | '('
+ | ')'
+ | ';'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonbrace_seq_opt(p):
+ '''nonbrace_seq_opt : empty
+ | nonbrace_seq_opt nonbrace
+ '''
+ pass
+
+def p_nonbrace(p):
+ '''nonbrace : misc
+ | '<'
+ | '>'
+ | '('
+ | ')'
+ | ';'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | LBRACE nonbrace_seq_opt RBRACE
+ '''
+ pass
+
+def p_nonlgt_seq_opt(p):
+ '''nonlgt_seq_opt : empty
+ | nonlgt_seq_opt nonlgt
+ '''
+ pass
+
+def p_nonlgt(p):
+ '''nonlgt : misc
+ | '('
+ | ')'
+ | LBRACKET nonbracket_seq_opt RBRACKET
+ | '<' nonlgt_seq_opt '>'
+ | ';'
+ '''
+ pass
+
+def p_misc(p):
+ '''misc : operator
+ | identifier
+ | IntegerLiteral
+ | CharacterLiteral
+ | FloatingLiteral
+ | StringLiteral
+ | reserved
+ | '?'
+ | ':'
+ | '.'
+ | SCOPE
+ | ELLIPSIS
+ | EXTENSION
+ '''
+ pass
+
+def p_empty(p):
+ '''empty : '''
+ pass
+
+
+
+#
+# Compute column.
+# input is the input text string
+# token is a token instance
+#
+def _find_column(input,token):
+ ''' TODO '''
+ i = token.lexpos
+ while i > 0:
+ if input[i] == '\n': break
+ i -= 1
+ column = (token.lexpos - i)+1
+ return column
+
+def p_error(p):
+ if p is None:
+ tmp = "Syntax error at end of file."
+ else:
+ tmp = "Syntax error at token "
+ if p.type is "":
+ tmp = tmp + "''"
+ else:
+ tmp = tmp + str(p.type)
+ tmp = tmp + " with value '"+str(p.value)+"'"
+ tmp = tmp + " in line " + str(lexer.lineno-1)
+ tmp = tmp + " at column "+str(_find_column(_parsedata,p))
+ raise IOError( tmp )
+
+
+
+#
+# The function that performs the parsing
+#
+def parse_cpp(data=None, filename=None, debug=0, optimize=0, verbose=False, func_filter=None):
+ #
+ # Reset global data
+ #
+ global lexer
+ lexer = None
+ global scope_lineno
+ scope_lineno = 0
+ global indentifier_lineno
+ identifier_lineno = {}
+ global _parse_info
+ _parse_info=None
+ global _parsedata
+ _parsedata=None
+ global noExceptionLogic
+ noExceptionLogic = True
+ #
+ if debug > 0:
+ print("Debugging parse_cpp!")
+ #
+ # Always remove the parser.out file, which is generated to create debugging
+ #
+ if os.path.exists("parser.out"):
+ os.remove("parser.out")
+ #
+ # Remove the parsetab.py* files. These apparently need to be removed
+ # to ensure the creation of a parser.out file.
+ #
+ if os.path.exists("parsetab.py"):
+ os.remove("parsetab.py")
+ if os.path.exists("parsetab.pyc"):
+ os.remove("parsetab.pyc")
+ global debugging
+ debugging=True
+ #
+ # Build lexer
+ #
+ lexer = lex.lex()
+ #
+ # Initialize parse object
+ #
+ _parse_info = CppInfo(filter=func_filter)
+ _parse_info.verbose=verbose
+ #
+ # Build yaccer
+ #
+ write_table = not os.path.exists("parsetab.py")
+ yacc.yacc(debug=debug, optimize=optimize, write_tables=write_table)
+ #
+ # Parse the file
+ #
+ if not data is None:
+ _parsedata=data
+ ply_init(_parsedata)
+ yacc.parse(data,debug=debug)
+ elif not filename is None:
+ f = open(filename)
+ data = f.read()
+ f.close()
+ _parsedata=data
+ ply_init(_parsedata)
+ yacc.parse(data, debug=debug)
+ else:
+ return None
+ #
+ if not noExceptionLogic:
+ _parse_info.noExceptionLogic = False
+ else:
+ for key in identifier_lineno:
+ if 'ASSERT_THROWS' in key:
+ _parse_info.noExceptionLogic = False
+ break
+ _parse_info.noExceptionLogic = True
+ #
+ return _parse_info
+
+
+
+import sys
+
+if __name__ == '__main__': #pragma: no cover
+ #
+ # This MAIN routine parses a sequence of files provided at the command
+ # line. If '-v' is included, then a verbose parsing output is
+ # generated.
+ #
+ for arg in sys.argv[1:]:
+ if arg == "-v":
+ continue
+ print("Parsing file '"+arg+"'")
+ if '-v' in sys.argv:
+ parse_cpp(filename=arg,debug=2,verbose=2)
+ else:
+ parse_cpp(filename=arg,verbose=2)
+ #
+ # Print the _parse_info object summary for this file.
+ # This illustrates how class inheritance can be used to
+ # deduce class members.
+ #
+ print(str(_parse_info))
+
diff --git a/third-party/cxxtest/python/python3/cxxtest/cxxtest_fog.py b/third-party/cxxtest/python/python3/cxxtest/cxxtest_fog.py
new file mode 100644
index 00000000..45dc9406
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/cxxtest_fog.py
@@ -0,0 +1,99 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+#
+# TODO: add line number info
+# TODO: add test function names
+#
+
+
+
+import sys
+import re
+from .cxxtest_misc import abort
+from . import cxx_parser
+import re
+
+def cstr( str ):
+ '''Convert a string to its C representation'''
+ return '"' + re.sub('\\\\', '\\\\\\\\', str ) + '"'
+
+def scanInputFiles(files, _options):
+ '''Scan all input files for test suites'''
+ suites=[]
+ for file in files:
+ try:
+ print("Parsing file "+file, end=' ')
+ sys.stdout.flush()
+ parse_info = cxx_parser.parse_cpp(filename=file,optimize=1)
+ except IOError as err:
+ print(" error.")
+ print(str(err))
+ continue
+ print("done.")
+ sys.stdout.flush()
+ #
+ # WEH: see if it really makes sense to use parse information to
+ # initialize this data. I don't think so...
+ #
+ _options.haveStandardLibrary=1
+ if not parse_info.noExceptionLogic:
+ _options.haveExceptionHandling=1
+ #
+ keys = list(parse_info.index.keys())
+ tpat = re.compile("[Tt][Ee][Ss][Tt]")
+ for key in keys:
+ if parse_info.index[key].scope_t == "class" and parse_info.is_baseclass(key,"CxxTest::TestSuite"):
+ name=parse_info.index[key].name
+ if key.startswith('::'):
+ fullname = key[2:]
+ else:
+ fullname = key
+ suite = {
+ 'fullname' : fullname,
+ 'name' : name,
+ 'file' : file,
+ 'cfile' : cstr(file),
+ 'line' : str(parse_info.index[key].lineno),
+ 'generated' : 0,
+ 'object' : 'suite_%s' % fullname.replace('::','_'),
+ 'dobject' : 'suiteDescription_%s' % fullname.replace('::','_'),
+ 'tlist' : 'Tests_%s' % fullname.replace('::','_'),
+ 'tests' : [],
+ 'lines' : [] }
+ for fn in parse_info.get_functions(key,quiet=True):
+ tname = fn[0]
+ lineno = str(fn[1])
+ if tname.startswith('createSuite'):
+ # Indicate that we're using a dynamically generated test suite
+ suite['create'] = str(lineno) # (unknown line)
+ if tname.startswith('destroySuite'):
+ # Indicate that we're using a dynamically generated test suite
+ suite['destroy'] = str(lineno) # (unknown line)
+ if not tpat.match(tname):
+ # Skip non-test methods
+ continue
+ test = { 'name' : tname,
+ 'suite' : suite,
+ 'class' : 'TestDescription_suite_%s_%s' % (suite['fullname'].replace('::','_'), tname),
+ 'object' : 'testDescription_suite_%s_%s' % (suite['fullname'].replace('::','_'), tname),
+ 'line' : lineno,
+ }
+ suite['tests'].append(test)
+ suites.append(suite)
+
+ if not _options.root:
+ ntests = 0
+ for suite in suites:
+ ntests += len(suite['tests'])
+ if ntests == 0:
+ abort( 'No tests defined' )
+ #
+ return [_options, suites]
+
diff --git a/third-party/cxxtest/python/python3/cxxtest/cxxtest_misc.py b/third-party/cxxtest/python/python3/cxxtest/cxxtest_misc.py
new file mode 100644
index 00000000..c9d337e2
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/cxxtest_misc.py
@@ -0,0 +1,78 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+import sys
+import os
+
+def abort( problem ):
+ '''Print error message and exit'''
+ sys.stderr.write( '\n' )
+ sys.stderr.write( problem )
+ sys.stderr.write( '\n\n' )
+ sys.exit(2)
+
+if sys.version_info < (2,6): #pragma: no cover
+ def resolve_symlinks(orig_path):
+ drive,tmp = os.path.splitdrive(os.path.normpath(orig_path))
+ if not drive:
+ drive = os.path.sep
+ parts = tmp.split(os.path.sep)
+ actual_path = [drive]
+ while parts:
+ actual_path.append(parts.pop(0))
+ if not os.path.islink(os.path.join(*actual_path)):
+ continue
+ actual_path[-1] = os.readlink(os.path.join(*actual_path))
+ tmp_drive, tmp_path = os.path.splitdrive(
+ dereference_path(os.path.join(*actual_path)) )
+ if tmp_drive:
+ drive = tmp_drive
+ actual_path = [drive] + tmp_path.split(os.path.sep)
+ return os.path.join(*actual_path)
+
+ def relpath(path, start=None):
+ """Return a relative version of a path.
+ (provides compatibility with Python < 2.6)"""
+ # Some notes on implementation:
+ # - We rely on resolve_symlinks to correctly resolve any symbolic
+ # links that may be present in the paths
+ # - The explicit handling od the drive name is critical for proper
+ # function on Windows (because os.path.join('c:','foo') yields
+ # "c:foo"!).
+ if not start:
+ start = os.getcwd()
+ ref_drive, ref_path = os.path.splitdrive(
+ resolve_symlinks(os.path.abspath(start)) )
+ if not ref_drive:
+ ref_drive = os.path.sep
+ start = [ref_drive] + ref_path.split(os.path.sep)
+ while '' in start:
+ start.remove('')
+
+ pth_drive, pth_path = os.path.splitdrive(
+ resolve_symlinks(os.path.abspath(path)) )
+ if not pth_drive:
+ pth_drive = os.path.sep
+ path = [pth_drive] + pth_path.split(os.path.sep)
+ while '' in path:
+ path.remove('')
+
+ i = 0
+ max = min(len(path), len(start))
+ while i < max and path[i] == start[i]:
+ i += 1
+
+ if i < 2:
+ return os.path.join(*path)
+ else:
+ rel = ['..']*(len(start)-i) + path[i:]
+ if rel:
+ return os.path.join(*rel)
+ else:
+ return '.'
diff --git a/third-party/cxxtest/python/python3/cxxtest/cxxtest_parser.py b/third-party/cxxtest/python/python3/cxxtest/cxxtest_parser.py
new file mode 100644
index 00000000..a4313a61
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/cxxtest_parser.py
@@ -0,0 +1,254 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+
+
+import codecs
+import re
+import sys
+from cxxtest.cxxtest_misc import abort
+
+# Global variables
+suites = []
+suite = None
+inBlock = 0
+options=None
+
+def scanInputFiles(files, _options):
+ '''Scan all input files for test suites'''
+ #
+ # Reset global data
+ #
+ global options
+ options=_options
+ global suites
+ suites = []
+ global suite
+ suite = None
+ global inBlock
+ inBlock = 0
+ #
+ for file in files:
+ scanInputFile(file)
+ if len(suites) is 0 and not options.root:
+ abort( 'No tests defined' )
+ return [options,suites]
+
+lineCont_re = re.compile('(.*)\\\s*$')
+def scanInputFile(fileName):
+ '''Scan single input file for test suites'''
+ # mode 'rb' is problematic in python3 - byte arrays don't behave the same as
+ # strings.
+ # As far as the choice of the default encoding: utf-8 chews through
+ # everything that the previous ascii codec could, plus most of new code.
+ # TODO: figure out how to do this properly - like autodetect encoding from
+ # file header.
+ file = codecs.open(fileName, mode='r', encoding='utf-8')
+ prev = ""
+ lineNo = 0
+ contNo = 0
+ while 1:
+ try:
+ line = file.readline()
+ except UnicodeDecodeError:
+ sys.stderr.write("Could not decode unicode character at %s:%s\n" % (fileName, lineNo + 1));
+ raise
+ if not line:
+ break
+ lineNo += 1
+
+ m = lineCont_re.match(line)
+ if m:
+ prev += m.group(1) + " "
+ contNo += 1
+ else:
+ scanInputLine( fileName, lineNo - contNo, prev + line )
+ contNo = 0
+ prev = ""
+ if contNo:
+ scanInputLine( fileName, lineNo - contNo, prev + line )
+
+ closeSuite()
+ file.close()
+
+def scanInputLine( fileName, lineNo, line ):
+ '''Scan single input line for interesting stuff'''
+ scanLineForExceptionHandling( line )
+ scanLineForStandardLibrary( line )
+
+ scanLineForSuiteStart( fileName, lineNo, line )
+
+ global suite
+ if suite:
+ scanLineInsideSuite( suite, lineNo, line )
+
+def scanLineInsideSuite( suite, lineNo, line ):
+ '''Analyze line which is part of a suite'''
+ global inBlock
+ if lineBelongsToSuite( suite, lineNo, line ):
+ scanLineForTest( suite, lineNo, line )
+ scanLineForCreate( suite, lineNo, line )
+ scanLineForDestroy( suite, lineNo, line )
+
+def lineBelongsToSuite( suite, lineNo, line ):
+ '''Returns whether current line is part of the current suite.
+ This can be false when we are in a generated suite outside of CXXTEST_CODE() blocks
+ If the suite is generated, adds the line to the list of lines'''
+ if not suite['generated']:
+ return 1
+
+ global inBlock
+ if not inBlock:
+ inBlock = lineStartsBlock( line )
+ if inBlock:
+ inBlock = addLineToBlock( suite, lineNo, line )
+ return inBlock
+
+
+std_re = re.compile( r"\b(std\s*::|CXXTEST_STD|using\s+namespace\s+std\b|^\s*\#\s*include\s+<[a-z0-9]+>)" )
+def scanLineForStandardLibrary( line ):
+ '''Check if current line uses standard library'''
+ global options
+ if not options.haveStandardLibrary and std_re.search(line):
+ if not options.noStandardLibrary:
+ options.haveStandardLibrary = 1
+
+exception_re = re.compile( r"\b(throw|try|catch|TSM?_ASSERT_THROWS[A-Z_]*)\b" )
+def scanLineForExceptionHandling( line ):
+ '''Check if current line uses exception handling'''
+ global options
+ if not options.haveExceptionHandling and exception_re.search(line):
+ if not options.noExceptionHandling:
+ options.haveExceptionHandling = 1
+
+classdef = '(?:::\s*)?(?:\w+\s*::\s*)*\w+'
+baseclassdef = '(?:public|private|protected)\s+%s' % (classdef,)
+general_suite = r"\bclass\s+(%s)\s*:(?:\s*%s\s*,)*\s*public\s+" \
+ % (classdef, baseclassdef,)
+testsuite = '(?:(?:::)?\s*CxxTest\s*::\s*)?TestSuite'
+suites_re = { re.compile( general_suite + testsuite ) : None }
+generatedSuite_re = re.compile( r'\bCXXTEST_SUITE\s*\(\s*(\w*)\s*\)' )
+def scanLineForSuiteStart( fileName, lineNo, line ):
+ '''Check if current line starts a new test suite'''
+ for i in list(suites_re.items()):
+ m = i[0].search( line )
+ if m:
+ suite = startSuite( m.group(1), fileName, lineNo, 0 )
+ if i[1] is not None:
+ for test in i[1]['tests']:
+ addTest(suite, test['name'], test['line'])
+ break
+ m = generatedSuite_re.search( line )
+ if m:
+ sys.stdout.write( "%s:%s: Warning: Inline test suites are deprecated.\n" % (fileName, lineNo) )
+ startSuite( m.group(1), fileName, lineNo, 1 )
+
+def startSuite( name, file, line, generated ):
+ '''Start scanning a new suite'''
+ global suite
+ closeSuite()
+ object_name = name.replace(':',"_")
+ suite = { 'fullname' : name,
+ 'name' : name,
+ 'file' : file,
+ 'cfile' : cstr(file),
+ 'line' : line,
+ 'generated' : generated,
+ 'object' : 'suite_%s' % object_name,
+ 'dobject' : 'suiteDescription_%s' % object_name,
+ 'tlist' : 'Tests_%s' % object_name,
+ 'tests' : [],
+ 'lines' : [] }
+ suites_re[re.compile( general_suite + name )] = suite
+ return suite
+
+def lineStartsBlock( line ):
+ '''Check if current line starts a new CXXTEST_CODE() block'''
+ return re.search( r'\bCXXTEST_CODE\s*\(', line ) is not None
+
+test_re = re.compile( r'^([^/]|/[^/])*\bvoid\s+([Tt]est\w+)\s*\(\s*(void)?\s*\)' )
+def scanLineForTest( suite, lineNo, line ):
+ '''Check if current line starts a test'''
+ m = test_re.search( line )
+ if m:
+ addTest( suite, m.group(2), lineNo )
+
+def addTest( suite, name, line ):
+ '''Add a test function to the current suite'''
+ test = { 'name' : name,
+ 'suite' : suite,
+ 'class' : 'TestDescription_%s_%s' % (suite['object'], name),
+ 'object' : 'testDescription_%s_%s' % (suite['object'], name),
+ 'line' : line,
+ }
+ suite['tests'].append( test )
+
+def addLineToBlock( suite, lineNo, line ):
+ '''Append the line to the current CXXTEST_CODE() block'''
+ line = fixBlockLine( suite, lineNo, line )
+ line = re.sub( r'^.*\{\{', '', line )
+
+ e = re.search( r'\}\}', line )
+ if e:
+ line = line[:e.start()]
+ suite['lines'].append( line )
+ return e is None
+
+def fixBlockLine( suite, lineNo, line):
+ '''Change all [E]TS_ macros used in a line to _[E]TS_ macros with the correct file/line'''
+ return re.sub( r'\b(E?TSM?_(ASSERT[A-Z_]*|FAIL))\s*\(',
+ r'_\1(%s,%s,' % (suite['cfile'], lineNo),
+ line, 0 )
+
+create_re = re.compile( r'\bstatic\s+\w+\s*\*\s*createSuite\s*\(\s*(void)?\s*\)' )
+def scanLineForCreate( suite, lineNo, line ):
+ '''Check if current line defines a createSuite() function'''
+ if create_re.search( line ):
+ addSuiteCreateDestroy( suite, 'create', lineNo )
+
+destroy_re = re.compile( r'\bstatic\s+void\s+destroySuite\s*\(\s*\w+\s*\*\s*\w*\s*\)' )
+def scanLineForDestroy( suite, lineNo, line ):
+ '''Check if current line defines a destroySuite() function'''
+ if destroy_re.search( line ):
+ addSuiteCreateDestroy( suite, 'destroy', lineNo )
+
+def cstr( s ):
+ '''Convert a string to its C representation'''
+ return '"' + s.replace( '\\', '\\\\' ) + '"'
+
+
+def addSuiteCreateDestroy( suite, which, line ):
+ '''Add createSuite()/destroySuite() to current suite'''
+ if which in suite:
+ abort( '%s:%s: %sSuite() already declared' % ( suite['file'], str(line), which ) )
+ suite[which] = line
+
+def closeSuite():
+ '''Close current suite and add it to the list if valid'''
+ global suite
+ if suite is not None:
+ if len(suite['tests']) is not 0:
+ verifySuite(suite)
+ rememberSuite(suite)
+ suite = None
+
+def verifySuite(suite):
+ '''Verify current suite is legal'''
+ if 'create' in suite and 'destroy' not in suite:
+ abort( '%s:%s: Suite %s has createSuite() but no destroySuite()' %
+ (suite['file'], suite['create'], suite['name']) )
+ elif 'destroy' in suite and 'create' not in suite:
+ abort( '%s:%s: Suite %s has destroySuite() but no createSuite()' %
+ (suite['file'], suite['destroy'], suite['name']) )
+
+def rememberSuite(suite):
+ '''Add current suite to list'''
+ global suites
+ suites.append( suite )
+
diff --git a/third-party/cxxtest/python/python3/cxxtest/cxxtestgen.py b/third-party/cxxtest/python/python3/cxxtest/cxxtestgen.py
new file mode 100644
index 00000000..8a5b84c4
--- /dev/null
+++ b/third-party/cxxtest/python/python3/cxxtest/cxxtestgen.py
@@ -0,0 +1,630 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+# vim: fileencoding=utf-8
+
+
+# the above import important for forward-compatibility with python3,
+# which is already the default in archlinux!
+
+__all__ = ['main', 'create_manpage']
+
+from . import __release__
+import os
+import sys
+import re
+import glob
+from optparse import OptionParser
+from . import cxxtest_parser
+from string import Template
+
+try:
+ from . import cxxtest_fog
+ imported_fog=True
+except ImportError:
+ imported_fog=False
+
+from .cxxtest_misc import abort
+
+try:
+ from os.path import relpath
+except ImportError:
+ from .cxxtest_misc import relpath
+
+# Global data is initialized by main()
+options = []
+suites = []
+wrotePreamble = 0
+wroteWorld = 0
+lastIncluded = ''
+
+
+def main(args=sys.argv, catch=False):
+ '''The main program'''
+ #
+ # Reset global state
+ #
+ global wrotePreamble
+ wrotePreamble=0
+ global wroteWorld
+ wroteWorld=0
+ global lastIncluded
+ lastIncluded = ''
+ global suites
+ suites = []
+ global options
+ options = []
+ #
+ try:
+ files = parseCommandline(args)
+ if imported_fog and options.fog:
+ [options,suites] = cxxtest_fog.scanInputFiles( files, options )
+ else:
+ [options,suites] = cxxtest_parser.scanInputFiles( files, options )
+ writeOutput()
+ except SystemExit:
+ if not catch:
+ raise
+
+def create_parser(asciidoc=False):
+ parser = OptionParser("cxxtestgen [options] [ ...]")
+ if asciidoc:
+ parser.description="The cxxtestgen command processes C++ header files to perform test discovery, and then it creates files for the CxxTest test runner."
+ else:
+ parser.description="The 'cxxtestgen' command processes C++ header files to perform test discovery, and then it creates files for the 'CxxTest' test runner."
+
+ parser.add_option("--version",
+ action="store_true", dest="version", default=False,
+ help="Write the CxxTest version.")
+ parser.add_option("-o", "--output",
+ dest="outputFileName", default=None, metavar="NAME",
+ help="Write output to file NAME.")
+ parser.add_option("-w","--world", dest="world", default="cxxtest",
+ help="The label of the tests, used to name the XML results.")
+ parser.add_option("", "--include", action="append",
+ dest="headers", default=[], metavar="HEADER",
+ help="Include file HEADER in the test runner before other headers.")
+ parser.add_option("", "--abort-on-fail",
+ action="store_true", dest="abortOnFail", default=False,
+ help="Abort tests on failed asserts (like xUnit).")
+ parser.add_option("", "--main",
+ action="store", dest="main", default="main",
+ help="Specify an alternative name for the main() function.")
+ parser.add_option("", "--headers",
+ action="store", dest="header_filename", default=None,
+ help="Specify a filename that contains a list of header files that are processed to generate a test runner.")
+ parser.add_option("", "--runner",
+ dest="runner", default="", metavar="CLASS",
+ help="Create a test runner that processes test events using the class CxxTest::CLASS.")
+ parser.add_option("", "--gui",
+ dest="gui", metavar="CLASS",
+ help="Create a GUI test runner that processes test events using the class CxxTest::CLASS. (deprecated)")
+ parser.add_option("", "--error-printer",
+ action="store_true", dest="error_printer", default=False,
+ help="Create a test runner using the ErrorPrinter class, and allow the use of the standard library.")
+ parser.add_option("", "--xunit-printer",
+ action="store_true", dest="xunit_printer", default=False,
+ help="Create a test runner using the XUnitPrinter class.")
+ parser.add_option("", "--xunit-file", dest="xunit_file", default="",
+ help="The file to which the XML summary is written for test runners using the XUnitPrinter class. The default XML filename is TEST-.xml, where is the value of the --world option. (default: cxxtest)")
+ parser.add_option("", "--have-std",
+ action="store_true", dest="haveStandardLibrary", default=False,
+ help="Use the standard library (even if not found in tests).")
+ parser.add_option("", "--no-std",
+ action="store_true", dest="noStandardLibrary", default=False,
+ help="Do not use standard library (even if found in tests).")
+ parser.add_option("", "--have-eh",
+ action="store_true", dest="haveExceptionHandling", default=False,
+ help="Use exception handling (even if not found in tests).")
+ parser.add_option("", "--no-eh",
+ action="store_true", dest="noExceptionHandling", default=False,
+ help="Do not use exception handling (even if found in tests).")
+ parser.add_option("", "--longlong",
+ dest="longlong", default=None, metavar="TYPE",
+ help="Use TYPE as for long long integers. (default: not supported)")
+ parser.add_option("", "--no-static-init",
+ action="store_true", dest="noStaticInit", default=False,
+ help="Do not rely on static initialization in the test runner.")
+ parser.add_option("", "--template",
+ dest="templateFileName", default=None, metavar="TEMPLATE",
+ help="Generate the test runner using file TEMPLATE to define a template.")
+ parser.add_option("", "--root",
+ action="store_true", dest="root", default=False,
+ help="Write the main() function and global data for a test runner.")
+ parser.add_option("", "--part",
+ action="store_true", dest="part", default=False,
+ help="Write the tester classes for a test runner.")
+ #parser.add_option("", "--factor",
+ #action="store_true", dest="factor", default=False,
+ #help="Declare the _CXXTEST_FACTOR macro. (deprecated)")
+ if imported_fog:
+ fog_help = "Use new FOG C++ parser"
+ else:
+ fog_help = "Use new FOG C++ parser (disabled)"
+ parser.add_option("-f", "--fog-parser",
+ action="store_true",
+ dest="fog",
+ default=False,
+ help=fog_help
+ )
+ return parser
+
+def parseCommandline(args):
+ '''Analyze command line arguments'''
+ global imported_fog
+ global options
+
+ parser = create_parser()
+ (options, args) = parser.parse_args(args=args)
+ if not options.header_filename is None:
+ if not os.path.exists(options.header_filename):
+ abort( "ERROR: the file '%s' does not exist!" % options.header_filename )
+ INPUT = open(options.header_filename)
+ headers = [line.strip() for line in INPUT]
+ args.extend( headers )
+ INPUT.close()
+
+ if options.fog and not imported_fog:
+ abort( "Cannot use the FOG parser. Check that the 'ply' package is installed. The 'ordereddict' package is also required if running Python 2.6")
+
+ if options.version:
+ printVersion()
+
+ # the cxxtest builder relies on this behaviour! don't remove
+ if options.runner == 'none':
+ options.runner = None
+
+ if options.xunit_printer or options.runner == "XUnitPrinter":
+ options.xunit_printer=True
+ options.runner="XUnitPrinter"
+ if len(args) > 1:
+ if options.xunit_file == "":
+ if options.world == "":
+ options.world = "cxxtest"
+ options.xunit_file="TEST-"+options.world+".xml"
+ elif options.xunit_file == "":
+ if options.world == "":
+ options.world = "cxxtest"
+ options.xunit_file="TEST-"+options.world+".xml"
+
+ if options.error_printer:
+ options.runner= "ErrorPrinter"
+ options.haveStandardLibrary = True
+
+ if options.noStaticInit and (options.root or options.part):
+ abort( '--no-static-init cannot be used with --root/--part' )
+
+ if options.gui and not options.runner:
+ options.runner = 'StdioPrinter'
+
+ files = setFiles(args[1:])
+ if len(files) == 0 and not options.root:
+ sys.stderr.write(parser.error("No input files found"))
+
+ return files
+
+
+def printVersion():
+ '''Print CxxTest version and exit'''
+ sys.stdout.write( "This is CxxTest version %s.\n" % __release__.__version__ )
+ sys.exit(0)
+
+def setFiles(patterns ):
+ '''Set input files specified on command line'''
+ files = expandWildcards( patterns )
+ return files
+
+def expandWildcards( patterns ):
+ '''Expand all wildcards in an array (glob)'''
+ fileNames = []
+ for pathName in patterns:
+ patternFiles = glob.glob( pathName )
+ for fileName in patternFiles:
+ fileNames.append( fixBackslashes( fileName ) )
+ return fileNames
+
+def fixBackslashes( fileName ):
+ '''Convert backslashes to slashes in file name'''
+ return re.sub( r'\\', '/', fileName, 0 )
+
+
+def writeOutput():
+ '''Create output file'''
+ if options.templateFileName:
+ writeTemplateOutput()
+ else:
+ writeSimpleOutput()
+
+def writeSimpleOutput():
+ '''Create output not based on template'''
+ output = startOutputFile()
+ writePreamble( output )
+ if options.root or not options.part:
+ writeMain( output )
+
+ if len(suites) > 0:
+ output.write("bool "+suites[0]['object']+"_init = false;\n")
+
+ writeWorld( output )
+ output.close()
+
+include_re = re.compile( r"\s*\#\s*include\s+\s*$" )
+world_re = re.compile( r"^\s*\s*$" )
+def writeTemplateOutput():
+ '''Create output based on template file'''
+ template = open(options.templateFileName)
+ output = startOutputFile()
+ while 1:
+ line = template.readline()
+ if not line:
+ break;
+ if include_re.search( line ):
+ writePreamble( output )
+ output.write( line )
+ elif preamble_re.search( line ):
+ writePreamble( output )
+ elif world_re.search( line ):
+ if len(suites) > 0:
+ output.write("bool "+suites[0]['object']+"_init = false;\n")
+ writeWorld( output )
+ else:
+ output.write( line )
+ template.close()
+ output.close()
+
+def startOutputFile():
+ '''Create output file and write header'''
+ if options.outputFileName is not None:
+ output = open( options.outputFileName, 'w' )
+ else:
+ output = sys.stdout
+ output.write( "/* Generated file, do not edit */\n\n" )
+ return output
+
+def writePreamble( output ):
+ '''Write the CxxTest header (#includes and #defines)'''
+ global wrotePreamble
+ if wrotePreamble: return
+ output.write( "#ifndef CXXTEST_RUNNING\n" )
+ output.write( "#define CXXTEST_RUNNING\n" )
+ output.write( "#endif\n" )
+ output.write( "\n" )
+ if options.xunit_printer:
+ output.write( "#include \n" )
+ if options.haveStandardLibrary:
+ output.write( "#define _CXXTEST_HAVE_STD\n" )
+ if options.haveExceptionHandling:
+ output.write( "#define _CXXTEST_HAVE_EH\n" )
+ if options.abortOnFail:
+ output.write( "#define _CXXTEST_ABORT_TEST_ON_FAIL\n" )
+ if options.longlong:
+ output.write( "#define _CXXTEST_LONGLONG %s\n" % options.longlong )
+ #if options.factor:
+ #output.write( "#define _CXXTEST_FACTOR\n" )
+ for header in options.headers:
+ output.write( "#include \"%s\"\n" % header )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ output.write( "#include \n" )
+ if options.runner:
+ output.write( "#include \n" % options.runner )
+ if options.gui:
+ output.write( "#include \n" % options.gui )
+ output.write( "\n" )
+ wrotePreamble = 1
+
+def writeMain( output ):
+ '''Write the main() function for the test runner'''
+ if not (options.gui or options.runner):
+ return
+ output.write( 'int %s( int argc, char *argv[] ) {\n' % options.main )
+ output.write( ' int status;\n' )
+ if options.noStaticInit:
+ output.write( ' CxxTest::initialize();\n' )
+ if options.gui:
+ tester_t = "CxxTest::GuiTuiRunner " % (options.gui, options.runner)
+ else:
+ tester_t = "CxxTest::%s" % (options.runner)
+ if options.xunit_printer:
+ output.write( ' std::ofstream ofstr("%s");\n' % options.xunit_file )
+ output.write( ' %s tmp(ofstr);\n' % tester_t )
+ else:
+ output.write( ' %s tmp;\n' % tester_t )
+ output.write( ' CxxTest::RealWorldDescription::_worldName = "%s";\n' % options.world )
+ output.write( ' status = CxxTest::Main< %s >( tmp, argc, argv );\n' % tester_t )
+ output.write( ' return status;\n')
+ output.write( '}\n' )
+
+
+def writeWorld( output ):
+ '''Write the world definitions'''
+ global wroteWorld
+ if wroteWorld: return
+ writePreamble( output )
+ writeSuites( output )
+ if options.root or not options.part:
+ writeRoot( output )
+ writeWorldDescr( output )
+ if options.noStaticInit:
+ writeInitialize( output )
+ wroteWorld = 1
+
+def writeSuites(output):
+ '''Write all TestDescriptions and SuiteDescriptions'''
+ for suite in suites:
+ writeInclude( output, suite['file'] )
+ if isGenerated(suite):
+ generateSuite( output, suite )
+ if not options.noStaticInit:
+ if isDynamic(suite):
+ writeSuitePointer( output, suite )
+ else:
+ writeSuiteObject( output, suite )
+ writeTestList( output, suite )
+ writeSuiteDescription( output, suite )
+ writeTestDescriptions( output, suite )
+
+def isGenerated(suite):
+ '''Checks whether a suite class should be created'''
+ return suite['generated']
+
+def isDynamic(suite):
+ '''Checks whether a suite is dynamic'''
+ return 'create' in suite
+
+def writeInclude(output, file):
+ '''Add #include "file" statement'''
+ global lastIncluded
+ if options.outputFileName:
+ dirname = os.path.split(options.outputFileName)[0]
+ tfile = relpath(file, dirname)
+ if os.path.exists(tfile):
+ if tfile == lastIncluded: return
+ output.writelines( [ '#include "', tfile, '"\n\n' ] )
+ lastIncluded = tfile
+ return
+ #
+ # Use an absolute path if the relative path failed
+ #
+ tfile = os.path.abspath(file)
+ if os.path.exists(tfile):
+ if tfile == lastIncluded: return
+ output.writelines( [ '#include "', tfile, '"\n\n' ] )
+ lastIncluded = tfile
+ return
+
+def generateSuite( output, suite ):
+ '''Write a suite declared with CXXTEST_SUITE()'''
+ output.write( 'class %s : public CxxTest::TestSuite {\n' % suite['fullname'] )
+ output.write( 'public:\n' )
+ for line in suite['lines']:
+ output.write(line)
+ output.write( '};\n\n' )
+
+def writeSuitePointer( output, suite ):
+ '''Create static suite pointer object for dynamic suites'''
+ if options.noStaticInit:
+ output.write( 'static %s* %s;\n\n' % (suite['fullname'], suite['object']) )
+ else:
+ output.write( 'static %s* %s = 0;\n\n' % (suite['fullname'], suite['object']) )
+
+def writeSuiteObject( output, suite ):
+ '''Create static suite object for non-dynamic suites'''
+ output.writelines( [ "static ", suite['fullname'], " ", suite['object'], ";\n\n" ] )
+
+def writeTestList( output, suite ):
+ '''Write the head of the test linked list for a suite'''
+ if options.noStaticInit:
+ output.write( 'static CxxTest::List %s;\n' % suite['tlist'] )
+ else:
+ output.write( 'static CxxTest::List %s = { 0, 0 };\n' % suite['tlist'] )
+
+def writeWorldDescr( output ):
+ '''Write the static name of the world name'''
+ if options.noStaticInit:
+ output.write( 'const char* CxxTest::RealWorldDescription::_worldName;\n' )
+ else:
+ output.write( 'const char* CxxTest::RealWorldDescription::_worldName = "cxxtest";\n' )
+
+def writeTestDescriptions( output, suite ):
+ '''Write all test descriptions for a suite'''
+ for test in suite['tests']:
+ writeTestDescription( output, suite, test )
+
+def writeTestDescription( output, suite, test ):
+ '''Write test description object'''
+ if not options.noStaticInit:
+ output.write( 'static class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
+ else:
+ output.write( 'class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
+ #
+ output.write( 'public:\n' )
+ if not options.noStaticInit:
+ output.write( ' %s() : CxxTest::RealTestDescription( %s, %s, %s, "%s" ) {}\n' %
+ (test['class'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
+ else:
+ if isDynamic(suite):
+ output.write( ' %s(%s* _%s) : %s(_%s) { }\n' %
+ (test['class'], suite['fullname'], suite['object'], suite['object'], suite['object']) )
+ output.write( ' %s* %s;\n' % (suite['fullname'], suite['object']) )
+ else:
+ output.write( ' %s(%s& _%s) : %s(_%s) { }\n' %
+ (test['class'], suite['fullname'], suite['object'], suite['object'], suite['object']) )
+ output.write( ' %s& %s;\n' % (suite['fullname'], suite['object']) )
+ output.write( ' void runTest() { %s }\n' % runBody( suite, test ) )
+ #
+ if not options.noStaticInit:
+ output.write( '} %s;\n\n' % test['object'] )
+ else:
+ output.write( '};\n\n' )
+
+def runBody( suite, test ):
+ '''Body of TestDescription::run()'''
+ if isDynamic(suite): return dynamicRun( suite, test )
+ else: return staticRun( suite, test )
+
+def dynamicRun( suite, test ):
+ '''Body of TestDescription::run() for test in a dynamic suite'''
+ return 'if ( ' + suite['object'] + ' ) ' + suite['object'] + '->' + test['name'] + '();'
+
+def staticRun( suite, test ):
+ '''Body of TestDescription::run() for test in a non-dynamic suite'''
+ return suite['object'] + '.' + test['name'] + '();'
+
+def writeSuiteDescription( output, suite ):
+ '''Write SuiteDescription object'''
+ if isDynamic( suite ):
+ writeDynamicDescription( output, suite )
+ else:
+ writeStaticDescription( output, suite )
+
+def writeDynamicDescription( output, suite ):
+ '''Write SuiteDescription for a dynamic suite'''
+ output.write( 'CxxTest::DynamicSuiteDescription< %s > %s' % (suite['fullname'], suite['dobject']) )
+ if not options.noStaticInit:
+ output.write( '( %s, %s, "%s", %s, %s, %s, %s )' %
+ (suite['cfile'], suite['line'], suite['fullname'], suite['tlist'],
+ suite['object'], suite['create'], suite['destroy']) )
+ output.write( ';\n\n' )
+
+def writeStaticDescription( output, suite ):
+ '''Write SuiteDescription for a static suite'''
+ output.write( 'CxxTest::StaticSuiteDescription %s' % suite['dobject'] )
+ if not options.noStaticInit:
+ output.write( '( %s, %s, "%s", %s, %s )' %
+ (suite['cfile'], suite['line'], suite['fullname'], suite['object'], suite['tlist']) )
+ output.write( ';\n\n' )
+
+def writeRoot(output):
+ '''Write static members of CxxTest classes'''
+ output.write( '#include \n' )
+
+def writeInitialize(output):
+ '''Write CxxTest::initialize(), which replaces static initialization'''
+ output.write( 'namespace CxxTest {\n' )
+ output.write( ' void initialize()\n' )
+ output.write( ' {\n' )
+ for suite in suites:
+ #print "HERE", suite
+ writeTestList( output, suite )
+ output.write( ' %s.initialize();\n' % suite['tlist'] )
+ #writeSuiteObject( output, suite )
+ if isDynamic(suite):
+ writeSuitePointer( output, suite )
+ output.write( ' %s = 0;\n' % suite['object'])
+ else:
+ writeSuiteObject( output, suite )
+ output.write( ' static ')
+ writeSuiteDescription( output, suite )
+ if isDynamic(suite):
+ #output.write( ' %s = %s.suite();\n' % (suite['object'],suite['dobject']) )
+ output.write( ' %s.initialize( %s, %s, "%s", %s, %s, %s, %s );\n' %
+ (suite['dobject'], suite['cfile'], suite['line'], suite['fullname'],
+ suite['tlist'], suite['object'], suite['create'], suite['destroy']) )
+ output.write( ' %s.setUp();\n' % suite['dobject'])
+ else:
+ output.write( ' %s.initialize( %s, %s, "%s", %s, %s );\n' %
+ (suite['dobject'], suite['cfile'], suite['line'], suite['fullname'],
+ suite['object'], suite['tlist']) )
+
+ for test in suite['tests']:
+ output.write( ' static %s %s(%s);\n' %
+ (test['class'], test['object'], suite['object']) )
+ output.write( ' %s.initialize( %s, %s, %s, "%s" );\n' %
+ (test['object'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
+
+ output.write( ' }\n' )
+ output.write( '}\n' )
+
+man_template=Template("""CXXTESTGEN(1)
+=============
+:doctype: manpage
+
+
+NAME
+----
+cxxtestgen - performs test discovery to create a CxxTest test runner
+
+
+SYNOPSIS
+--------
+${usage}
+
+
+DESCRIPTION
+-----------
+${description}
+
+
+OPTIONS
+-------
+${options}
+
+
+EXIT STATUS
+-----------
+*0*::
+ Success
+
+*1*::
+ Failure (syntax or usage error; configuration error; document
+ processing failure; unexpected error).
+
+
+BUGS
+----
+See the CxxTest Home Page for the link to the CxxTest ticket repository.
+
+
+AUTHOR
+------
+CxxTest was originally written by Erez Volk. Many people have
+contributed to it.
+
+
+RESOURCES
+---------
+Home page:
+
+CxxTest User Guide:
+
+
+
+COPYING
+-------
+Copyright (c) 2008 Sandia Corporation. This software is distributed
+under the Lesser GNU General Public License (LGPL) v3
+""")
+
+def create_manpage():
+ """Write ASCIIDOC manpage file"""
+ parser = create_parser(asciidoc=True)
+ #
+ usage = parser.usage
+ description = parser.description
+ options=""
+ for opt in parser.option_list:
+ opts = opt._short_opts + opt._long_opts
+ optstr = '*' + ', '.join(opts) + '*'
+ if not opt.metavar is None:
+ optstr += "='%s'" % opt.metavar
+ optstr += '::\n'
+ options += optstr
+ #
+ options += opt.help
+ options += '\n\n'
+ #
+ OUTPUT = open('cxxtestgen.1.txt','w')
+ OUTPUT.write( man_template.substitute(usage=usage, description=description, options=options) )
+ OUTPUT.close()
+
+
diff --git a/third-party/cxxtest/python/python3/scripts/cxxtestgen b/third-party/cxxtest/python/python3/scripts/cxxtestgen
new file mode 100644
index 00000000..74090ec7
--- /dev/null
+++ b/third-party/cxxtest/python/python3/scripts/cxxtestgen
@@ -0,0 +1,5 @@
+#! python
+
+import cxxtest.cxxtestgen
+
+cxxtest.cxxtestgen.main()
diff --git a/third-party/cxxtest/python/scripts/cxxtestgen b/third-party/cxxtest/python/scripts/cxxtestgen
new file mode 100755
index 00000000..4fb2d796
--- /dev/null
+++ b/third-party/cxxtest/python/scripts/cxxtestgen
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+import sys
+import os.path
+
+try:
+ import cxxtest.cxxtestgen
+except ImportError:
+ currdir = os.path.dirname(os.path.abspath(__file__))
+
+ if sys.version_info < (3,0):
+ sys.path.append( os.path.abspath( os.path.sep.join([currdir, '..']) ) )
+ else:
+ sys.path.append( os.path.abspath( os.path.sep.join([currdir, '..', python3]) ) )
+
+ import cxxtest.cxxtestgen
+
+cxxtest.cxxtestgen.main()
diff --git a/third-party/cxxtest/python/setup.py b/third-party/cxxtest/python/setup.py
new file mode 100644
index 00000000..7fc9168c
--- /dev/null
+++ b/third-party/cxxtest/python/setup.py
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------------------
+# CxxTest: A lightweight C++ unit testing library.
+# Copyright (c) 2008 Sandia Corporation.
+# This software is distributed under the LGPL License v3
+# For more information, see the COPYING file in the top CxxTest directory.
+# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+# the U.S. Government retains certain rights in this software.
+#-------------------------------------------------------------------------
+
+"""
+Script to generate the installer for cxxtest.
+"""
+
+classifiers = """\
+Development Status :: 4 - Beta
+Intended Audience :: End Users/Desktop
+License :: OSI Approved :: LGPL License
+Natural Language :: English
+Operating System :: Microsoft :: Windows
+Operating System :: Unix
+Programming Language :: Python
+Topic :: Software Development :: Libraries :: Python Modules
+"""
+
+import os
+import sys
+from os.path import realpath, dirname
+if sys.version_info >= (3,0):
+ sys.path.insert(0, dirname(realpath(__file__))+os.sep+'python3')
+ os.chdir('python3')
+
+import cxxtest
+
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
+
+doclines = cxxtest.__doc__.split("\n")
+
+setup(name="cxxtest",
+ version=cxxtest.__version__,
+ maintainer=cxxtest.__maintainer__,
+ maintainer_email=cxxtest.__maintainer_email__,
+ url = cxxtest.__url__,
+ license = cxxtest.__license__,
+ platforms = ["any"],
+ description = doclines[0],
+ classifiers = filter(None, classifiers.split("\n")),
+ long_description = "\n".join(doclines[2:]),
+ packages=['cxxtest'],
+ keywords=['utility'],
+ scripts=['scripts/cxxtestgen']
+ #
+ # The entry_points option is not supported by distutils.core
+ #
+ #entry_points="""
+ #[console_scripts]
+ #cxxtestgen = cxxtest.cxxtestgen:main
+ #"""
+ )
+
diff --git a/third-party/cxxtest/sample/.cvsignore b/third-party/cxxtest/sample/.cvsignore
new file mode 100644
index 00000000..087c5dc6
--- /dev/null
+++ b/third-party/cxxtest/sample/.cvsignore
@@ -0,0 +1,5 @@
+.consign
+Makefile
+*_runner*
+tests.cpp error_printer.cpp stdio_printer.cpp file_printer.cpp aborter.cpp only.cpp
+error_printer stdio_printer file_printer aborter only
diff --git a/third-party/cxxtest/sample/Construct b/third-party/cxxtest/sample/Construct
new file mode 100644
index 00000000..60902254
--- /dev/null
+++ b/third-party/cxxtest/sample/Construct
@@ -0,0 +1,64 @@
+# -*- Perl -*-
+
+#
+# This file shows how to use CxxTest with Cons
+#
+
+$env = new cons( CXX => ("$^O" eq 'MSWin32') ? 'cl -nologo -GX' : 'c++',
+ CPPPATH => '..',
+ CXXTESTGEN => '../bin/cxxtestgen' );
+
+@tests = <*.h>;
+
+# The error printer is the most basic runner
+CxxTestErrorPrinter $env 'error_printer', @tests;
+
+# You can also specify which runner you want to use
+CxxTestRunner $env 'stdio_printer', 'StdioPrinter', @tests;
+
+# For more control, use template files
+CxxTestTemplate $env 'file_printer', 'file_printer.tpl', @tests;
+
+# Or, you can always separate the tests from the runner
+CxxTest $env 'tests.cpp', '', @tests;
+Program $env 'yes_no_runner', ('yes_no_runner.cpp', 'tests.cpp');
+
+
+#
+# Here is the code used to build these files
+# You can use this in your own Construct files
+#
+
+# cons::CxxTest $env $dst, $options, @srcs
+# Generates a CxxTest source file, passing the specified options to cxxtestgen
+sub cons::CxxTest($$$@) {
+ my ($env, $dst, $options, @srcs) = @_;
+ Command $env $dst, @srcs, "%CXXTESTGEN -o %> ${options} %<";
+}
+
+# cons::CxxTestTemplate $env $dst, $template, @srcs
+# Generates and builds a CxxTest runner using a template file
+sub cons::CxxTestTemplate($$$@) {
+ my ($env, $dst, $template, @srcs) = @_;
+ my $source = "${dst}.cpp";
+ CxxTest $env $source, "--template=${template}", ($template, @srcs);
+ Program $env $dst, $source;
+}
+
+# cons::CxxTestRunner $env $dst, $runner, @srcs
+# Generates and builds a CxxTest runner using the --runner option
+sub cons::CxxTestRunner($$$@) {
+ my ($env, $dst, $runner, @srcs) = @_;
+ my $source = "${dst}.cpp";
+ CxxTest $env $source, "--runner=${runner}", @srcs;
+ Program $env $dst, $source;
+}
+
+# cons::CxxTestErrorPrinter $env $dst, @srcs
+# Generates and builds a CxxTest ErrorPrinter
+sub cons::CxxTestErrorPrinter($$@) {
+ my ($env, $dst, @srcs) = @_;
+ CxxTestRunner $env $dst, 'ErrorPrinter', @srcs;
+}
+
+
diff --git a/third-party/cxxtest/sample/CreatedTest.h b/third-party/cxxtest/sample/CreatedTest.h
new file mode 100644
index 00000000..d1518634
--- /dev/null
+++ b/third-party/cxxtest/sample/CreatedTest.h
@@ -0,0 +1,29 @@
+#ifndef __CREATEDTEST_H
+#define __CREATEDTEST_H
+
+#include
+#include
+#include
+
+//
+// This test suite shows what to do when your test case
+// class cannot be instantiated statically.
+// As an example, this test suite requires a non-default constructor.
+//
+
+class CreatedTest : public CxxTest::TestSuite {
+ char *_buffer;
+public:
+ CreatedTest(unsigned size) : _buffer(new char[size]) {}
+ virtual ~CreatedTest() { delete [] _buffer; }
+
+ static CreatedTest *createSuite() { return new CreatedTest(16); }
+ static void destroySuite(CreatedTest *suite) { delete suite; }
+
+ void test_nothing() {
+ TS_FAIL("Nothing to test");
+ }
+};
+
+
+#endif // __CREATEDTEST_H
diff --git a/third-party/cxxtest/sample/DeltaTest.h b/third-party/cxxtest/sample/DeltaTest.h
new file mode 100644
index 00000000..2820c016
--- /dev/null
+++ b/third-party/cxxtest/sample/DeltaTest.h
@@ -0,0 +1,30 @@
+#ifndef __DELTATEST_H
+#define __DELTATEST_H
+
+#include
+#include
+
+class DeltaTest : public CxxTest::TestSuite {
+ double _pi, _delta;
+
+public:
+ void setUp() {
+ _pi = 3.1415926535;
+ _delta = 0.0001;
+ }
+
+ void testSine() {
+ TS_ASSERT_DELTA(sin(0.0), 0.0, _delta);
+ TS_ASSERT_DELTA(sin(_pi / 6), 0.5, _delta);
+ TS_ASSERT_DELTA(sin(_pi / 2), 1.0, _delta);
+ TS_ASSERT_DELTA(sin(_pi), 0.0, _delta);
+ }
+
+ void testInt() {
+ unsigned a = 0;
+ unsigned b = 0;
+ TS_ASSERT_DELTA(a, b, 10);
+ }
+};
+
+#endif // __DELTATEST_H
diff --git a/third-party/cxxtest/sample/EnumTraits.h b/third-party/cxxtest/sample/EnumTraits.h
new file mode 100644
index 00000000..f17bf3f2
--- /dev/null
+++ b/third-party/cxxtest/sample/EnumTraits.h
@@ -0,0 +1,37 @@
+//
+// This is a test of CxxTest's ValueTraits for enumerations.
+//
+#include
+
+//
+// First define your enumeration
+//
+enum Answer {
+ Yes,
+ No,
+ Maybe,
+ DontKnow,
+ DontCare
+};
+
+//
+// Now make CxxTest aware of it
+//
+CXXTEST_ENUM_TRAITS(Answer,
+ CXXTEST_ENUM_MEMBER(Yes)
+ CXXTEST_ENUM_MEMBER(No)
+ CXXTEST_ENUM_MEMBER(Maybe)
+ CXXTEST_ENUM_MEMBER(DontKnow)
+ CXXTEST_ENUM_MEMBER(DontCare));
+
+class EnumTraits : public CxxTest::TestSuite {
+public:
+ void test_Enum_traits() {
+ TS_FAIL(Yes);
+ TS_FAIL(No);
+ TS_FAIL(Maybe);
+ TS_FAIL(DontKnow);
+ TS_FAIL(DontCare);
+ TS_FAIL((Answer)1000);
+ }
+};
diff --git a/third-party/cxxtest/sample/ExceptionTest.h b/third-party/cxxtest/sample/ExceptionTest.h
new file mode 100644
index 00000000..ccb41aab
--- /dev/null
+++ b/third-party/cxxtest/sample/ExceptionTest.h
@@ -0,0 +1,49 @@
+#ifndef __EXCEPTIONTEST_H
+#define __EXCEPTIONTEST_H
+
+#include
+
+//
+// This test suite demonstrates the use of TS_ASSERT_THROWS
+//
+
+class ExceptionTest : public CxxTest::TestSuite {
+public:
+ void testAssertion(void) {
+ // This assert passes, since throwThis() throws (Number)
+ TS_ASSERT_THROWS(throwThis(3), const Number &);
+ // This assert passes, since throwThis() throws something
+ TS_ASSERT_THROWS_ANYTHING(throwThis(-30));
+ // This assert fails, since throwThis() doesn't throw char *
+ TS_ASSERT_THROWS(throwThis(5), const char *);
+ // This assert fails since goodFunction() throws nothing
+ TS_ASSERT_THROWS_ANYTHING(goodFunction(1));
+ // The regular TS_ASSERT macros will catch unhandled exceptions
+ TS_ASSERT_EQUALS(throwThis(3), 333);
+ // You can assert that a function throws nothing
+ TS_ASSERT_THROWS_NOTHING(throwThis(-1));
+ // This assert fails, since throwThis() throws (Number)
+ TS_ASSERT_THROWS(throwThis(3), std::exception&);
+ // If you want to catch the exceptions yourself, use the ETS_ marcos
+ try {
+ ETS_ASSERT_EQUALS(throwThis(3), 333);
+ } catch (const Number &) {
+ TS_FAIL("throwThis(3) failed");
+ }
+ }
+
+private:
+ void goodFunction(int) {
+ }
+
+ class Number {
+ public:
+ Number(int) {}
+ };
+
+ int throwThis(int i) {
+ throw Number(i);
+ }
+};
+
+#endif // __EXCEPTIONTEST_H
diff --git a/third-party/cxxtest/sample/FixtureTest.h b/third-party/cxxtest/sample/FixtureTest.h
new file mode 100644
index 00000000..2a350963
--- /dev/null
+++ b/third-party/cxxtest/sample/FixtureTest.h
@@ -0,0 +1,33 @@
+#ifndef __FIXTURETEST_H
+#define __FIXTURETEST_H
+
+#include
+#include
+
+//
+// This test suite shows how to use setUp() and tearDown()
+// to initialize data common to all tests.
+// setUp()/tearDown() will be called before and after each
+// test.
+//
+
+class FixtureTest : public CxxTest::TestSuite {
+ char *_buffer;
+public:
+ void setUp() {
+ _buffer = new char[1024];
+ }
+
+ void tearDown() {
+ delete [] _buffer;
+ }
+
+ void test_strcpy() {
+ strcpy(_buffer, "Hello, world!");
+ TS_ASSERT_EQUALS(_buffer[0], 'H');
+ TS_ASSERT_EQUALS(_buffer[1], 'E');
+ }
+};
+
+
+#endif // __FIXTURETEST_H
diff --git a/third-party/cxxtest/sample/Makefile.PL b/third-party/cxxtest/sample/Makefile.PL
new file mode 100755
index 00000000..d29afcc6
--- /dev/null
+++ b/third-party/cxxtest/sample/Makefile.PL
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+#
+# This isn't a "real" `Makefile.PL'
+# It just copies the correct `Makefile.*' to `Makefile'
+#
+use strict;
+use Getopt::Long;
+use File::Copy;
+
+sub usage() {
+ die "Usage: $0 [--bcc32]\n";
+}
+
+my $source;
+my $target = 'Makefile';
+my $windows = $ENV{'windir'};
+
+GetOptions( 'bcc32' => sub { $source = 'Makefile.bcc32' } ) or usage();
+if ( !defined( $source ) ) {
+ $source = $windows ? 'Makefile.msvc' : 'Makefile.unix';
+}
+
+unlink($target);
+$windows ? copy($source, $target) : symlink($source, $target);
+
+print "`Makefile' is now `$source'.\n";
+
+#
+# Local Variables:
+# compile-command: "perl Makefile.PL"
+# End:
+#
diff --git a/third-party/cxxtest/sample/Makefile.bcc32 b/third-party/cxxtest/sample/Makefile.bcc32
new file mode 100644
index 00000000..3bd5303b
--- /dev/null
+++ b/third-party/cxxtest/sample/Makefile.bcc32
@@ -0,0 +1,94 @@
+#
+# Makefile for Borland C++
+# Make sure bcc32.exe is in the PATH or change CXXC below
+#
+
+# For the Win32 GUI
+#WIN32_FLAGS = user32.lib comctl32.lib
+
+# For the Qt GUI
+#QTDIR = c:\qt
+QT_FLAGS = -I$(QTDIR)/include $(QTDIR)/lib/qt.lib
+
+
+TARGETS = error_printer.exe stdio_printer.exe yes_no_runner.exe file_printer.exe aborter.exe only.exe
+GUI_TARGETS = win32_runner.exe qt_runner.exe
+TESTS = *.h
+GUI_TESTS = gui/GreenYellowRed.h $(TESTS)
+TESTGEN = ../bin/cxxtestgen
+CXXC = bcc32.exe -w- -I. -I..
+
+all: $(TARGETS)
+
+clean:
+ del *~ *.o *.obj
+ del $(TARGETS)
+ del $(GUI_TARGETS)
+ del tests.cpp error_printer.cpp stdio_printer.cpp file_printer.cpp aborter.cpp only.cpp
+ del win32_runner.cpp qt_runner.cpp
+
+distclean: clean
+ del Makefile
+
+run: error_printer.exe
+ error_printer.exe
+
+run_win32: win32_runner.exe
+ win32_runner.exe
+
+run_qt: qt_runner.exe
+ qt_runner.exe
+
+error_printer.cpp: $(TESTS)
+ $(TESTGEN) -o error_printer.cpp --error-printer $(TESTS)
+
+stdio_printer.cpp: $(TESTS)
+ $(TESTGEN) -o stdio_printer.cpp --runner=StdioPrinter $(TESTS)
+
+file_printer.cpp: file_printer.tpl $(TESTS)
+ $(TESTGEN) -o file_printer.cpp --template=file_printer.tpl $(TESTS)
+
+aborter.cpp: aborter.tpl $(TESTS)
+ $(TESTGEN) -o aborter.cpp --template=aborter.tpl $(TESTS)
+
+only.cpp: only.tpl $(TESTS)
+ $(TESTGEN) -o only.cpp --template=only.tpl $(TESTS)
+
+tests.cpp: $(TESTS)
+ $(TESTGEN) -o tests.cpp $(TESTS)
+
+win32_runner.cpp: $(GUI_TESTS)
+ $(TESTGEN) -o win32_runner.cpp --gui=Win32Gui $(GUI_TESTS)
+
+qt_runner.cpp: $(GUI_TESTS)
+ $(TESTGEN) -o qt_runner.cpp --gui=QtGui $(GUI_TESTS)
+
+error_printer.exe: error_printer.cpp
+ $(CXXC) -eerror_printer.exe error_printer.cpp
+
+stdio_printer.exe: stdio_printer.cpp
+ $(CXXC) -estdio_printer.exe stdio_printer.cpp
+
+file_printer.exe: file_printer.cpp
+ $(CXXC) -efile_printer.exe file_printer.cpp
+
+only.exe: only.cpp
+ $(CXXC) -eonly.exe only.cpp
+
+aborter.exe: aborter.cpp
+ $(CXXC) -eaborter.exe aborter.cpp
+
+yes_no_runner.exe: yes_no_runner.cpp tests.cpp
+ $(CXXC) -eyes_no_runner.exe yes_no_runner.cpp tests.cpp
+
+win32_runner.exe: win32_runner.cpp
+ $(CXXC) -ewin32_runner.exe win32_runner.cpp $(WIN32_FLAGS)
+
+qt_runner.exe: qt_runner.cpp
+ $(CXXC) -o qt_runner.exe qt_runner.cpp $(QT_FLAGS)
+
+#
+# Local Variables:
+# compile-command: "make -fMakefile.bcc32"
+# End:
+#
diff --git a/third-party/cxxtest/sample/Makefile.msvc b/third-party/cxxtest/sample/Makefile.msvc
new file mode 100644
index 00000000..2374f802
--- /dev/null
+++ b/third-party/cxxtest/sample/Makefile.msvc
@@ -0,0 +1,93 @@
+#
+# Makefile for Microsoft Visual C++
+# Make sure cl.exe is in the PATH (run vcvars.bat) or change CXXC below
+#
+
+# For the Win32 GUI
+WIN32_FLAGS = user32.lib
+
+# For the Qt GUI
+# QTDIR = c:\qt
+QT_FLAGS = -I$(QTDIR)/include $(QTDIR)/lib/qt.lib
+
+TARGETS = error_printer.exe stdio_printer.exe yes_no_runner.exe file_printer.exe aborter.exe only.exe
+GUI_TARGETS = win32_runner.exe qt_runner.exe
+TESTS = *.h
+GUI_TESTS = gui/GreenYellowRed.h $(TESTS)
+TESTGEN = python ../bin/cxxtestgen
+CXXC = cl.exe -GX -W3 -WX -I. -I..
+
+all: $(TARGETS)
+
+clean:
+ del *~ *.o *.obj
+ del $(TARGETS)
+ del $(GUI_TARGETS)
+ del tests.cpp error_printer.cpp stdio_printer.cpp file_printer.cpp aborter.cpp only.cpp
+ del win32_runner.cpp qt_runner.cpp
+
+distclean: clean
+ del Makefile
+
+run: error_printer.exe
+ error_printer.exe
+
+run_win32: win32_runner.exe
+ win32_runner.exe
+
+run_qt: qt_runner.exe
+ qt_runner.exe
+
+error_printer.cpp: $(TESTS)
+ $(TESTGEN) -o error_printer.cpp --error-printer $(TESTS)
+
+stdio_printer.cpp: $(TESTS)
+ $(TESTGEN) -o stdio_printer.cpp --runner=StdioPrinter $(TESTS)
+
+file_printer.cpp: file_printer.tpl $(TESTS)
+ $(TESTGEN) -o file_printer.cpp --template=file_printer.tpl $(TESTS)
+
+aborter.cpp: aborter.tpl $(TESTS)
+ $(TESTGEN) -o aborter.cpp --template=aborter.tpl $(TESTS)
+
+only.cpp: only.tpl $(TESTS)
+ $(TESTGEN) -o only.cpp --template=only.tpl $(TESTS)
+
+tests.cpp: $(TESTS)
+ $(TESTGEN) -o tests.cpp $(TESTS)
+
+win32_runner.cpp: $(GUI_TESTS)
+ $(TESTGEN) -o win32_runner.cpp --gui=Win32Gui $(GUI_TESTS)
+
+qt_runner.cpp: $(GUI_TESTS)
+ $(TESTGEN) -o qt_runner.cpp --gui=QtGui $(GUI_TESTS)
+
+error_printer.exe: error_printer.cpp
+ $(CXXC) -o error_printer.exe error_printer.cpp
+
+stdio_printer.exe: stdio_printer.cpp
+ $(CXXC) -o stdio_printer.exe stdio_printer.cpp
+
+file_printer.exe: file_printer.cpp
+ $(CXXC) -o file_printer.exe file_printer.cpp
+
+only.exe: only.cpp
+ $(CXXC) -o only.exe only.cpp
+
+aborter.exe: aborter.cpp
+ $(CXXC) -o aborter.exe aborter.cpp
+
+yes_no_runner.exe: yes_no_runner.cpp tests.cpp
+ $(CXXC) -o yes_no_runner.exe yes_no_runner.cpp tests.cpp
+
+win32_runner.exe: win32_runner.cpp
+ $(CXXC) -o win32_runner.exe win32_runner.cpp $(WIN32_FLAGS)
+
+qt_runner.exe: qt_runner.cpp
+ $(CXXC) -o qt_runner.exe qt_runner.cpp $(QT_FLAGS)
+
+#
+# Local Variables:
+# compile-command: "nmake -fMakefile.msvc"
+# End:
+#
diff --git a/third-party/cxxtest/sample/Makefile.unix b/third-party/cxxtest/sample/Makefile.unix
new file mode 100644
index 00000000..ad87b3bc
--- /dev/null
+++ b/third-party/cxxtest/sample/Makefile.unix
@@ -0,0 +1,83 @@
+#
+# Makefile for UN*X-like systems
+#
+
+# Change this line if you want a different compiler
+CXXC = c++ -Wall -W -Werror -I. -I..
+
+TESTGEN = ../bin/cxxtestgen
+
+# For the X11 GUI
+X11_FLAGS = -I/usr/X11R6/include -L/usr/X11R6/lib -lX11
+
+# For the Qt GUI
+#QTDIR = /usr/lib/qt
+QTLIB = -lqt-mt
+#QTLIB = -lqt
+QT_FLAGS = -I$(QTDIR)/include -L$(QTDIR)/lib $(QTLIB) -O2
+
+TARGETS = error_printer stdio_printer yes_no_runner file_printer aborter only
+GUI_TARGETS = x11_runner qt_runner
+TESTS = *.h
+GUI_TESTS = gui/GreenYellowRed.h $(TESTS)
+
+all: $(TARGETS)
+
+clean:
+ rm -f *~ *.o *.obj $(TARGETS) $(GUI_TARGETS)
+ rm -f tests.cpp error_printer.cpp stdio_printer.cpp file_printer.cpp aborter.cpp only.cpp
+ rm -f x11_runner.cpp qt_runner.cpp
+
+distclean: clean
+ rm -f Makefile
+
+run: error_printer
+ ./error_printer
+
+run_x11: x11_runner
+ ./x11_runner
+
+run_qt: qt_runner
+ ./qt_runner
+
+error_printer.cpp: $(TESTS)
+ $(TESTGEN) -o $@ --error-printer $(TESTS)
+
+stdio_printer.cpp: $(TESTS)
+ $(TESTGEN) -o $@ --runner=StdioPrinter $(TESTS)
+
+file_printer.cpp: file_printer.tpl $(TESTS)
+ $(TESTGEN) -o $@ --template=file_printer.tpl $(TESTS)
+
+aborter.cpp: aborter.tpl $(TESTS)
+ $(TESTGEN) -o $@ --template=aborter.tpl $(TESTS)
+
+only.cpp: only.tpl $(TESTS)
+ $(TESTGEN) -o $@ --template=only.tpl $(TESTS)
+
+tests.cpp: $(TESTS)
+ $(TESTGEN) -o $@ $(TESTS)
+
+x11_runner.cpp: $(GUI_TESTS)
+ $(TESTGEN) -o $@ --gui=X11Gui $(GUI_TESTS)
+
+qt_runner.cpp: $(GUI_TESTS)
+ $(TESTGEN) -o $@ --gui=QtGui $(GUI_TESTS)
+
+%: %.cpp
+ $(CXXC) -o $@ $<
+
+yes_no_runner: yes_no_runner.cpp tests.cpp
+ $(CXXC) -o $@ $^
+
+x11_runner: x11_runner.cpp
+ $(CXXC) -o $@ $^ $(X11_FLAGS)
+
+qt_runner: qt_runner.cpp
+ $(CXXC) -o $@ $^ $(QT_FLAGS)
+
+#
+# Local Variables:
+# compile-command: "make -fMakefile.unix"
+# End:
+#
diff --git a/third-party/cxxtest/sample/MessageTest.h b/third-party/cxxtest/sample/MessageTest.h
new file mode 100644
index 00000000..d981d35b
--- /dev/null
+++ b/third-party/cxxtest/sample/MessageTest.h
@@ -0,0 +1,27 @@
+#ifndef __MESSAGETEST_H
+#define __MESSAGETEST_H
+
+#include
+
+//
+// The [E]TSM_ macros can be used to print a specified message
+// instead of the default one.
+// This is useful when you refactor your tests, as shown below
+//
+
+class MessageTest : public CxxTest::TestSuite {
+public:
+ void testValues() {
+ checkValue(0, "My hovercraft");
+ checkValue(1, "is full");
+ checkValue(2, "of eels");
+ }
+
+ void checkValue(unsigned value, const char *message) {
+ TSM_ASSERT(message, value != 0);
+ TSM_ASSERT_EQUALS(message, value, value * value);
+ }
+};
+
+
+#endif // __MESSAGETEST_H
diff --git a/third-party/cxxtest/sample/SCons/SConstruct b/third-party/cxxtest/sample/SCons/SConstruct
new file mode 100644
index 00000000..cb394084
--- /dev/null
+++ b/third-party/cxxtest/sample/SCons/SConstruct
@@ -0,0 +1,40 @@
+
+cxxtestbuilder_path = '../../build_tools/SCons/cxxtest.py'
+cxxtest_path = '../..'
+
+# First a bit of python magic to make the CxxTestBuilder available
+# without having to copy it into a particular path.
+# for nicer examples you *should* use, see the cxxtest builder tests in the
+# build_tools/SCons/test directory.
+import imp
+cxxtest = imp.load_source('cxxtest', cxxtestbuilder_path)
+
+# First build the 'real' library, when working on an embedded system
+# this may involve a cross compiler.
+env = Environment()
+env.BuildDir('build/embedded_platform', 'src')
+env.Append(CPPPATH=['include'])
+libtested = env.StaticLibrary('build/embedded_platform/tested',
+ env.Glob('build/embedded_platform/*.c'))
+
+# Now create a seperate build environment for the tests so we can keep any
+# options that are specific to testing seperate from the 'production' build
+# environment. For simplicity I am just copying the production environment.
+# If we are cross compiling for the "real" library, then this
+# environement might be using the normal compiler.
+env_test = env.Clone()
+
+# Add the CxxTestBuilder to our testing build environment.
+cxxtest.generate(env_test, CXXTEST_INSTALL_DIR = cxxtest_path)
+
+# If we were working with an embedded platform we may want to create a
+# seperate version of our library that runs on our development box in
+# order to do our initial unit testing. This version may also include
+# any special preprocessor defines needed for testing e.g. -DTESTING
+env_test.BuildDir('build/dev_platform', 'src')
+env_test.BuildDir('build/tests', 'tests')
+lib_to_test = env_test.StaticLibrary('build/dev_platform/tested',
+ env.Glob('build/dev_platform/*.c'))
+env_test.Append(LIBS=lib_to_test)
+env_test.CxxTest(env_test.Glob('tests/*.h'))
+
diff --git a/third-party/cxxtest/sample/SCons/include/stack.h b/third-party/cxxtest/sample/SCons/include/stack.h
new file mode 100644
index 00000000..e73420b9
--- /dev/null
+++ b/third-party/cxxtest/sample/SCons/include/stack.h
@@ -0,0 +1,27 @@
+#ifndef STACK_H
+#define STACK_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef struct stack_t {
+ int size;
+ int* vals;
+ int capacity;
+ } stack_t;
+
+ stack_t* stack_create();
+ void stack_free(stack_t* stack);
+ int stack_size(stack_t* stack);
+ void stack_push(stack_t* stack, int val);
+ int stack_pop(stack_t* stack);
+ int stack_peak(stack_t* stack);
+ int stack_capacity(stack_t* stack);
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif
diff --git a/third-party/cxxtest/sample/SCons/src/stack.c b/third-party/cxxtest/sample/SCons/src/stack.c
new file mode 100644
index 00000000..960f8cfb
--- /dev/null
+++ b/third-party/cxxtest/sample/SCons/src/stack.c
@@ -0,0 +1,48 @@
+#include
+
+#include
+
+stack_t* stack_create() {
+ stack_t* retVal = malloc(sizeof(stack_t));
+ retVal->size = 0;
+ retVal->capacity = 10;
+ retVal->vals = malloc(retVal->capacity*sizeof(int));
+ return retVal;
+}
+
+void stack_free(stack_t* stack) {
+ free(stack->vals);
+ free(stack);
+}
+
+int stack_size(stack_t* stack) {
+ return stack->size;
+}
+
+void stack_push(stack_t* stack, int val) {
+ if(stack->size == stack->capacity) {
+ stack->capacity *= 2;
+ stack->vals = realloc(stack->vals, stack->capacity*sizeof(int));
+ }
+ stack->vals[stack->size++] = val;
+}
+
+int stack_pop(stack_t* stack) {
+ if (stack->size >= 1)
+ return stack->vals[--stack->size];
+ else
+ return 0;
+}
+
+int stack_peak(stack_t* stack) {
+ if (stack->size >= 1)
+ return stack->vals[stack->size-1];
+ else
+ return 0;
+}
+
+int stack_capacity(stack_t* stack) {
+ return stack->capacity;
+}
+
+
diff --git a/third-party/cxxtest/sample/SCons/tests/stack_test.h b/third-party/cxxtest/sample/SCons/tests/stack_test.h
new file mode 100644
index 00000000..24fd6b52
--- /dev/null
+++ b/third-party/cxxtest/sample/SCons/tests/stack_test.h
@@ -0,0 +1,71 @@
+#ifndef STACK_TEST_H
+#define STACK_TEST_H
+
+#include
+#include
+
+class stack_test : public CxxTest::TestSuite
+{
+
+ private:
+ stack_t* stack;
+ public:
+
+ void setUp() {
+ stack = stack_create();
+ }
+
+ void tearDown() {
+ stack_free(stack);
+ }
+
+ void test_create_stack() {
+ TS_ASSERT_DIFFERS((stack_t*)0, stack);
+ }
+
+ void test_new_stack_is_empty() {
+ TS_ASSERT_EQUALS(0, stack_size(stack));
+ }
+
+ void test_one_push_add_one_to_size() {
+ stack_push(stack, 1);
+ TS_ASSERT_EQUALS(1, stack_size(stack));
+ }
+
+ void test_push_pop_doesnt_change_size() {
+ stack_push(stack, 1);
+ (void)stack_pop(stack);
+ TS_ASSERT_EQUALS(0, stack_size(stack));
+ }
+
+ void test_peak_after_push() {
+ stack_push(stack, 1);
+ TS_ASSERT_EQUALS(1, stack_peak(stack))
+ }
+
+ void test_initial_capacity_is_positive() {
+ TS_ASSERT(stack_capacity(stack) > 0);
+ }
+
+ void test_pop_on_empty() {
+ TS_ASSERT_EQUALS(0, stack_pop(stack));
+ TS_ASSERT_EQUALS(0, stack_size(stack));
+ }
+
+ void test_peak_on_empty() {
+ TS_ASSERT_EQUALS(0, stack_peak(stack));
+ }
+
+ void test_capacity_gte_size() {
+ TS_ASSERT_LESS_THAN_EQUALS(stack_size(stack), stack_capacity(stack));
+ int init_capacity = stack_capacity(stack);
+ for (int i=0; i < init_capacity + 1; i++) {
+ stack_push(stack, i);
+ }
+ TS_ASSERT_LESS_THAN_EQUALS(stack_size(stack), stack_capacity(stack));
+ }
+
+};
+
+#endif // STACK_TEST_H
+
diff --git a/third-party/cxxtest/sample/SimpleTest.h b/third-party/cxxtest/sample/SimpleTest.h
new file mode 100644
index 00000000..159b534e
--- /dev/null
+++ b/third-party/cxxtest/sample/SimpleTest.h
@@ -0,0 +1,58 @@
+#ifndef __SIMPLETEST_H
+#define __SIMPLETEST_H
+
+#include
+
+//
+// A simple test suite: Just inherit CxxTest::TestSuite and write tests!
+//
+
+class SimpleTest : public CxxTest::TestSuite {
+public:
+ void testEquality() {
+ TS_ASSERT_EQUALS(1, 1);
+ TS_ASSERT_EQUALS(1, 2);
+ TS_ASSERT_EQUALS('a', 'A');
+ TS_ASSERT_EQUALS(1.0, -12345678900000000000000000000000000000000000000000.1234);
+ const char* tmp = "foo";
+ TS_ASSERT_EQUALS("foo", tmp);
+ }
+
+ void testAddition() {
+ TS_ASSERT_EQUALS(1 + 1, 2);
+ TS_ASSERT_EQUALS(2 + 2, 5);
+ }
+
+ void TestMultiplication() {
+ TS_ASSERT_EQUALS(2 * 2, 4);
+ TS_ASSERT_EQUALS(4 * 4, 44);
+ TS_ASSERT_DIFFERS(-2 * -2, 4);
+ }
+
+ void testComparison() {
+ TS_ASSERT_LESS_THAN((int)1, (unsigned long)2);
+ TS_ASSERT_LESS_THAN(-1, -2);
+ }
+
+ void testTheWorldIsCrazy() {
+ TS_ASSERT_EQUALS(true, false);
+ }
+
+ void test_Failure() {
+ TS_FAIL("Not implemented");
+ TS_FAIL(1569779912);
+ }
+
+ void test_TS_SKIP_macro() {
+ TS_SKIP("Simply skip this test");
+ TS_WARN("Skipping will abort the test");
+ }
+
+ void test_TS_WARN_macro() {
+ TS_WARN("Just a friendly warning");
+ TS_WARN("Warnings don't abort the test");
+ }
+};
+
+
+#endif // __SIMPLETEST_H
diff --git a/third-party/cxxtest/sample/TraitsTest.h b/third-party/cxxtest/sample/TraitsTest.h
new file mode 100644
index 00000000..ed5a499d
--- /dev/null
+++ b/third-party/cxxtest/sample/TraitsTest.h
@@ -0,0 +1,63 @@
+#ifndef __TRAITSTEST_H
+#define __TRAITSTEST_H
+
+//
+// This example shows how to use TS_ASSERT_EQUALS for your own classes
+//
+#include
+#include
+
+//
+// Define your class with operator==
+//
+#include
+#include
+
+class Pet {
+ char _name[128];
+public:
+ Pet(const char *petName) { strcpy(_name, petName); }
+
+ const char *name() const { return _name; }
+
+ bool operator== (const Pet &other) const {
+ return !strcmp(name(), other.name());
+ }
+};
+
+//
+// Instantiate CxxTest::ValueTraits<*your class*>
+// Note: Most compilers do not require that you define both
+// ValueTraits and ValueTraits, but some do.
+//
+namespace CxxTest {
+CXXTEST_TEMPLATE_INSTANTIATION
+class ValueTraits {
+ char _asString[256];
+
+public:
+ ValueTraits(const Pet &pet) { sprintf(_asString, "Pet(\"%s\")", pet.name()); }
+ const char *asString() const { return _asString; }
+};
+
+CXXTEST_COPY_CONST_TRAITS(Pet);
+}
+
+//
+// Here's how it works
+//
+class TestFunky : public CxxTest::TestSuite {
+public:
+ void testPets() {
+ Pet pet1("dog"), pet2("cat");
+ TS_ASSERT_EQUALS(pet1, pet2);
+ Pet cat("cat"), gato("cat");
+ TS_ASSERT_DIFFERS(cat, gato);
+#ifdef _CXXTEST_HAVE_STD
+ typedef CXXTEST_STD(string) String;
+ TS_ASSERT_EQUALS(String("Hello"), String("World!"));
+#endif // _CXXTEST_HAVE_STD
+ }
+};
+
+#endif // __TRAITSTEST_H
diff --git a/third-party/cxxtest/sample/aborter.tpl b/third-party/cxxtest/sample/aborter.tpl
new file mode 100644
index 00000000..14fc50d2
--- /dev/null
+++ b/third-party/cxxtest/sample/aborter.tpl
@@ -0,0 +1,16 @@
+// -*- C++ -*-
+// This template file demonstrates the use of CXXTEST_ABORT_TEST_ON_FAIL
+//
+
+#define CXXTEST_HAVE_STD
+#define CXXTEST_ABORT_TEST_ON_FAIL
+#include
+
+int main()
+{
+ return CxxTest::ErrorPrinter().run();
+}
+
+// The CxxTest "world"
+
+
diff --git a/third-party/cxxtest/sample/file_printer.tpl b/third-party/cxxtest/sample/file_printer.tpl
new file mode 100644
index 00000000..a9627d6d
--- /dev/null
+++ b/third-party/cxxtest/sample/file_printer.tpl
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+// This is a sample of a custom test runner
+// using CxxTest template files.
+// This prints the output to a file given on the command line.
+//
+
+#include
+#include
+
+int main( int argc, char *argv[] )
+{
+ if ( argc != 2 ) {
+ fprintf( stderr, "Usage: %s