From dd42f97e430af30c4f98c465faf3731700c436ea Mon Sep 17 00:00:00 2001 From: benrubson Date: Sat, 5 Aug 2017 13:12:38 +0200 Subject: [PATCH 01/25] Add missing options to man page and reorganize it --- encfs/encfs.pod | 260 ++++++++++++++++++++++++++---------------------- 1 file changed, 139 insertions(+), 121 deletions(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 65414ef..4eceaca 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -16,12 +16,13 @@ encfs - mounts or creates an encrypted virtual filesystem =head1 SYNOPSIS -B [B<--version>] [B<-s>] [B<-f>] [B<-v>|B<--verbose>] -[B<-i MINUTES>|B<--idle=MINUTES>] [B<--extpass=program>] -[B<-S>|B<--stdinpass>] [B<--anykey>] [B<--forcedecode>] -[B<-d>|B<--fuse-debug>] [B<--public>] [B<--no-default-flags>] -[B<--ondemand>] [B<--delaymount>] [B<--reverse>] [B<--standard>] -[B<-o FUSE_OPTION>] +B [B<--version>] [B<-v>|B<--verbose>] [B<-t>|B<--syslogtag>] +[B<-s>] [B<-f>] [B<--annotate>] [B<--standard>] [B<--paranoia>] +[B<--reverse>] [B<--extpass=program>] [B<-S>|B<--stdinpass>] +[B<--anykey>] [B<--forcedecode>] [B<-require-macs>] +[B<-i MINUTES>|B<--idle=MINUTES>] [B<-m>|B<--ondemand>] [B<--delaymount>] +[B<--public>] [B<--nocache>] [B<--no-default-flags>] +[B<-o FUSE_OPTION>] [B<-d>|B<--fuse-debug>] [B<-H>|B<--fuse-help>] I I [B<--> [I]] @@ -42,22 +43,10 @@ may be an increasing number of choices. =over 4 -=item B<-i>, B<--idle=MINUTES> +=item B<--version> -Enable automatic unmount of the filesystem after a period of inactivity. The -period is specified in minutes, so the shortest timeout period that can be -requested is one minute. B will not automatically unmount if there are -files open within the filesystem, even if they are open in read-only mode. -However simply having files open does not count as activity. - -=item B<-f> - -The B<-f> (I) option causes B to run in the foreground. -Normally B spawns off as a daemon and runs in the background, returning -control to the spawning shell. With the B<-f> option, it will run in the -foreground and any warning/debug log messages will be displayed on standard -error. In the default (background) mode, all log messages are logged via -syslog. +Shows B version. Using B<--verbose> before B<--version> may display +additional information. =item B<-v>, B<--verbose> @@ -78,62 +67,31 @@ mode. By default, B runs in multi-threaded mode. This option is used during B development in order to simplify debugging and allow it to run under memory checking tools. -=item B<-d>, B<--fuse-debug> +=item B<-f> -Enables debugging within the B library. This should only be used if you -suspect a problem within B itself (not B), as it generates a lot -of low-level data and is not likely to be very helpful in general problem -tracking. Try I mode (B<-v>) first, which gives a higher level view -of what is happening within B. +The B<-f> (I) option causes B to run in the foreground. +Normally B spawns off as a daemon and runs in the background, returning +control to the spawning shell. With the B<-f> option, it will run in the +foreground and any warning/debug log messages will be displayed on standard +error. In the default (background) mode, all log messages are logged via +syslog. -=item B<--forcedecode> +=item B<--annotate> -This option only has an effect on filesystems which use MAC block headers. By -default, if a block is decoded and the stored MAC doesn't match what is -calculated, then an IO error is returned to the application and the block is -not returned. However, by specifying B<--forcedecode>, only an error will be -logged and the data will still be returned to the application. This may be -useful for attempting to read corrupted files. +Print annotation lines to stderr during configuration. -=item B<--public> +=item B<--standard> -Attempt to make encfs behave as a typical multi-user filesystem. By default, -all FUSE based filesystems are visible only to the user who mounted them. No -other users (including root) can view the filesystem contents. The B<--public> -option does two things. It adds the FUSE flags "allow_other" and -"default_permission" when mounting the filesystem, which tells FUSE to allow -other users to access the filesystem, and to use the ownership permissions -provided by the filesystem. Secondly, the B<--public> flag changes how encfs's -node creation functions work - as they will try and set ownership of new nodes -based on the caller identification. +If creating a new filesystem, this automatically selects standard configuration +options, to help with automatic filesystem creation. This is the set of +options that should be used unless you know what you're doing and have read the +documentation. -B: In order for this to work, encfs must be run as root -- otherwise -it will not have the ability to change ownership of files. I recommend that -you instead investigate if the fuse allow_other option can be used to do what -you want before considering the use of B<--public>. +When not creating a filesystem, this flag does nothing. -=item B<--ondemand> +=item B<--paranoia> -Mount the filesystem on-demand. This currently only makes sense in combination -with B<--idle> and B<--extpass> options. When the filesystem becomes idle, -instead of exiting, B stops allowing access to the filesystem by -internally dropping its reference to it. If someone attempts to access the -filesystem again, the extpass program is used to prompt the user for the -password. If this succeeds, then the filesystem becomes available again. - -=item B<--delaymount> - -Do not mount the filesystem when encfs starts; instead, delay mounting until -first use. This option only makes sense with B<--ondemand>. - -=item B<--require-macs> - -If creating a new filesystem, this forces block authentication code headers to -be enabled. When mounting an existing filesystem, this causes encfs to exit -if block authentication code headers are not enabled. - -This can be used to improve security in case the ciphertext is vulnerable to -tampering, by preventing an attacker from disabling MACs in the config file. +Same as =item B<--standard>, but for B mode. =item B<--reverse> @@ -159,58 +117,6 @@ Now /tmp/plain-view contains the same data as /home/me Note that B<--reverse> mode only works with limited configuration options, so many settings may be disabled when used. -=item B<--nocache> - -Disable the kernel's cache of file attributes. -Setting this option makes EncFS pass "attr_timeout=0" and "entry_timeout=0" to -FUSE. This makes sure that modifications to the backing files that occour -outside EncFS show up immediately in the EncFS mount. The main use case -for "--nocache" is reverse mode. - -=item B<--standard> - -If creating a new filesystem, this automatically selects standard configuration -options, to help with automatic filesystem creation. This is the set of -options that should be used unless you know what you're doing and have read the -documentation. - -When not creating a filesystem, this flag does nothing. - -=item B<-o FUSE_ARG> - -Pass through B args to the underlying library. This makes it easy to -pass FUSE options when mounting B via mount (and /etc/fstab). Eg: - - mount encfs#/home/me-crypt /home/me -t fuse -o kernel_cache - -Note that encfs arguments cannot be set this way. If you need to set encfs -arguments, create a wrapper, such as encfs-reverse; - - #!/bin/sh - encfs --reverse "$@" - -Then mount using the script path - - mount encfs-reverse#/home/me /home/me-crypt -t fuse - -=item B<--> - -The B<--> option tells B to send any remaining arguments directly to -B. In turn, B passes the arguments to B. See -the B help page for information on available commands. - -=item B<--no-default-flags> - -B adds the FUSE flags "use_ino" and "default_permissions" by default, as -of version 1.2.2, because that improves compatibility with some programs. If -for some reason you need to disable one or both of these flags, use the option -B<--no-default-flags>. - -The following command lines produce the same result: - - encfs raw crypt - encfs --no-default-flags raw crypt -- -o use_ino,default_permissions - =item B<--extpass=program> Specify an external program to use for getting the user password. When the @@ -252,6 +158,118 @@ which will not remain the same if the primary password is changed. B: Use this option at your own risk. +=item B<--forcedecode> + +This option only has an effect on filesystems which use MAC block headers. By +default, if a block is decoded and the stored MAC doesn't match what is +calculated, then an IO error is returned to the application and the block is +not returned. However, by specifying B<--forcedecode>, only an error will be +logged and the data will still be returned to the application. This may be +useful for attempting to read corrupted files. + +=item B<--require-macs> + +If creating a new filesystem, this forces block authentication code headers to +be enabled. When mounting an existing filesystem, this causes encfs to exit +if block authentication code headers are not enabled. + +This can be used to improve security in case the ciphertext is vulnerable to +tampering, by preventing an attacker from disabling MACs in the config file. + +=item B<-i>, B<--idle=MINUTES> + +Enable automatic unmount of the filesystem after a period of inactivity. The +period is specified in minutes, so the shortest timeout period that can be +requested is one minute. B will not automatically unmount if there are +files open within the filesystem, even if they are open in read-only mode. +However simply having files open does not count as activity. + +=item B<-m>, B<--ondemand> + +Mount the filesystem on-demand. This currently only makes sense in combination +with B<--idle> and B<--extpass> options. When the filesystem becomes idle, +instead of exiting, B stops allowing access to the filesystem by +internally dropping its reference to it. If someone attempts to access the +filesystem again, the extpass program is used to prompt the user for the +password. If this succeeds, then the filesystem becomes available again. + +=item B<--delaymount> + +Do not mount the filesystem when encfs starts; instead, delay mounting until +first use. This option only makes sense with B<--ondemand>. + +=item B<--public> + +Attempt to make encfs behave as a typical multi-user filesystem. By default, +all FUSE based filesystems are visible only to the user who mounted them. No +other users (including root) can view the filesystem contents. The B<--public> +option does two things. It adds the FUSE flags "allow_other" and +"default_permission" when mounting the filesystem, which tells FUSE to allow +other users to access the filesystem, and to use the ownership permissions +provided by the filesystem. Secondly, the B<--public> flag changes how encfs's +node creation functions work - as they will try and set ownership of new nodes +based on the caller identification. + +B: In order for this to work, encfs must be run as root -- otherwise +it will not have the ability to change ownership of files. I recommend that +you instead investigate if the fuse allow_other option can be used to do what +you want before considering the use of B<--public>. + +=item B<--nocache> + +Disable the kernel's cache of file attributes. +Setting this option makes EncFS pass "attr_timeout=0" and "entry_timeout=0" to +FUSE. This makes sure that modifications to the backing files that occour +outside EncFS show up immediately in the EncFS mount. The main use case +for "--nocache" is reverse mode. + +=item B<--no-default-flags> + +B adds the FUSE flags "use_ino" and "default_permissions" by default, as +of version 1.2.2, because that improves compatibility with some programs. If +for some reason you need to disable one or both of these flags, use the option +B<--no-default-flags>. + +The following command lines produce the same result: + + encfs raw crypt + encfs --no-default-flags raw crypt -- -o use_ino,default_permissions + +=item B<-o FUSE_ARG> + +Pass through B args to the underlying library. This makes it easy to +pass FUSE options when mounting B via mount (and /etc/fstab). Eg: + + mount encfs#/home/me-crypt /home/me -t fuse -o kernel_cache + +Note that encfs arguments cannot be set this way. If you need to set encfs +arguments, create a wrapper, such as encfs-reverse; + + #!/bin/sh + encfs --reverse "$@" + +Then mount using the script path + + mount encfs-reverse#/home/me /home/me-crypt -t fuse + +=item B<-d>, B<--fuse-debug> + +Enables debugging within the B library. This should only be used if you +suspect a problem within B itself (not B), as it generates a lot +of low-level data and is not likely to be very helpful in general problem +tracking. Try I mode (B<-v>) first, which gives a higher level view +of what is happening within B. + +=item B<-H>, B<--fuse-help> + +Shows B help. + +=item B<--> + +The B<--> option tells B to send any remaining arguments directly to +B. In turn, B passes the arguments to B. See +the B help page for information on available commands. + =back =head1 ENVIRONMENT VARIABLES From 8c9886d6b051839c0e78f4a44cfbb2cc40e9bd60 Mon Sep 17 00:00:00 2001 From: benrubson Date: Sat, 5 Aug 2017 13:16:29 +0200 Subject: [PATCH 02/25] Add missing options to man page and reorganize it, typo --- encfs/encfs.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 4eceaca..c216169 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -91,7 +91,7 @@ When not creating a filesystem, this flag does nothing. =item B<--paranoia> -Same as =item B<--standard>, but for B mode. +Same as B<--standard>, but for B mode. =item B<--reverse> From 04e23b50d8ad94e3cee098ba4ee31976976c5902 Mon Sep 17 00:00:00 2001 From: benrubson Date: Sat, 5 Aug 2017 13:40:52 +0200 Subject: [PATCH 03/25] Tune syslog logging --- encfs/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encfs/main.cpp b/encfs/main.cpp index 0d0e6bb..5c97b30 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -569,7 +569,7 @@ int main(int argc, char *argv[]) { } encfs::initLogging(encfsArgs->isVerbose, encfsArgs->isDaemon); - ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), 0, 0); + ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_LOCAL7); VLOG(1) << "Root directory: " << encfsArgs->opts->rootDir; VLOG(1) << "Fuse arguments: " << encfsArgs->toString(); From 69f42276a0a0dd80abe4ca6afc6f8cb7db7d7031 Mon Sep 17 00:00:00 2001 From: benrubson Date: Sat, 5 Aug 2017 13:45:31 +0200 Subject: [PATCH 04/25] Tune syslog logging, typo --- encfs/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encfs/main.cpp b/encfs/main.cpp index 5c97b30..48e432f 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -569,7 +569,7 @@ int main(int argc, char *argv[]) { } encfs::initLogging(encfsArgs->isVerbose, encfsArgs->isDaemon); - ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_LOCAL7); + ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_USER); VLOG(1) << "Root directory: " << encfsArgs->opts->rootDir; VLOG(1) << "Fuse arguments: " << encfsArgs->toString(); From 75c63e9267ca8831f61f5dab92228573386c70db Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 5 Aug 2017 22:59:07 -0700 Subject: [PATCH 05/25] drop old internal tinyxml2 --- internal/tinyxml2-3.0.0/.gitignore | 13 - internal/tinyxml2-3.0.0/CMakeLists.txt | 79 - internal/tinyxml2-3.0.0/Makefile | 6 - .../tinyxml2-3.0.0/contrib/html5-printer.cpp | 108 - internal/tinyxml2-3.0.0/readme.md | 324 -- internal/tinyxml2-3.0.0/resources/dream.xml | 4546 ----------------- internal/tinyxml2-3.0.0/resources/empty.xml | 0 .../tinyxml2-3.0.0/resources/utf8test.xml | 11 - .../resources/utf8testverify.xml | 11 - internal/tinyxml2-3.0.0/setversion.py | 123 - internal/tinyxml2-3.0.0/tinyxml2.cpp | 2344 --------- internal/tinyxml2-3.0.0/tinyxml2.h | 2130 -------- internal/tinyxml2-3.0.0/tinyxml2.pc.in | 10 - internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj | 347 -- .../tinyxml2/test.vcxproj.filters | 6 - .../tinyxml2/tinyxml2-cbp/README | 3 - .../tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp | 49 - internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.sln | 56 - .../tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj | 384 -- .../tinyxml2/tinyxml2.vcxproj.filters | 9 - .../tinyxml2.xcodeproj/project.pbxproj | 211 - internal/tinyxml2-3.0.0/xmltest.cpp | 1489 ------ 22 files changed, 12259 deletions(-) delete mode 100644 internal/tinyxml2-3.0.0/.gitignore delete mode 100644 internal/tinyxml2-3.0.0/CMakeLists.txt delete mode 100644 internal/tinyxml2-3.0.0/Makefile delete mode 100644 internal/tinyxml2-3.0.0/contrib/html5-printer.cpp delete mode 100644 internal/tinyxml2-3.0.0/readme.md delete mode 100755 internal/tinyxml2-3.0.0/resources/dream.xml delete mode 100644 internal/tinyxml2-3.0.0/resources/empty.xml delete mode 100755 internal/tinyxml2-3.0.0/resources/utf8test.xml delete mode 100755 internal/tinyxml2-3.0.0/resources/utf8testverify.xml delete mode 100755 internal/tinyxml2-3.0.0/setversion.py delete mode 100755 internal/tinyxml2-3.0.0/tinyxml2.cpp delete mode 100755 internal/tinyxml2-3.0.0/tinyxml2.h delete mode 100644 internal/tinyxml2-3.0.0/tinyxml2.pc.in delete mode 100644 internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj delete mode 100644 internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj.filters delete mode 100644 internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/README delete mode 100644 internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp delete mode 100755 internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.sln delete mode 100755 internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj delete mode 100755 internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj.filters delete mode 100644 internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.xcodeproj/project.pbxproj delete mode 100644 internal/tinyxml2-3.0.0/xmltest.cpp diff --git a/internal/tinyxml2-3.0.0/.gitignore b/internal/tinyxml2-3.0.0/.gitignore deleted file mode 100644 index a765577..0000000 --- a/internal/tinyxml2-3.0.0/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# intermediate files -Win32/ -x64/ -ipch/ -resources/out/ -tinyxml2/tinyxml2-cbp/bin/ -tinyxml2/tinyxml2-cbp/obj/ -*.sdf -*.suo -*.opensdf -*.user -*.depend -*.layout \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/CMakeLists.txt b/internal/tinyxml2-3.0.0/CMakeLists.txt deleted file mode 100644 index e8d0abb..0000000 --- a/internal/tinyxml2-3.0.0/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -cmake_minimum_required(VERSION 2.6 FATAL_ERROR) -cmake_policy(VERSION 2.6) - -project(tinyxml2) -include(GNUInstallDirs) -#enable_testing() - -#CMAKE_BUILD_TOOL - -################################ -# set lib version here - -set(GENERIC_LIB_VERSION "3.0.0") -set(GENERIC_LIB_SOVERSION "3") - - -################################ -# Add common source - -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.") - -################################ -# Add custom target to copy all data - -set(TARGET_DATA_COPY DATA_COPY) -if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) - add_custom_target( - ${TARGET_DATA_COPY} - COMMAND ${CMAKE_COMMAND} -E echo "In source build") -else(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) - make_directory(${CMAKE_CURRENT_BINARY_DIR}/resources/) - add_custom_target( - ${TARGET_DATA_COPY} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/dream.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/ - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/empty.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/ - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/utf8test.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/ - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/utf8testverify.xml ${CMAKE_CURRENT_BINARY_DIR}/resources/) -endif(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) - -################################ -# Add definitions - -if(MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) -endif(MSVC) - -################################ -# Add targets -option(BUILD_SHARED_LIBS "build shared or static libraries" OFF) -add_library(tinyxml2 tinyxml2.cpp tinyxml2.h) -set_target_properties(tinyxml2 PROPERTIES - COMPILE_DEFINITIONS "TINYXML2_EXPORT" - VERSION "${GENERIC_LIB_VERSION}" - SOVERSION "${GENERIC_LIB_SOVERSION}") - -add_executable(xmltest xmltest.cpp) -add_dependencies(xmltest tinyxml2) -add_dependencies(xmltest ${TARGET_DATA_COPY}) -target_link_libraries(xmltest tinyxml2) - - -#install(TARGETS tinyxml2 -# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} -# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -#install(FILES tinyxml2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -#foreach(p LIB INCLUDE) -# set(var CMAKE_INSTALL_${p}DIR) -# if(NOT IS_ABSOLUTE "${${var}}") -# set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") -# endif() -#endforeach() - -#configure_file(tinyxml2.pc.in tinyxml2.pc @ONLY) -#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - -#add_test(xmltest ${SAMPLE_NAME} COMMAND $) diff --git a/internal/tinyxml2-3.0.0/Makefile b/internal/tinyxml2-3.0.0/Makefile deleted file mode 100644 index aab6293..0000000 --- a/internal/tinyxml2-3.0.0/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: xmltest -xmltest: xmltest.cpp tinyxml2.cpp tinyxml2.h -test: clean xmltest - ./xmltest -clean: - rm -f *.o xmltest diff --git a/internal/tinyxml2-3.0.0/contrib/html5-printer.cpp b/internal/tinyxml2-3.0.0/contrib/html5-printer.cpp deleted file mode 100644 index 3205ccd..0000000 --- a/internal/tinyxml2-3.0.0/contrib/html5-printer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// g++ -Wall -O2 contrib/html5-printer.cpp -o html5-printer -ltinyxml2 - -// This program demonstrates how to use "tinyxml2" to generate conformant HTML5 -// by deriving from the "tinyxml2::XMLPrinter" class. - -// http://dev.w3.org/html5/markup/syntax.html - -// In HTML5, there are 16 so-called "void" elements. "void elements" NEVER have -// inner content (but they MAY have attributes), and are assumed to be self-closing. -// An example of a self-closig HTML5 element is "
" (line break) -// All other elements are called "non-void" and MUST never self-close. -// Examples: "
". - -// tinyxml2::XMLPrinter will emit _ALL_ XML elements with no inner content as -// self-closing. This behavior produces space-effeceint XML, but incorrect HTML5. - -// Author: Dennis Jenkins, dennis (dot) jenkins (dot) 75 (at) gmail (dot) com. -// License: Same as tinyxml2 (zlib, see below) -// This example is a small contribution to the world! Enjoy it! - -/* -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#include -#include - -#if defined (_MSC_VER) -#define strcasecmp stricmp -#endif - -using namespace tinyxml2; - -// Contrived input containing a mix of void and non-void HTML5 elements. -// When printed via XMLPrinter, some non-void elements will self-close (not valid HTML5). -static const char input[] = -"


©
"; - -// XMLPrinterHTML5 is small enough, just put the entire implementation inline. -class XMLPrinterHTML5 : public XMLPrinter -{ -public: - XMLPrinterHTML5 (FILE* file=0, bool compact = false, int depth = 0) : - XMLPrinter (file, compact, depth) - {} - -protected: - virtual void CloseElement () { - if (_elementJustOpened && !isVoidElement (_stack.PeekTop())) { - SealElement(); - } - XMLPrinter::CloseElement(); - } - - virtual bool isVoidElement (const char *name) { -// Complete list of all HTML5 "void elements", -// http://dev.w3.org/html5/markup/syntax.html - static const char *list[] = { - "area", "base", "br", "col", "command", "embed", "hr", "img", - "input", "keygen", "link", "meta", "param", "source", "track", "wbr", - NULL - }; - -// I could use 'bsearch', but I don't have MSVC to test on (it would work with gcc/libc). - for (const char **p = list; *p; ++p) { - if (!strcasecmp (name, *p)) { - return true; - } - } - - return false; - } -}; - -int main (void) { - XMLDocument doc (false); - doc.Parse (input); - - std::cout << "INPUT:\n" << input << "\n\n"; - - XMLPrinter prn (NULL, true); - doc.Print (&prn); - std::cout << "XMLPrinter (not valid HTML5):\n" << prn.CStr() << "\n\n"; - - XMLPrinterHTML5 html5 (NULL, true); - doc.Print (&html5); - std::cout << "XMLPrinterHTML5:\n" << html5.CStr() << "\n"; - - return 0; -} diff --git a/internal/tinyxml2-3.0.0/readme.md b/internal/tinyxml2-3.0.0/readme.md deleted file mode 100644 index 485e00f..0000000 --- a/internal/tinyxml2-3.0.0/readme.md +++ /dev/null @@ -1,324 +0,0 @@ -TinyXML-2 -========= -![TinyXML-2 Logo](http://www.grinninglizard.com/tinyxml2/TinyXML2_small.png) - -TinyXML-2 is a simple, small, efficient, C++ XML parser that can be -easily integrated into other programs. - -The master is hosted on github: -https://github.com/leethomason/tinyxml2 - -The online HTML version of these docs: -http://grinninglizard.com/tinyxml2docs/index.html - -Examples are in the "related pages" tab of the HTML docs. - -What it does. -------------- - -In brief, TinyXML-2 parses an XML document, and builds from that a -Document Object Model (DOM) that can be read, modified, and saved. - -XML stands for "eXtensible Markup Language." It is a general purpose -human and machine readable markup language to describe arbitrary data. -All those random file formats created to store application data can -all be replaced with XML. One parser for everything. - -http://en.wikipedia.org/wiki/XML - -There are different ways to access and interact with XML data. -TinyXML-2 uses a Document Object Model (DOM), meaning the XML data is parsed -into a C++ objects that can be browsed and manipulated, and then -written to disk or another output stream. You can also construct an XML document -from scratch with C++ objects and write this to disk or another output -stream. You can even use TinyXML-2 to stream XML programmatically from -code without creating a document first. - -TinyXML-2 is designed to be easy and fast to learn. It is one header and -one cpp file. Simply add these to your project and off you go. -There is an example file - xmltest.cpp - to get you started. - -TinyXML-2 is released under the ZLib license, -so you can use it in open source or commercial code. The details -of the license are at the top of every source file. - -TinyXML-2 attempts to be a flexible parser, but with truly correct and -compliant XML output. TinyXML-2 should compile on any reasonably C++ -compliant system. It does not rely on exceptions, RTTI, or the STL. - -What it doesn't do. -------------------- - -TinyXML-2 doesn't parse or use DTDs (Document Type Definitions) or XSLs -(eXtensible Stylesheet Language.) There are other parsers out there -that are much more fully featured. But they are also much bigger, -take longer to set up in your project, have a higher learning curve, -and often have a more restrictive license. If you are working with -browsers or have more complete XML needs, TinyXML-2 is not the parser for you. - -TinyXML-1 vs. TinyXML-2 ------------------------ - -TinyXML-2 is now the focus of all development, well tested, and your -best choice unless you have a requirement to maintain TinyXML-1 code. - -TinyXML-2 uses a similar API to TinyXML-1 and the same -rich test cases. But the implementation of the parser is completely re-written -to make it more appropriate for use in a game. It uses less memory, is faster, -and uses far fewer memory allocations. - -TinyXML-2 has no requirement for STL, but has also dropped all STL support. All -strings are query and set as 'const char*'. This allows the use of internal -allocators, and keeps the code much simpler. - -Both parsers: - -1. Simple to use with similar APIs. -2. DOM based parser. -3. UTF-8 Unicode support. http://en.wikipedia.org/wiki/UTF-8 - -Advantages of TinyXML-2 - -1. The focus of all future dev. -2. Many fewer memory allocation (1/10th to 1/100th), uses less memory - (about 40% of TinyXML-1), and faster. -3. No STL requirement. -4. More modern C++, including a proper namespace. -5. Proper and useful handling of whitespace - -Advantages of TinyXML-1 - -1. Can report the location of parsing errors. -2. Support for some C++ STL conventions: streams and strings -3. Very mature and well debugged code base. - -Features --------- - -### Memory Model - -An XMLDocument is a C++ object like any other, that can be on the stack, or -new'd and deleted on the heap. - -However, any sub-node of the Document, XMLElement, XMLText, etc, can only -be created by calling the appropriate XMLDocument::NewElement, NewText, etc. -method. Although you have pointers to these objects, they are still owned -by the Document. When the Document is deleted, so are all the nodes it contains. - -### White Space - -#### Whitespace Preservation (default) - -Microsoft has an excellent article on white space: http://msdn.microsoft.com/en-us/library/ms256097.aspx - -By default, TinyXML-2 preserves white space in a (hopefully) sane way that is almost complient with the -spec. (TinyXML-1 used a completely different model, much more similar to 'collapse', below.) - -As a first step, all newlines / carriage-returns / line-feeds are normalized to a -line-feed character, as required by the XML spec. - -White space in text is preserved. For example: - - Hello, World - -The leading space before the "Hello" and the double space after the comma are -preserved. Line-feeds are preserved, as in this example: - - Hello again, - World - -However, white space between elements is **not** preserved. Although not strictly -compliant, tracking and reporting inter-element space is awkward, and not normally -valuable. TinyXML-2 sees these as the same XML: - - - 1 - 2 - 3 - - - 123 - -#### Whitespace Collapse - -For some applications, it is preferable to collapse whitespace. Collapsing -whitespace gives you "HTML-like" behavior, which is sometimes more suitable -for hand typed documents. - -TinyXML-2 supports this with the 'whitespace' parameter to the XMLDocument constructor. -(The default is to preserve whitespace, as described above.) - -However, you may also use COLLAPSE_WHITESPACE, which will: - -* Remove leading and trailing whitespace -* Convert newlines and line-feeds into a space character -* Collapse a run of any number of space characters into a single space character - -Note that (currently) there is a performance impact for using COLLAPSE_WHITESPACE. -It essentially causes the XML to be parsed twice. - -### Entities - -TinyXML-2 recognizes the pre-defined "character entities", meaning special -characters. Namely: - - & & - < < - > > - " " - ' ' - -These are recognized when the XML document is read, and translated to their -UTF-8 equivalents. For instance, text with the XML of: - - Far & Away - -will have the Value() of "Far & Away" when queried from the XMLText object, -and will be written back to the XML stream/file as an ampersand. - -Additionally, any character can be specified by its Unicode code point: -The syntax " " or " " are both to the non-breaking space characher. -This is called a 'numeric character reference'. Any numeric character reference -that isn't one of the special entities above, will be read, but written as a -regular code point. The output is correct, but the entity syntax isn't preserved. - -### Printing - -#### Print to file -You can directly use the convenience function: - - XMLDocument doc; - ... - doc.SaveFile( "foo.xml" ); - -Or the XMLPrinter class: - - XMLPrinter printer( fp ); - doc.Print( &printer ); - -#### Print to memory -Printing to memory is supported by the XMLPrinter. - - XMLPrinter printer; - doc.Print( &printer ); - // printer.CStr() has a const char* to the XML - -#### Print without an XMLDocument - -When loading, an XML parser is very useful. However, sometimes -when saving, it just gets in the way. The code is often set up -for streaming, and constructing the DOM is just overhead. - -The Printer supports the streaming case. The following code -prints out a trivially simple XML file without ever creating -an XML document. - - XMLPrinter printer( fp ); - printer.OpenElement( "foo" ); - printer.PushAttribute( "foo", "bar" ); - printer.CloseElement(); - -Examples --------- - -#### Load and parse an XML file. - - /* ------ Example 1: Load and parse an XML file. ---- */ - { - XMLDocument doc; - doc.LoadFile( "dream.xml" ); - } - -#### Lookup information. - - /* ------ Example 2: Lookup information. ---- */ - { - XMLDocument doc; - doc.LoadFile( "dream.xml" ); - - // Structure of the XML file: - // - Element "PLAY" the root Element, which is the - // FirstChildElement of the Document - // - - Element "TITLE" child of the root PLAY Element - // - - - Text child of the TITLE Element - - // Navigate to the title, using the convenience function, - // with a dangerous lack of error checking. - const char* title = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->GetText(); - printf( "Name of play (1): %s\n", title ); - - // Text is just another Node to TinyXML-2. The more - // general way to get to the XMLText: - XMLText* textNode = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->FirstChild()->ToText(); - title = textNode->Value(); - printf( "Name of play (2): %s\n", title ); - } - -Using and Installing --------------------- - -There are 2 files in TinyXML-2: -* tinyxml2.cpp -* tinyxml2.h - -And additionally a test file: -* xmltest.cpp - -Simply compile and run. There is a visual studio 2010 project included, a simple Makefile, -an XCode project, a Code::Blocks project, and a cmake CMakeLists.txt included to help you. -The top of tinyxml.h even has a simple g++ command line if you are are *nix and don't want -to use a build system. - -Versioning ----------- - -TinyXML-2 uses semantic versioning. http://semver.org/ Releases are now tagged in github. - -Note that the major version will (probably) change fairly rapidly. API changes are fairly -common. - -Documentation -------------- - -The documentation is build with Doxygen, using the 'dox' -configuration file. - -License -------- - -TinyXML-2 is released under the zlib license: - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source -distribution. - -Contributors ------------- - -Thanks very much to everyone who sends suggestions, bugs, ideas, and -encouragement. It all helps, and makes this project fun. - -The original TinyXML-1 has many contributors, who all deserve thanks -in shaping what is a very successful library. Extra thanks to Yves -Berquin and Andrew Ellerton who were key contributors. - -TinyXML-2 grew from that effort. Lee Thomason is the original author -of TinyXML-2 (and TinyXML-1) but TinyXML-2 has been and is being improved -by many contributors. - -Thanks to John Mackay at http://john.mackay.rosalilastudio.com for the TinyXML-2 logo! - - diff --git a/internal/tinyxml2-3.0.0/resources/dream.xml b/internal/tinyxml2-3.0.0/resources/dream.xml deleted file mode 100755 index 0a0b17c..0000000 --- a/internal/tinyxml2-3.0.0/resources/dream.xml +++ /dev/null @@ -1,4546 +0,0 @@ - - - - -A Midsummer Night's Dream - - -

Text placed in the public domain by Moby Lexical Tools, 1992.

-

SGML markup by Jon Bosak, 1992-1994.

-

XML version by Jon Bosak, 1996-1998.

-

This work may be freely copied and distributed worldwide.

-
- - - -Dramatis Personae - -THESEUS, Duke of Athens. -EGEUS, father to Hermia. - - -LYSANDER -DEMETRIUS -in love with Hermia. - - -PHILOSTRATE, master of the revels to Theseus. -QUINCE, a carpenter. -SNUG, a joiner. -BOTTOM, a weaver. -FLUTE, a bellows-mender. -SNOUT, a tinker. -STARVELING, a tailor. -HIPPOLYTA, queen of the Amazons, betrothed to Theseus. -HERMIA, daughter to Egeus, in love with Lysander. -HELENA, in love with Demetrius. -OBERON, king of the fairies. -TITANIA, queen of the fairies. -PUCK, or Robin Goodfellow. - - -PEASEBLOSSOM -COBWEB -MOTH -MUSTARDSEED -fairies. - - -Other fairies attending their King and Queen. -Attendants on Theseus and Hippolyta. - - -SCENE Athens, and a wood near it. - -A MIDSUMMER NIGHT'S DREAM - -ACT I - -SCENE I. Athens. The palace of THESEUS. -Enter THESEUS, HIPPOLYTA, PHILOSTRATE, and -Attendants - - -THESEUS -Now, fair Hippolyta, our nuptial hour -Draws on apace; four happy days bring in -Another moon: but, O, methinks, how slow -This old moon wanes! she lingers my desires, -Like to a step-dame or a dowager -Long withering out a young man revenue. - - - -HIPPOLYTA -Four days will quickly steep themselves in night; -Four nights will quickly dream away the time; -And then the moon, like to a silver bow -New-bent in heaven, shall behold the night -Of our solemnities. - - - -THESEUS -Go, Philostrate, -Stir up the Athenian youth to merriments; -Awake the pert and nimble spirit of mirth; -Turn melancholy forth to funerals; -The pale companion is not for our pomp. -Exit PHILOSTRATE -Hippolyta, I woo'd thee with my sword, -And won thy love, doing thee injuries; -But I will wed thee in another key, -With pomp, with triumph and with revelling. - - - -Enter EGEUS, HERMIA, LYSANDER, and DEMETRIUS - - -EGEUS -Happy be Theseus, our renowned duke! - - - -THESEUS -Thanks, good Egeus: what's the news with thee? - - - -EGEUS -Full of vexation come I, with complaint -Against my child, my daughter Hermia. -Stand forth, Demetrius. My noble lord, -This man hath my consent to marry her. -Stand forth, Lysander: and my gracious duke, -This man hath bewitch'd the bosom of my child; -Thou, thou, Lysander, thou hast given her rhymes, -And interchanged love-tokens with my child: -Thou hast by moonlight at her window sung, -With feigning voice verses of feigning love, -And stolen the impression of her fantasy -With bracelets of thy hair, rings, gawds, conceits, -Knacks, trifles, nosegays, sweetmeats, messengers -Of strong prevailment in unharden'd youth: -With cunning hast thou filch'd my daughter's heart, -Turn'd her obedience, which is due to me, -To stubborn harshness: and, my gracious duke, -Be it so she; will not here before your grace -Consent to marry with Demetrius, -I beg the ancient privilege of Athens, -As she is mine, I may dispose of her: -Which shall be either to this gentleman -Or to her death, according to our law -Immediately provided in that case. - - - -THESEUS -What say you, Hermia? be advised fair maid: -To you your father should be as a god; -One that composed your beauties, yea, and one -To whom you are but as a form in wax -By him imprinted and within his power -To leave the figure or disfigure it. -Demetrius is a worthy gentleman. - - - -HERMIA -So is Lysander. - - - -THESEUS -In himself he is; -But in this kind, wanting your father's voice, -The other must be held the worthier. - - - -HERMIA -I would my father look'd but with my eyes. - - - -THESEUS -Rather your eyes must with his judgment look. - - - -HERMIA -I do entreat your grace to pardon me. -I know not by what power I am made bold, -Nor how it may concern my modesty, -In such a presence here to plead my thoughts; -But I beseech your grace that I may know -The worst that may befall me in this case, -If I refuse to wed Demetrius. - - - -THESEUS -Either to die the death or to abjure -For ever the society of men. -Therefore, fair Hermia, question your desires; -Know of your youth, examine well your blood, -Whether, if you yield not to your father's choice, -You can endure the livery of a nun, -For aye to be in shady cloister mew'd, -To live a barren sister all your life, -Chanting faint hymns to the cold fruitless moon. -Thrice-blessed they that master so their blood, -To undergo such maiden pilgrimage; -But earthlier happy is the rose distill'd, -Than that which withering on the virgin thorn -Grows, lives and dies in single blessedness. - - - -HERMIA -So will I grow, so live, so die, my lord, -Ere I will my virgin patent up -Unto his lordship, whose unwished yoke -My soul consents not to give sovereignty. - - - -THESEUS -Take time to pause; and, by the nest new moon-- -The sealing-day betwixt my love and me, -For everlasting bond of fellowship-- -Upon that day either prepare to die -For disobedience to your father's will, -Or else to wed Demetrius, as he would; -Or on Diana's altar to protest -For aye austerity and single life. - - - -DEMETRIUS -Relent, sweet Hermia: and, Lysander, yield -Thy crazed title to my certain right. - - - -LYSANDER -You have her father's love, Demetrius; -Let me have Hermia's: do you marry him. - - - -EGEUS -Scornful Lysander! true, he hath my love, -And what is mine my love shall render him. -And she is mine, and all my right of her -I do estate unto Demetrius. - - - -LYSANDER -I am, my lord, as well derived as he, -As well possess'd; my love is more than his; -My fortunes every way as fairly rank'd, -If not with vantage, as Demetrius'; -And, which is more than all these boasts can be, -I am beloved of beauteous Hermia: -Why should not I then prosecute my right? -Demetrius, I'll avouch it to his head, -Made love to Nedar's daughter, Helena, -And won her soul; and she, sweet lady, dotes, -Devoutly dotes, dotes in idolatry, -Upon this spotted and inconstant man. - - - -THESEUS -I must confess that I have heard so much, -And with Demetrius thought to have spoke thereof; -But, being over-full of self-affairs, -My mind did lose it. But, Demetrius, come; -And come, Egeus; you shall go with me, -I have some private schooling for you both. -For you, fair Hermia, look you arm yourself -To fit your fancies to your father's will; -Or else the law of Athens yields you up-- -Which by no means we may extenuate-- -To death, or to a vow of single life. -Come, my Hippolyta: what cheer, my love? -Demetrius and Egeus, go along: -I must employ you in some business -Against our nuptial and confer with you -Of something nearly that concerns yourselves. - - - -EGEUS -With duty and desire we follow you. - - - -Exeunt all but LYSANDER and HERMIA - - -LYSANDER -How now, my love! why is your cheek so pale? -How chance the roses there do fade so fast? - - - -HERMIA -Belike for want of rain, which I could well -Beteem them from the tempest of my eyes. - - - -LYSANDER -Ay me! for aught that I could ever read, -Could ever hear by tale or history, -The course of true love never did run smooth; -But, either it was different in blood,-- - - - -HERMIA -O cross! too high to be enthrall'd to low. - - - -LYSANDER -Or else misgraffed in respect of years,-- - - - -HERMIA -O spite! too old to be engaged to young. - - - -LYSANDER -Or else it stood upon the choice of friends,-- - - - -HERMIA -O hell! to choose love by another's eyes. - - - -LYSANDER -Or, if there were a sympathy in choice, -War, death, or sickness did lay siege to it, -Making it momentany as a sound, -Swift as a shadow, short as any dream; -Brief as the lightning in the collied night, -That, in a spleen, unfolds both heaven and earth, -And ere a man hath power to say 'Behold!' -The jaws of darkness do devour it up: -So quick bright things come to confusion. - - - -HERMIA -If then true lovers have been ever cross'd, -It stands as an edict in destiny: -Then let us teach our trial patience, -Because it is a customary cross, -As due to love as thoughts and dreams and sighs, -Wishes and tears, poor fancy's followers. - - - -LYSANDER -A good persuasion: therefore, hear me, Hermia. -I have a widow aunt, a dowager -Of great revenue, and she hath no child: -From Athens is her house remote seven leagues; -And she respects me as her only son. -There, gentle Hermia, may I marry thee; -And to that place the sharp Athenian law -Cannot pursue us. If thou lovest me then, -Steal forth thy father's house to-morrow night; -And in the wood, a league without the town, -Where I did meet thee once with Helena, -To do observance to a morn of May, -There will I stay for thee. - - - -HERMIA -My good Lysander! -I swear to thee, by Cupid's strongest bow, -By his best arrow with the golden head, -By the simplicity of Venus' doves, -By that which knitteth souls and prospers loves, -And by that fire which burn'd the Carthage queen, -When the false Troyan under sail was seen, -By all the vows that ever men have broke, -In number more than ever women spoke, -In that same place thou hast appointed me, -To-morrow truly will I meet with thee. - - - -LYSANDER -Keep promise, love. Look, here comes Helena. - - - -Enter HELENA - - -HERMIA -God speed fair Helena! whither away? - - - -HELENA -Call you me fair? that fair again unsay. -Demetrius loves your fair: O happy fair! -Your eyes are lode-stars; and your tongue's sweet air -More tuneable than lark to shepherd's ear, -When wheat is green, when hawthorn buds appear. -Sickness is catching: O, were favour so, -Yours would I catch, fair Hermia, ere I go; -My ear should catch your voice, my eye your eye, -My tongue should catch your tongue's sweet melody. -Were the world mine, Demetrius being bated, -The rest I'd give to be to you translated. -O, teach me how you look, and with what art -You sway the motion of Demetrius' heart. - - - -HERMIA -I frown upon him, yet he loves me still. - - - -HELENA -O that your frowns would teach my smiles such skill! - - - -HERMIA -I give him curses, yet he gives me love. - - - -HELENA -O that my prayers could such affection move! - - - -HERMIA -The more I hate, the more he follows me. - - - -HELENA -The more I love, the more he hateth me. - - - -HERMIA -His folly, Helena, is no fault of mine. - - - -HELENA -None, but your beauty: would that fault were mine! - - - -HERMIA -Take comfort: he no more shall see my face; -Lysander and myself will fly this place. -Before the time I did Lysander see, -Seem'd Athens as a paradise to me: -O, then, what graces in my love do dwell, -That he hath turn'd a heaven unto a hell! - - - -LYSANDER -Helen, to you our minds we will unfold: -To-morrow night, when Phoebe doth behold -Her silver visage in the watery glass, -Decking with liquid pearl the bladed grass, -A time that lovers' flights doth still conceal, -Through Athens' gates have we devised to steal. - - - -HERMIA -And in the wood, where often you and I -Upon faint primrose-beds were wont to lie, -Emptying our bosoms of their counsel sweet, -There my Lysander and myself shall meet; -And thence from Athens turn away our eyes, -To seek new friends and stranger companies. -Farewell, sweet playfellow: pray thou for us; -And good luck grant thee thy Demetrius! -Keep word, Lysander: we must starve our sight -From lovers' food till morrow deep midnight. - - - -LYSANDER -I will, my Hermia. -Exit HERMIA -Helena, adieu: -As you on him, Demetrius dote on you! - - - -Exit - - -HELENA -How happy some o'er other some can be! -Through Athens I am thought as fair as she. -But what of that? Demetrius thinks not so; -He will not know what all but he do know: -And as he errs, doting on Hermia's eyes, -So I, admiring of his qualities: -Things base and vile, folding no quantity, -Love can transpose to form and dignity: -Love looks not with the eyes, but with the mind; -And therefore is wing'd Cupid painted blind: -Nor hath Love's mind of any judgement taste; -Wings and no eyes figure unheedy haste: -And therefore is Love said to be a child, -Because in choice he is so oft beguiled. -As waggish boys in game themselves forswear, -So the boy Love is perjured every where: -For ere Demetrius look'd on Hermia's eyne, -He hail'd down oaths that he was only mine; -And when this hail some heat from Hermia felt, -So he dissolved, and showers of oaths did melt. -I will go tell him of fair Hermia's flight: -Then to the wood will he to-morrow night -Pursue her; and for this intelligence -If I have thanks, it is a dear expense: -But herein mean I to enrich my pain, -To have his sight thither and back again. - - - -Exit - - -SCENE II. Athens. QUINCE'S house. -Enter QUINCE, SNUG, BOTTOM, FLUTE, SNOUT, and -STARVELING - - -QUINCE -Is all our company here? - - - -BOTTOM -You were best to call them generally, man by man, -according to the scrip. - - - -QUINCE -Here is the scroll of every man's name, which is -thought fit, through all Athens, to play in our -interlude before the duke and the duchess, on his -wedding-day at night. - - - -BOTTOM -First, good Peter Quince, say what the play treats -on, then read the names of the actors, and so grow -to a point. - - - -QUINCE -Marry, our play is, The most lamentable comedy, and -most cruel death of Pyramus and Thisby. - - - -BOTTOM -A very good piece of work, I assure you, and a -merry. Now, good Peter Quince, call forth your -actors by the scroll. Masters, spread yourselves. - - - -QUINCE -Answer as I call you. Nick Bottom, the weaver. - - - -BOTTOM -Ready. Name what part I am for, and proceed. - - - -QUINCE -You, Nick Bottom, are set down for Pyramus. - - - -BOTTOM -What is Pyramus? a lover, or a tyrant? - - - -QUINCE -A lover, that kills himself most gallant for love. - - - -BOTTOM -That will ask some tears in the true performing of -it: if I do it, let the audience look to their -eyes; I will move storms, I will condole in some -measure. To the rest: yet my chief humour is for a -tyrant: I could play Ercles rarely, or a part to -tear a cat in, to make all split. -The raging rocks -And shivering shocks -Shall break the locks -Of prison gates; -And Phibbus' car -Shall shine from far -And make and mar -The foolish Fates. -This was lofty! Now name the rest of the players. -This is Ercles' vein, a tyrant's vein; a lover is -more condoling. - - - -QUINCE -Francis Flute, the bellows-mender. - - - -FLUTE -Here, Peter Quince. - - - -QUINCE -Flute, you must take Thisby on you. - - - -FLUTE -What is Thisby? a wandering knight? - - - -QUINCE -It is the lady that Pyramus must love. - - - -FLUTE -Nay, faith, let me not play a woman; I have a beard coming. - - - -QUINCE -That's all one: you shall play it in a mask, and -you may speak as small as you will. - - - -BOTTOM -An I may hide my face, let me play Thisby too, I'll -speak in a monstrous little voice. 'Thisne, -Thisne;' 'Ah, Pyramus, lover dear! thy Thisby dear, -and lady dear!' - - - -QUINCE -No, no; you must play Pyramus: and, Flute, you Thisby. - - - -BOTTOM -Well, proceed. - - - -QUINCE -Robin Starveling, the tailor. - - - -STARVELING -Here, Peter Quince. - - - -QUINCE -Robin Starveling, you must play Thisby's mother. -Tom Snout, the tinker. - - - -SNOUT -Here, Peter Quince. - - - -QUINCE -You, Pyramus' father: myself, Thisby's father: -Snug, the joiner; you, the lion's part: and, I -hope, here is a play fitted. - - - -SNUG -Have you the lion's part written? pray you, if it -be, give it me, for I am slow of study. - - - -QUINCE -You may do it extempore, for it is nothing but roaring. - - - -BOTTOM -Let me play the lion too: I will roar, that I will -do any man's heart good to hear me; I will roar, -that I will make the duke say 'Let him roar again, -let him roar again.' - - - -QUINCE -An you should do it too terribly, you would fright -the duchess and the ladies, that they would shriek; -and that were enough to hang us all. - - - -ALL -That would hang us, every mother's son. - - - -BOTTOM -I grant you, friends, if that you should fright the -ladies out of their wits, they would have no more -discretion but to hang us: but I will aggravate my -voice so that I will roar you as gently as any -sucking dove; I will roar you an 'twere any -nightingale. - - - -QUINCE -You can play no part but Pyramus; for Pyramus is a -sweet-faced man; a proper man, as one shall see in a -summer's day; a most lovely gentleman-like man: -therefore you must needs play Pyramus. - - - -BOTTOM -Well, I will undertake it. What beard were I best -to play it in? - - - -QUINCE -Why, what you will. - - - -BOTTOM -I will discharge it in either your straw-colour -beard, your orange-tawny beard, your purple-in-grain -beard, or your French-crown-colour beard, your -perfect yellow. - - - -QUINCE -Some of your French crowns have no hair at all, and -then you will play bare-faced. But, masters, here -are your parts: and I am to entreat you, request -you and desire you, to con them by to-morrow night; -and meet me in the palace wood, a mile without the -town, by moonlight; there will we rehearse, for if -we meet in the city, we shall be dogged with -company, and our devices known. In the meantime I -will draw a bill of properties, such as our play -wants. I pray you, fail me not. - - - -BOTTOM -We will meet; and there we may rehearse most -obscenely and courageously. Take pains; be perfect: adieu. - - - -QUINCE -At the duke's oak we meet. - - - -BOTTOM -Enough; hold or cut bow-strings. - - - -Exeunt - - - - -ACT II - -SCENE I. A wood near Athens. -Enter, from opposite sides, a Fairy, and PUCK - - -PUCK -How now, spirit! whither wander you? - - - -Fairy -Over hill, over dale, -Thorough bush, thorough brier, -Over park, over pale, -Thorough flood, thorough fire, -I do wander everywhere, -Swifter than the moon's sphere; -And I serve the fairy queen, -To dew her orbs upon the green. -The cowslips tall her pensioners be: -In their gold coats spots you see; -Those be rubies, fairy favours, -In those freckles live their savours: -I must go seek some dewdrops here -And hang a pearl in every cowslip's ear. -Farewell, thou lob of spirits; I'll be gone: -Our queen and all our elves come here anon. - - - -PUCK -The king doth keep his revels here to-night: -Take heed the queen come not within his sight; -For Oberon is passing fell and wrath, -Because that she as her attendant hath -A lovely boy, stolen from an Indian king; -She never had so sweet a changeling; -And jealous Oberon would have the child -Knight of his train, to trace the forests wild; -But she perforce withholds the loved boy, -Crowns him with flowers and makes him all her joy: -And now they never meet in grove or green, -By fountain clear, or spangled starlight sheen, -But, they do square, that all their elves for fear -Creep into acorn-cups and hide them there. - - - -Fairy -Either I mistake your shape and making quite, -Or else you are that shrewd and knavish sprite -Call'd Robin Goodfellow: are not you he -That frights the maidens of the villagery; -Skim milk, and sometimes labour in the quern -And bootless make the breathless housewife churn; -And sometime make the drink to bear no barm; -Mislead night-wanderers, laughing at their harm? -Those that Hobgoblin call you and sweet Puck, -You do their work, and they shall have good luck: -Are not you he? - - - -PUCK -Thou speak'st aright; -I am that merry wanderer of the night. -I jest to Oberon and make him smile -When I a fat and bean-fed horse beguile, -Neighing in likeness of a filly foal: -And sometime lurk I in a gossip's bowl, -In very likeness of a roasted crab, -And when she drinks, against her lips I bob -And on her wither'd dewlap pour the ale. -The wisest aunt, telling the saddest tale, -Sometime for three-foot stool mistaketh me; -Then slip I from her bum, down topples she, -And 'tailor' cries, and falls into a cough; -And then the whole quire hold their hips and laugh, -And waxen in their mirth and neeze and swear -A merrier hour was never wasted there. -But, room, fairy! here comes Oberon. - - - -Fairy -And here my mistress. Would that he were gone! - - - -Enter, from one side, OBERON, with his train; -from the other, TITANIA, with hers - - -OBERON -Ill met by moonlight, proud Titania. - - - -TITANIA -What, jealous Oberon! Fairies, skip hence: -I have forsworn his bed and company. - - - -OBERON -Tarry, rash wanton: am not I thy lord? - - - -TITANIA -Then I must be thy lady: but I know -When thou hast stolen away from fairy land, -And in the shape of Corin sat all day, -Playing on pipes of corn and versing love -To amorous Phillida. Why art thou here, -Come from the farthest Steppe of India? -But that, forsooth, the bouncing Amazon, -Your buskin'd mistress and your warrior love, -To Theseus must be wedded, and you come -To give their bed joy and prosperity. - - - -OBERON -How canst thou thus for shame, Titania, -Glance at my credit with Hippolyta, -Knowing I know thy love to Theseus? -Didst thou not lead him through the glimmering night -From Perigenia, whom he ravished? -And make him with fair AEgle break his faith, -With Ariadne and Antiopa? - - - -TITANIA -These are the forgeries of jealousy: -And never, since the middle summer's spring, -Met we on hill, in dale, forest or mead, -By paved fountain or by rushy brook, -Or in the beached margent of the sea, -To dance our ringlets to the whistling wind, -But with thy brawls thou hast disturb'd our sport. -Therefore the winds, piping to us in vain, -As in revenge, have suck'd up from the sea -Contagious fogs; which falling in the land -Have every pelting river made so proud -That they have overborne their continents: -The ox hath therefore stretch'd his yoke in vain, -The ploughman lost his sweat, and the green corn -Hath rotted ere his youth attain'd a beard; -The fold stands empty in the drowned field, -And crows are fatted with the murrion flock; -The nine men's morris is fill'd up with mud, -And the quaint mazes in the wanton green -For lack of tread are undistinguishable: -The human mortals want their winter here; -No night is now with hymn or carol blest: -Therefore the moon, the governess of floods, -Pale in her anger, washes all the air, -That rheumatic diseases do abound: -And thorough this distemperature we see -The seasons alter: hoary-headed frosts -Far in the fresh lap of the crimson rose, -And on old Hiems' thin and icy crown -An odorous chaplet of sweet summer buds -Is, as in mockery, set: the spring, the summer, -The childing autumn, angry winter, change -Their wonted liveries, and the mazed world, -By their increase, now knows not which is which: -And this same progeny of evils comes -From our debate, from our dissension; -We are their parents and original. - - - -OBERON -Do you amend it then; it lies in you: -Why should Titania cross her Oberon? -I do but beg a little changeling boy, -To be my henchman. - - - -TITANIA -Set your heart at rest: -The fairy land buys not the child of me. -His mother was a votaress of my order: -And, in the spiced Indian air, by night, -Full often hath she gossip'd by my side, -And sat with me on Neptune's yellow sands, -Marking the embarked traders on the flood, -When we have laugh'd to see the sails conceive -And grow big-bellied with the wanton wind; -Which she, with pretty and with swimming gait -Following,--her womb then rich with my young squire,-- -Would imitate, and sail upon the land, -To fetch me trifles, and return again, -As from a voyage, rich with merchandise. -But she, being mortal, of that boy did die; -And for her sake do I rear up her boy, -And for her sake I will not part with him. - - - -OBERON -How long within this wood intend you stay? - - - -TITANIA -Perchance till after Theseus' wedding-day. -If you will patiently dance in our round -And see our moonlight revels, go with us; -If not, shun me, and I will spare your haunts. - - - -OBERON -Give me that boy, and I will go with thee. - - - -TITANIA -Not for thy fairy kingdom. Fairies, away! -We shall chide downright, if I longer stay. - - - -Exit TITANIA with her train - - -OBERON -Well, go thy way: thou shalt not from this grove -Till I torment thee for this injury. -My gentle Puck, come hither. Thou rememberest -Since once I sat upon a promontory, -And heard a mermaid on a dolphin's back -Uttering such dulcet and harmonious breath -That the rude sea grew civil at her song -And certain stars shot madly from their spheres, -To hear the sea-maid's music. - - - -PUCK -I remember. - - - -OBERON -That very time I saw, but thou couldst not, -Flying between the cold moon and the earth, -Cupid all arm'd: a certain aim he took -At a fair vestal throned by the west, -And loosed his love-shaft smartly from his bow, -As it should pierce a hundred thousand hearts; -But I might see young Cupid's fiery shaft -Quench'd in the chaste beams of the watery moon, -And the imperial votaress passed on, -In maiden meditation, fancy-free. -Yet mark'd I where the bolt of Cupid fell: -It fell upon a little western flower, -Before milk-white, now purple with love's wound, -And maidens call it love-in-idleness. -Fetch me that flower; the herb I shew'd thee once: -The juice of it on sleeping eye-lids laid -Will make or man or woman madly dote -Upon the next live creature that it sees. -Fetch me this herb; and be thou here again -Ere the leviathan can swim a league. - - - -PUCK -I'll put a girdle round about the earth -In forty minutes. - - - -Exit - - -OBERON -Having once this juice, -I'll watch Titania when she is asleep, -And drop the liquor of it in her eyes. -The next thing then she waking looks upon, -Be it on lion, bear, or wolf, or bull, -On meddling monkey, or on busy ape, -She shall pursue it with the soul of love: -And ere I take this charm from off her sight, -As I can take it with another herb, -I'll make her render up her page to me. -But who comes here? I am invisible; -And I will overhear their conference. - - - -Enter DEMETRIUS, HELENA, following him - - -DEMETRIUS -I love thee not, therefore pursue me not. -Where is Lysander and fair Hermia? -The one I'll slay, the other slayeth me. -Thou told'st me they were stolen unto this wood; -And here am I, and wode within this wood, -Because I cannot meet my Hermia. -Hence, get thee gone, and follow me no more. - - - -HELENA -You draw me, you hard-hearted adamant; -But yet you draw not iron, for my heart -Is true as steel: leave you your power to draw, -And I shall have no power to follow you. - - - -DEMETRIUS -Do I entice you? do I speak you fair? -Or, rather, do I not in plainest truth -Tell you, I do not, nor I cannot love you? - - - -HELENA -And even for that do I love you the more. -I am your spaniel; and, Demetrius, -The more you beat me, I will fawn on you: -Use me but as your spaniel, spurn me, strike me, -Neglect me, lose me; only give me leave, -Unworthy as I am, to follow you. -What worser place can I beg in your love,-- -And yet a place of high respect with me,-- -Than to be used as you use your dog? - - - -DEMETRIUS -Tempt not too much the hatred of my spirit; -For I am sick when I do look on thee. - - - -HELENA -And I am sick when I look not on you. - - - -DEMETRIUS -You do impeach your modesty too much, -To leave the city and commit yourself -Into the hands of one that loves you not; -To trust the opportunity of night -And the ill counsel of a desert place -With the rich worth of your virginity. - - - -HELENA -Your virtue is my privilege: for that -It is not night when I do see your face, -Therefore I think I am not in the night; -Nor doth this wood lack worlds of company, -For you in my respect are all the world: -Then how can it be said I am alone, -When all the world is here to look on me? - - - -DEMETRIUS -I'll run from thee and hide me in the brakes, -And leave thee to the mercy of wild beasts. - - - -HELENA -The wildest hath not such a heart as you. -Run when you will, the story shall be changed: -Apollo flies, and Daphne holds the chase; -The dove pursues the griffin; the mild hind -Makes speed to catch the tiger; bootless speed, -When cowardice pursues and valour flies. - - - -DEMETRIUS -I will not stay thy questions; let me go: -Or, if thou follow me, do not believe -But I shall do thee mischief in the wood. - - - -HELENA -Ay, in the temple, in the town, the field, -You do me mischief. Fie, Demetrius! -Your wrongs do set a scandal on my sex: -We cannot fight for love, as men may do; -We should be wood and were not made to woo. -Exit DEMETRIUS -I'll follow thee and make a heaven of hell, -To die upon the hand I love so well. - - - -Exit - - -OBERON -Fare thee well, nymph: ere he do leave this grove, -Thou shalt fly him and he shall seek thy love. -Re-enter PUCK -Hast thou the flower there? Welcome, wanderer. - - - -PUCK -Ay, there it is. - - - -OBERON -I pray thee, give it me. -I know a bank where the wild thyme blows, -Where oxlips and the nodding violet grows, -Quite over-canopied with luscious woodbine, -With sweet musk-roses and with eglantine: -There sleeps Titania sometime of the night, -Lull'd in these flowers with dances and delight; -And there the snake throws her enamell'd skin, -Weed wide enough to wrap a fairy in: -And with the juice of this I'll streak her eyes, -And make her full of hateful fantasies. -Take thou some of it, and seek through this grove: -A sweet Athenian lady is in love -With a disdainful youth: anoint his eyes; -But do it when the next thing he espies -May be the lady: thou shalt know the man -By the Athenian garments he hath on. -Effect it with some care, that he may prove -More fond on her than she upon her love: -And look thou meet me ere the first cock crow. - - - -PUCK -Fear not, my lord, your servant shall do so. - - - -Exeunt - - -SCENE II. Another part of the wood. -Enter TITANIA, with her train - - -TITANIA -Come, now a roundel and a fairy song; -Then, for the third part of a minute, hence; -Some to kill cankers in the musk-rose buds, -Some war with rere-mice for their leathern wings, -To make my small elves coats, and some keep back -The clamorous owl that nightly hoots and wonders -At our quaint spirits. Sing me now asleep; -Then to your offices and let me rest. -The Fairies sing -You spotted snakes with double tongue, -Thorny hedgehogs, be not seen; -Newts and blind-worms, do no wrong, -Come not near our fairy queen. -Philomel, with melody -Sing in our sweet lullaby; -Lulla, lulla, lullaby, lulla, lulla, lullaby: -Never harm, -Nor spell nor charm, -Come our lovely lady nigh; -So, good night, with lullaby. -Weaving spiders, come not here; -Hence, you long-legg'd spinners, hence! -Beetles black, approach not near; -Worm nor snail, do no offence. -Philomel, with melody, &c. - - - -Fairy -Hence, away! now all is well: -One aloof stand sentinel. - - -Exeunt Fairies. TITANIA sleeps -Enter OBERON and squeezes the flower on TITANIA's eyelids - - -OBERON -What thou seest when thou dost wake, -Do it for thy true-love take, -Love and languish for his sake: -Be it ounce, or cat, or bear, -Pard, or boar with bristled hair, -In thy eye that shall appear -When thou wakest, it is thy dear: -Wake when some vile thing is near. - - -Exit -Enter LYSANDER and HERMIA - - -LYSANDER -Fair love, you faint with wandering in the wood; -And to speak troth, I have forgot our way: -We'll rest us, Hermia, if you think it good, -And tarry for the comfort of the day. - - - -HERMIA -Be it so, Lysander: find you out a bed; -For I upon this bank will rest my head. - - - -LYSANDER -One turf shall serve as pillow for us both; -One heart, one bed, two bosoms and one troth. - - - -HERMIA -Nay, good Lysander; for my sake, my dear, -Lie further off yet, do not lie so near. - - - -LYSANDER -O, take the sense, sweet, of my innocence! -Love takes the meaning in love's conference. -I mean, that my heart unto yours is knit -So that but one heart we can make of it; -Two bosoms interchained with an oath; -So then two bosoms and a single troth. -Then by your side no bed-room me deny; -For lying so, Hermia, I do not lie. - - - -HERMIA -Lysander riddles very prettily: -Now much beshrew my manners and my pride, -If Hermia meant to say Lysander lied. -But, gentle friend, for love and courtesy -Lie further off; in human modesty, -Such separation as may well be said -Becomes a virtuous bachelor and a maid, -So far be distant; and, good night, sweet friend: -Thy love ne'er alter till thy sweet life end! - - - -LYSANDER -Amen, amen, to that fair prayer, say I; -And then end life when I end loyalty! -Here is my bed: sleep give thee all his rest! - - - -HERMIA -With half that wish the wisher's eyes be press'd! - - -They sleep -Enter PUCK - - -PUCK -Through the forest have I gone. -But Athenian found I none, -On whose eyes I might approve -This flower's force in stirring love. -Night and silence.--Who is here? -Weeds of Athens he doth wear: -This is he, my master said, -Despised the Athenian maid; -And here the maiden, sleeping sound, -On the dank and dirty ground. -Pretty soul! she durst not lie -Near this lack-love, this kill-courtesy. -Churl, upon thy eyes I throw -All the power this charm doth owe. -When thou wakest, let love forbid -Sleep his seat on thy eyelid: -So awake when I am gone; -For I must now to Oberon. - - -Exit -Enter DEMETRIUS and HELENA, running - - -HELENA -Stay, though thou kill me, sweet Demetrius. - - - -DEMETRIUS -I charge thee, hence, and do not haunt me thus. - - - -HELENA -O, wilt thou darkling leave me? do not so. - - - -DEMETRIUS -Stay, on thy peril: I alone will go. - - - -Exit - - -HELENA -O, I am out of breath in this fond chase! -The more my prayer, the lesser is my grace. -Happy is Hermia, wheresoe'er she lies; -For she hath blessed and attractive eyes. -How came her eyes so bright? Not with salt tears: -If so, my eyes are oftener wash'd than hers. -No, no, I am as ugly as a bear; -For beasts that meet me run away for fear: -Therefore no marvel though Demetrius -Do, as a monster fly my presence thus. -What wicked and dissembling glass of mine -Made me compare with Hermia's sphery eyne? -But who is here? Lysander! on the ground! -Dead? or asleep? I see no blood, no wound. -Lysander if you live, good sir, awake. - - - -LYSANDER -Awaking And run through fire I will for thy sweet sake. -Transparent Helena! Nature shows art, -That through thy bosom makes me see thy heart. -Where is Demetrius? O, how fit a word -Is that vile name to perish on my sword! - - - -HELENA -Do not say so, Lysander; say not so -What though he love your Hermia? Lord, what though? -Yet Hermia still loves you: then be content. - - - -LYSANDER -Content with Hermia! No; I do repent -The tedious minutes I with her have spent. -Not Hermia but Helena I love: -Who will not change a raven for a dove? -The will of man is by his reason sway'd; -And reason says you are the worthier maid. -Things growing are not ripe until their season -So I, being young, till now ripe not to reason; -And touching now the point of human skill, -Reason becomes the marshal to my will -And leads me to your eyes, where I o'erlook -Love's stories written in love's richest book. - - - -HELENA -Wherefore was I to this keen mockery born? -When at your hands did I deserve this scorn? -Is't not enough, is't not enough, young man, -That I did never, no, nor never can, -Deserve a sweet look from Demetrius' eye, -But you must flout my insufficiency? -Good troth, you do me wrong, good sooth, you do, -In such disdainful manner me to woo. -But fare you well: perforce I must confess -I thought you lord of more true gentleness. -O, that a lady, of one man refused. -Should of another therefore be abused! - - - -Exit - - -LYSANDER -She sees not Hermia. Hermia, sleep thou there: -And never mayst thou come Lysander near! -For as a surfeit of the sweetest things -The deepest loathing to the stomach brings, -Or as tie heresies that men do leave -Are hated most of those they did deceive, -So thou, my surfeit and my heresy, -Of all be hated, but the most of me! -And, all my powers, address your love and might -To honour Helen and to be her knight! - - - -Exit - - -HERMIA -Awaking Help me, Lysander, help me! do thy best -To pluck this crawling serpent from my breast! -Ay me, for pity! what a dream was here! -Lysander, look how I do quake with fear: -Methought a serpent eat my heart away, -And you sat smiling at his cruel pray. -Lysander! what, removed? Lysander! lord! -What, out of hearing? gone? no sound, no word? -Alack, where are you speak, an if you hear; -Speak, of all loves! I swoon almost with fear. -No? then I well perceive you all not nigh -Either death or you I'll find immediately. - - - -Exit - - - - -ACT III - -SCENE I. The wood. TITANIA lying asleep. -Enter QUINCE, SNUG, BOTTOM, FLUTE, SNOUT, and -STARVELING - - -BOTTOM -Are we all met? - - - -QUINCE -Pat, pat; and here's a marvellous convenient place -for our rehearsal. This green plot shall be our -stage, this hawthorn-brake our tiring-house; and we -will do it in action as we will do it before the duke. - - - -BOTTOM -Peter Quince,-- - - - -QUINCE -What sayest thou, bully Bottom? - - - -BOTTOM -There are things in this comedy of Pyramus and -Thisby that will never please. First, Pyramus must -draw a sword to kill himself; which the ladies -cannot abide. How answer you that? - - - -SNOUT -By'r lakin, a parlous fear. - - - -STARVELING -I believe we must leave the killing out, when all is done. - - - -BOTTOM -Not a whit: I have a device to make all well. -Write me a prologue; and let the prologue seem to -say, we will do no harm with our swords, and that -Pyramus is not killed indeed; and, for the more -better assurance, tell them that I, Pyramus, am not -Pyramus, but Bottom the weaver: this will put them -out of fear. - - - -QUINCE -Well, we will have such a prologue; and it shall be -written in eight and six. - - - -BOTTOM -No, make it two more; let it be written in eight and eight. - - - -SNOUT -Will not the ladies be afeard of the lion? - - - -STARVELING -I fear it, I promise you. - - - -BOTTOM -Masters, you ought to consider with yourselves: to -bring in--God shield us!--a lion among ladies, is a -most dreadful thing; for there is not a more fearful -wild-fowl than your lion living; and we ought to -look to 't. - - - -SNOUT -Therefore another prologue must tell he is not a lion. - - - -BOTTOM -Nay, you must name his name, and half his face must -be seen through the lion's neck: and he himself -must speak through, saying thus, or to the same -defect,--'Ladies,'--or 'Fair-ladies--I would wish -You,'--or 'I would request you,'--or 'I would -entreat you,--not to fear, not to tremble: my life -for yours. If you think I come hither as a lion, it -were pity of my life: no I am no such thing; I am a -man as other men are;' and there indeed let him name -his name, and tell them plainly he is Snug the joiner. - - - -QUINCE -Well it shall be so. But there is two hard things; -that is, to bring the moonlight into a chamber; for, -you know, Pyramus and Thisby meet by moonlight. - - - -SNOUT -Doth the moon shine that night we play our play? - - - -BOTTOM -A calendar, a calendar! look in the almanac; find -out moonshine, find out moonshine. - - - -QUINCE -Yes, it doth shine that night. - - - -BOTTOM -Why, then may you leave a casement of the great -chamber window, where we play, open, and the moon -may shine in at the casement. - - - -QUINCE -Ay; or else one must come in with a bush of thorns -and a lanthorn, and say he comes to disfigure, or to -present, the person of Moonshine. Then, there is -another thing: we must have a wall in the great -chamber; for Pyramus and Thisby says the story, did -talk through the chink of a wall. - - - -SNOUT -You can never bring in a wall. What say you, Bottom? - - - -BOTTOM -Some man or other must present Wall: and let him -have some plaster, or some loam, or some rough-cast -about him, to signify wall; and let him hold his -fingers thus, and through that cranny shall Pyramus -and Thisby whisper. - - - -QUINCE -If that may be, then all is well. Come, sit down, -every mother's son, and rehearse your parts. -Pyramus, you begin: when you have spoken your -speech, enter into that brake: and so every one -according to his cue. - - - -Enter PUCK behind - - -PUCK -What hempen home-spuns have we swaggering here, -So near the cradle of the fairy queen? -What, a play toward! I'll be an auditor; -An actor too, perhaps, if I see cause. - - - -QUINCE -Speak, Pyramus. Thisby, stand forth. - - - -BOTTOM -Thisby, the flowers of odious savours sweet,-- - - - -QUINCE -Odours, odours. - - - -BOTTOM ---odours savours sweet: -So hath thy breath, my dearest Thisby dear. -But hark, a voice! stay thou but here awhile, -And by and by I will to thee appear. - - - -Exit - - -PUCK -A stranger Pyramus than e'er played here. - - - -Exit - - -FLUTE -Must I speak now? - - - -QUINCE -Ay, marry, must you; for you must understand he goes -but to see a noise that he heard, and is to come again. - - - -FLUTE -Most radiant Pyramus, most lily-white of hue, -Of colour like the red rose on triumphant brier, -Most brisky juvenal and eke most lovely Jew, -As true as truest horse that yet would never tire, -I'll meet thee, Pyramus, at Ninny's tomb. - - - -QUINCE -'Ninus' tomb,' man: why, you must not speak that -yet; that you answer to Pyramus: you speak all your -part at once, cues and all Pyramus enter: your cue -is past; it is, 'never tire.' - - - -FLUTE -O,--As true as truest horse, that yet would -never tire. - - - -Re-enter PUCK, and BOTTOM with an ass's head - - -BOTTOM -If I were fair, Thisby, I were only thine. - - - -QUINCE -O monstrous! O strange! we are haunted. Pray, -masters! fly, masters! Help! - - - -Exeunt QUINCE, SNUG, FLUTE, SNOUT, and STARVELING - - -PUCK -I'll follow you, I'll lead you about a round, -Through bog, through bush, through brake, through brier: -Sometime a horse I'll be, sometime a hound, -A hog, a headless bear, sometime a fire; -And neigh, and bark, and grunt, and roar, and burn, -Like horse, hound, hog, bear, fire, at every turn. - - - -Exit - - -BOTTOM -Why do they run away? this is a knavery of them to -make me afeard. - - - -Re-enter SNOUT - - -SNOUT -O Bottom, thou art changed! what do I see on thee? - - - -BOTTOM -What do you see? you see an asshead of your own, do -you? - - -Exit SNOUT -Re-enter QUINCE - - -QUINCE -Bless thee, Bottom! bless thee! thou art -translated. - - - -Exit - - -BOTTOM -I see their knavery: this is to make an ass of me; -to fright me, if they could. But I will not stir -from this place, do what they can: I will walk up -and down here, and I will sing, that they shall hear -I am not afraid. -Sings -The ousel cock so black of hue, -With orange-tawny bill, -The throstle with his note so true, -The wren with little quill,-- - - - -TITANIA -Awaking What angel wakes me from my flowery bed? - - - -BOTTOM -Sings -The finch, the sparrow and the lark, -The plain-song cuckoo gray, -Whose note full many a man doth mark, -And dares not answer nay;-- -for, indeed, who would set his wit to so foolish -a bird? who would give a bird the lie, though he cry -'cuckoo' never so? - - - -TITANIA -I pray thee, gentle mortal, sing again: -Mine ear is much enamour'd of thy note; -So is mine eye enthralled to thy shape; -And thy fair virtue's force perforce doth move me -On the first view to say, to swear, I love thee. - - - -BOTTOM -Methinks, mistress, you should have little reason -for that: and yet, to say the truth, reason and -love keep little company together now-a-days; the -more the pity that some honest neighbours will not -make them friends. Nay, I can gleek upon occasion. - - - -TITANIA -Thou art as wise as thou art beautiful. - - - -BOTTOM -Not so, neither: but if I had wit enough to get out -of this wood, I have enough to serve mine own turn. - - - -TITANIA -Out of this wood do not desire to go: -Thou shalt remain here, whether thou wilt or no. -I am a spirit of no common rate; -The summer still doth tend upon my state; -And I do love thee: therefore, go with me; -I'll give thee fairies to attend on thee, -And they shall fetch thee jewels from the deep, -And sing while thou on pressed flowers dost sleep; -And I will purge thy mortal grossness so -That thou shalt like an airy spirit go. -Peaseblossom! Cobweb! Moth! and Mustardseed! - - - -Enter PEASEBLOSSOM, COBWEB, MOTH, and MUSTARDSEED - - -PEASEBLOSSOM -Ready. - - - -COBWEB -And I. - - - -MOTH -And I. - - - -MUSTARDSEED -And I. - - - -ALL -Where shall we go? - - - -TITANIA -Be kind and courteous to this gentleman; -Hop in his walks and gambol in his eyes; -Feed him with apricocks and dewberries, -With purple grapes, green figs, and mulberries; -The honey-bags steal from the humble-bees, -And for night-tapers crop their waxen thighs -And light them at the fiery glow-worm's eyes, -To have my love to bed and to arise; -And pluck the wings from Painted butterflies -To fan the moonbeams from his sleeping eyes: -Nod to him, elves, and do him courtesies. - - - -PEASEBLOSSOM -Hail, mortal! - - - -COBWEB -Hail! - - - -MOTH -Hail! - - - -MUSTARDSEED -Hail! - - - -BOTTOM -I cry your worship's mercy, heartily: I beseech your -worship's name. - - - -COBWEB -Cobweb. - - - -BOTTOM -I shall desire you of more acquaintance, good Master -Cobweb: if I cut my finger, I shall make bold with -you. Your name, honest gentleman? - - - -PEASEBLOSSOM -Peaseblossom. - - - -BOTTOM -I pray you, commend me to Mistress Squash, your -mother, and to Master Peascod, your father. Good -Master Peaseblossom, I shall desire you of more -acquaintance too. Your name, I beseech you, sir? - - - -MUSTARDSEED -Mustardseed. - - - -BOTTOM -Good Master Mustardseed, I know your patience well: -that same cowardly, giant-like ox-beef hath -devoured many a gentleman of your house: I promise -you your kindred had made my eyes water ere now. I -desire your more acquaintance, good Master -Mustardseed. - - - -TITANIA -Come, wait upon him; lead him to my bower. -The moon methinks looks with a watery eye; -And when she weeps, weeps every little flower, -Lamenting some enforced chastity. -Tie up my love's tongue bring him silently. - - - -Exeunt - - -SCENE II. Another part of the wood. -Enter OBERON - - -OBERON -I wonder if Titania be awaked; -Then, what it was that next came in her eye, -Which she must dote on in extremity. -Enter PUCK -Here comes my messenger. -How now, mad spirit! -What night-rule now about this haunted grove? - - - -PUCK -My mistress with a monster is in love. -Near to her close and consecrated bower, -While she was in her dull and sleeping hour, -A crew of patches, rude mechanicals, -That work for bread upon Athenian stalls, -Were met together to rehearse a play -Intended for great Theseus' nuptial-day. -The shallowest thick-skin of that barren sort, -Who Pyramus presented, in their sport -Forsook his scene and enter'd in a brake -When I did him at this advantage take, -An ass's nole I fixed on his head: -Anon his Thisbe must be answered, -And forth my mimic comes. When they him spy, -As wild geese that the creeping fowler eye, -Or russet-pated choughs, many in sort, -Rising and cawing at the gun's report, -Sever themselves and madly sweep the sky, -So, at his sight, away his fellows fly; -And, at our stamp, here o'er and o'er one falls; -He murder cries and help from Athens calls. -Their sense thus weak, lost with their fears -thus strong, -Made senseless things begin to do them wrong; -For briers and thorns at their apparel snatch; -Some sleeves, some hats, from yielders all -things catch. -I led them on in this distracted fear, -And left sweet Pyramus translated there: -When in that moment, so it came to pass, -Titania waked and straightway loved an ass. - - - -OBERON -This falls out better than I could devise. -But hast thou yet latch'd the Athenian's eyes -With the love-juice, as I did bid thee do? - - - -PUCK -I took him sleeping,--that is finish'd too,-- -And the Athenian woman by his side: -That, when he waked, of force she must be eyed. - - - -Enter HERMIA and DEMETRIUS - - -OBERON -Stand close: this is the same Athenian. - - - -PUCK -This is the woman, but not this the man. - - - -DEMETRIUS -O, why rebuke you him that loves you so? -Lay breath so bitter on your bitter foe. - - - -HERMIA -Now I but chide; but I should use thee worse, -For thou, I fear, hast given me cause to curse, -If thou hast slain Lysander in his sleep, -Being o'er shoes in blood, plunge in the deep, -And kill me too. -The sun was not so true unto the day -As he to me: would he have stolen away -From sleeping Hermia? I'll believe as soon -This whole earth may be bored and that the moon -May through the centre creep and so displease -Her brother's noontide with Antipodes. -It cannot be but thou hast murder'd him; -So should a murderer look, so dead, so grim. - - - -DEMETRIUS -So should the murder'd look, and so should I, -Pierced through the heart with your stern cruelty: -Yet you, the murderer, look as bright, as clear, -As yonder Venus in her glimmering sphere. - - - -HERMIA -What's this to my Lysander? where is he? -Ah, good Demetrius, wilt thou give him me? - - - -DEMETRIUS -I had rather give his carcass to my hounds. - - - -HERMIA -Out, dog! out, cur! thou drivest me past the bounds -Of maiden's patience. Hast thou slain him, then? -Henceforth be never number'd among men! -O, once tell true, tell true, even for my sake! -Durst thou have look'd upon him being awake, -And hast thou kill'd him sleeping? O brave touch! -Could not a worm, an adder, do so much? -An adder did it; for with doubler tongue -Than thine, thou serpent, never adder stung. - - - -DEMETRIUS -You spend your passion on a misprised mood: -I am not guilty of Lysander's blood; -Nor is he dead, for aught that I can tell. - - - -HERMIA -I pray thee, tell me then that he is well. - - - -DEMETRIUS -An if I could, what should I get therefore? - - - -HERMIA -A privilege never to see me more. -And from thy hated presence part I so: -See me no more, whether he be dead or no. - - - -Exit - - -DEMETRIUS -There is no following her in this fierce vein: -Here therefore for a while I will remain. -So sorrow's heaviness doth heavier grow -For debt that bankrupt sleep doth sorrow owe: -Which now in some slight measure it will pay, -If for his tender here I make some stay. - - - -Lies down and sleeps - - -OBERON -What hast thou done? thou hast mistaken quite -And laid the love-juice on some true-love's sight: -Of thy misprision must perforce ensue -Some true love turn'd and not a false turn'd true. - - - -PUCK -Then fate o'er-rules, that, one man holding troth, -A million fail, confounding oath on oath. - - - -OBERON -About the wood go swifter than the wind, -And Helena of Athens look thou find: -All fancy-sick she is and pale of cheer, -With sighs of love, that costs the fresh blood dear: -By some illusion see thou bring her here: -I'll charm his eyes against she do appear. - - - -PUCK -I go, I go; look how I go, -Swifter than arrow from the Tartar's bow. - - - -Exit - - -OBERON -Flower of this purple dye, -Hit with Cupid's archery, -Sink in apple of his eye. -When his love he doth espy, -Let her shine as gloriously -As the Venus of the sky. -When thou wakest, if she be by, -Beg of her for remedy. - - - -Re-enter PUCK - - -PUCK -Captain of our fairy band, -Helena is here at hand; -And the youth, mistook by me, -Pleading for a lover's fee. -Shall we their fond pageant see? -Lord, what fools these mortals be! - - - -OBERON -Stand aside: the noise they make -Will cause Demetrius to awake. - - - -PUCK -Then will two at once woo one; -That must needs be sport alone; -And those things do best please me -That befal preposterously. - - - -Enter LYSANDER and HELENA - - -LYSANDER -Why should you think that I should woo in scorn? -Scorn and derision never come in tears: -Look, when I vow, I weep; and vows so born, -In their nativity all truth appears. -How can these things in me seem scorn to you, -Bearing the badge of faith, to prove them true? - - - -HELENA -You do advance your cunning more and more. -When truth kills truth, O devilish-holy fray! -These vows are Hermia's: will you give her o'er? -Weigh oath with oath, and you will nothing weigh: -Your vows to her and me, put in two scales, -Will even weigh, and both as light as tales. - - - -LYSANDER -I had no judgment when to her I swore. - - - -HELENA -Nor none, in my mind, now you give her o'er. - - - -LYSANDER -Demetrius loves her, and he loves not you. - - - -DEMETRIUS -Awaking O Helena, goddess, nymph, perfect, divine! -To what, my love, shall I compare thine eyne? -Crystal is muddy. O, how ripe in show -Thy lips, those kissing cherries, tempting grow! -That pure congealed white, high Taurus snow, -Fann'd with the eastern wind, turns to a crow -When thou hold'st up thy hand: O, let me kiss -This princess of pure white, this seal of bliss! - - - -HELENA -O spite! O hell! I see you all are bent -To set against me for your merriment: -If you we re civil and knew courtesy, -You would not do me thus much injury. -Can you not hate me, as I know you do, -But you must join in souls to mock me too? -If you were men, as men you are in show, -You would not use a gentle lady so; -To vow, and swear, and superpraise my parts, -When I am sure you hate me with your hearts. -You both are rivals, and love Hermia; -And now both rivals, to mock Helena: -A trim exploit, a manly enterprise, -To conjure tears up in a poor maid's eyes -With your derision! none of noble sort -Would so offend a virgin, and extort -A poor soul's patience, all to make you sport. - - - -LYSANDER -You are unkind, Demetrius; be not so; -For you love Hermia; this you know I know: -And here, with all good will, with all my heart, -In Hermia's love I yield you up my part; -And yours of Helena to me bequeath, -Whom I do love and will do till my death. - - - -HELENA -Never did mockers waste more idle breath. - - - -DEMETRIUS -Lysander, keep thy Hermia; I will none: -If e'er I loved her, all that love is gone. -My heart to her but as guest-wise sojourn'd, -And now to Helen is it home return'd, -There to remain. - - - -LYSANDER -Helen, it is not so. - - - -DEMETRIUS -Disparage not the faith thou dost not know, -Lest, to thy peril, thou aby it dear. -Look, where thy love comes; yonder is thy dear. - - - -Re-enter HERMIA - - -HERMIA -Dark night, that from the eye his function takes, -The ear more quick of apprehension makes; -Wherein it doth impair the seeing sense, -It pays the hearing double recompense. -Thou art not by mine eye, Lysander, found; -Mine ear, I thank it, brought me to thy sound -But why unkindly didst thou leave me so? - - - -LYSANDER -Why should he stay, whom love doth press to go? - - - -HERMIA -What love could press Lysander from my side? - - - -LYSANDER -Lysander's love, that would not let him bide, -Fair Helena, who more engilds the night -Than all you fiery oes and eyes of light. -Why seek'st thou me? could not this make thee know, -The hate I bear thee made me leave thee so? - - - -HERMIA -You speak not as you think: it cannot be. - - - -HELENA -Lo, she is one of this confederacy! -Now I perceive they have conjoin'd all three -To fashion this false sport, in spite of me. -Injurious Hermia! most ungrateful maid! -Have you conspired, have you with these contrived -To bait me with this foul derision? -Is all the counsel that we two have shared, -The sisters' vows, the hours that we have spent, -When we have chid the hasty-footed time -For parting us,--O, is it all forgot? -All school-days' friendship, childhood innocence? -We, Hermia, like two artificial gods, -Have with our needles created both one flower, -Both on one sampler, sitting on one cushion, -Both warbling of one song, both in one key, -As if our hands, our sides, voices and minds, -Had been incorporate. So we grow together, -Like to a double cherry, seeming parted, -But yet an union in partition; -Two lovely berries moulded on one stem; -So, with two seeming bodies, but one heart; -Two of the first, like coats in heraldry, -Due but to one and crowned with one crest. -And will you rent our ancient love asunder, -To join with men in scorning your poor friend? -It is not friendly, 'tis not maidenly: -Our sex, as well as I, may chide you for it, -Though I alone do feel the injury. - - - -HERMIA -I am amazed at your passionate words. -I scorn you not: it seems that you scorn me. - - - -HELENA -Have you not set Lysander, as in scorn, -To follow me and praise my eyes and face? -And made your other love, Demetrius, -Who even but now did spurn me with his foot, -To call me goddess, nymph, divine and rare, -Precious, celestial? Wherefore speaks he this -To her he hates? and wherefore doth Lysander -Deny your love, so rich within his soul, -And tender me, forsooth, affection, -But by your setting on, by your consent? -What thought I be not so in grace as you, -So hung upon with love, so fortunate, -But miserable most, to love unloved? -This you should pity rather than despise. - - - -HERNIA -I understand not what you mean by this. - - - -HELENA -Ay, do, persever, counterfeit sad looks, -Make mouths upon me when I turn my back; -Wink each at other; hold the sweet jest up: -This sport, well carried, shall be chronicled. -If you have any pity, grace, or manners, -You would not make me such an argument. -But fare ye well: 'tis partly my own fault; -Which death or absence soon shall remedy. - - - -LYSANDER -Stay, gentle Helena; hear my excuse: -My love, my life my soul, fair Helena! - - - -HELENA -O excellent! - - - -HERMIA -Sweet, do not scorn her so. - - - -DEMETRIUS -If she cannot entreat, I can compel. - - - -LYSANDER -Thou canst compel no more than she entreat: -Thy threats have no more strength than her weak prayers. -Helen, I love thee; by my life, I do: -I swear by that which I will lose for thee, -To prove him false that says I love thee not. - - - -DEMETRIUS -I say I love thee more than he can do. - - - -LYSANDER -If thou say so, withdraw, and prove it too. - - - -DEMETRIUS -Quick, come! - - - -HERMIA -Lysander, whereto tends all this? - - - -LYSANDER -Away, you Ethiope! - - - -DEMETRIUS -No, no; he'll -Seem to break loose; take on as you would follow, -But yet come not: you are a tame man, go! - - - -LYSANDER -Hang off, thou cat, thou burr! vile thing, let loose, -Or I will shake thee from me like a serpent! - - - -HERMIA -Why are you grown so rude? what change is this? -Sweet love,-- - - - -LYSANDER -Thy love! out, tawny Tartar, out! -Out, loathed medicine! hated potion, hence! - - - -HERMIA -Do you not jest? - - - -HELENA -Yes, sooth; and so do you. - - - -LYSANDER -Demetrius, I will keep my word with thee. - - - -DEMETRIUS -I would I had your bond, for I perceive -A weak bond holds you: I'll not trust your word. - - - -LYSANDER -What, should I hurt her, strike her, kill her dead? -Although I hate her, I'll not harm her so. - - - -HERMIA -What, can you do me greater harm than hate? -Hate me! wherefore? O me! what news, my love! -Am not I Hermia? are not you Lysander? -I am as fair now as I was erewhile. -Since night you loved me; yet since night you left -me: -Why, then you left me--O, the gods forbid!-- -In earnest, shall I say? - - - -LYSANDER -Ay, by my life; -And never did desire to see thee more. -Therefore be out of hope, of question, of doubt; -Be certain, nothing truer; 'tis no jest -That I do hate thee and love Helena. - - - -HERMIA -O me! you juggler! you canker-blossom! -You thief of love! what, have you come by night -And stolen my love's heart from him? - - - -HELENA -Fine, i'faith! -Have you no modesty, no maiden shame, -No touch of bashfulness? What, will you tear -Impatient answers from my gentle tongue? -Fie, fie! you counterfeit, you puppet, you! - - - -HERMIA -Puppet? why so? ay, that way goes the game. -Now I perceive that she hath made compare -Between our statures; she hath urged her height; -And with her personage, her tall personage, -Her height, forsooth, she hath prevail'd with him. -And are you grown so high in his esteem; -Because I am so dwarfish and so low? -How low am I, thou painted maypole? speak; -How low am I? I am not yet so low -But that my nails can reach unto thine eyes. - - - -HELENA -I pray you, though you mock me, gentlemen, -Let her not hurt me: I was never curst; -I have no gift at all in shrewishness; -I am a right maid for my cowardice: -Let her not strike me. You perhaps may think, -Because she is something lower than myself, -That I can match her. - - - -HERMIA -Lower! hark, again. - - - -HELENA -Good Hermia, do not be so bitter with me. -I evermore did love you, Hermia, -Did ever keep your counsels, never wrong'd you; -Save that, in love unto Demetrius, -I told him of your stealth unto this wood. -He follow'd you; for love I follow'd him; -But he hath chid me hence and threaten'd me -To strike me, spurn me, nay, to kill me too: -And now, so you will let me quiet go, -To Athens will I bear my folly back -And follow you no further: let me go: -You see how simple and how fond I am. - - - -HERMIA -Why, get you gone: who is't that hinders you? - - - -HELENA -A foolish heart, that I leave here behind. - - - -HERMIA -What, with Lysander? - - - -HELENA -With Demetrius. - - - -LYSANDER -Be not afraid; she shall not harm thee, Helena. - - - -DEMETRIUS -No, sir, she shall not, though you take her part. - - - -HELENA -O, when she's angry, she is keen and shrewd! -She was a vixen when she went to school; -And though she be but little, she is fierce. - - - -HERMIA -'Little' again! nothing but 'low' and 'little'! -Why will you suffer her to flout me thus? -Let me come to her. - - - -LYSANDER -Get you gone, you dwarf; -You minimus, of hindering knot-grass made; -You bead, you acorn. - - - -DEMETRIUS -You are too officious -In her behalf that scorns your services. -Let her alone: speak not of Helena; -Take not her part; for, if thou dost intend -Never so little show of love to her, -Thou shalt aby it. - - - -LYSANDER -Now she holds me not; -Now follow, if thou darest, to try whose right, -Of thine or mine, is most in Helena. - - - -DEMETRIUS -Follow! nay, I'll go with thee, cheek by jole. - - - -Exeunt LYSANDER and DEMETRIUS - - -HERMIA -You, mistress, all this coil is 'long of you: -Nay, go not back. - - - -HELENA -I will not trust you, I, -Nor longer stay in your curst company. -Your hands than mine are quicker for a fray, -My legs are longer though, to run away. - - - -Exit - - -HERMIA -I am amazed, and know not what to say. - - - -Exit - - -OBERON -This is thy negligence: still thou mistakest, -Or else committ'st thy knaveries wilfully. - - - -PUCK -Believe me, king of shadows, I mistook. -Did not you tell me I should know the man -By the Athenian garment be had on? -And so far blameless proves my enterprise, -That I have 'nointed an Athenian's eyes; -And so far am I glad it so did sort -As this their jangling I esteem a sport. - - - -OBERON -Thou see'st these lovers seek a place to fight: -Hie therefore, Robin, overcast the night; -The starry welkin cover thou anon -With drooping fog as black as Acheron, -And lead these testy rivals so astray -As one come not within another's way. -Like to Lysander sometime frame thy tongue, -Then stir Demetrius up with bitter wrong; -And sometime rail thou like Demetrius; -And from each other look thou lead them thus, -Till o'er their brows death-counterfeiting sleep -With leaden legs and batty wings doth creep: -Then crush this herb into Lysander's eye; -Whose liquor hath this virtuous property, -To take from thence all error with his might, -And make his eyeballs roll with wonted sight. -When they next wake, all this derision -Shall seem a dream and fruitless vision, -And back to Athens shall the lovers wend, -With league whose date till death shall never end. -Whiles I in this affair do thee employ, -I'll to my queen and beg her Indian boy; -And then I will her charmed eye release -From monster's view, and all things shall be peace. - - - -PUCK -My fairy lord, this must be done with haste, -For night's swift dragons cut the clouds full fast, -And yonder shines Aurora's harbinger; -At whose approach, ghosts, wandering here and there, -Troop home to churchyards: damned spirits all, -That in crossways and floods have burial, -Already to their wormy beds are gone; -For fear lest day should look their shames upon, -They willfully themselves exile from light -And must for aye consort with black-brow'd night. - - - -OBERON -But we are spirits of another sort: -I with the morning's love have oft made sport, -And, like a forester, the groves may tread, -Even till the eastern gate, all fiery-red, -Opening on Neptune with fair blessed beams, -Turns into yellow gold his salt green streams. -But, notwithstanding, haste; make no delay: -We may effect this business yet ere day. - - - -Exit - - -PUCK -Up and down, up and down, -I will lead them up and down: -I am fear'd in field and town: -Goblin, lead them up and down. -Here comes one. - - - -Re-enter LYSANDER - - -LYSANDER -Where art thou, proud Demetrius? speak thou now. - - - -PUCK -Here, villain; drawn and ready. Where art thou? - - - -LYSANDER -I will be with thee straight. - - - -PUCK -Follow me, then, -To plainer ground. - - -Exit LYSANDER, as following the voice -Re-enter DEMETRIUS - - -DEMETRIUS -Lysander! speak again: -Thou runaway, thou coward, art thou fled? -Speak! In some bush? Where dost thou hide thy head? - - - -PUCK -Thou coward, art thou bragging to the stars, -Telling the bushes that thou look'st for wars, -And wilt not come? Come, recreant; come, thou child; -I'll whip thee with a rod: he is defiled -That draws a sword on thee. - - - -DEMETRIUS -Yea, art thou there? - - - -PUCK -Follow my voice: we'll try no manhood here. - - -Exeunt -Re-enter LYSANDER - - -LYSANDER -He goes before me and still dares me on: -When I come where he calls, then he is gone. -The villain is much lighter-heel'd than I: -I follow'd fast, but faster he did fly; -That fallen am I in dark uneven way, -And here will rest me. -Lies down -Come, thou gentle day! -For if but once thou show me thy grey light, -I'll find Demetrius and revenge this spite. - - -Sleeps -Re-enter PUCK and DEMETRIUS - - -PUCK -Ho, ho, ho! Coward, why comest thou not? - - - -DEMETRIUS -Abide me, if thou darest; for well I wot -Thou runn'st before me, shifting every place, -And darest not stand, nor look me in the face. -Where art thou now? - - - -PUCK -Come hither: I am here. - - - -DEMETRIUS -Nay, then, thou mock'st me. Thou shalt buy this dear, -If ever I thy face by daylight see: -Now, go thy way. Faintness constraineth me -To measure out my length on this cold bed. -By day's approach look to be visited. - - -Lies down and sleeps -Re-enter HELENA - - -HELENA -O weary night, O long and tedious night, -Abate thy hour! Shine comforts from the east, -That I may back to Athens by daylight, -From these that my poor company detest: -And sleep, that sometimes shuts up sorrow's eye, -Steal me awhile from mine own company. - - - -Lies down and sleeps - - -PUCK -Yet but three? Come one more; -Two of both kinds make up four. -Here she comes, curst and sad: -Cupid is a knavish lad, -Thus to make poor females mad. - - - -Re-enter HERMIA - - -HERMIA -Never so weary, never so in woe, -Bedabbled with the dew and torn with briers, -I can no further crawl, no further go; -My legs can keep no pace with my desires. -Here will I rest me till the break of day. -Heavens shield Lysander, if they mean a fray! - - - -Lies down and sleeps - - -PUCK -On the ground -Sleep sound: -I'll apply -To your eye, -Gentle lover, remedy. -Squeezing the juice on LYSANDER's eyes -When thou wakest, -Thou takest -True delight -In the sight -Of thy former lady's eye: -And the country proverb known, -That every man should take his own, -In your waking shall be shown: -Jack shall have Jill; -Nought shall go ill; -The man shall have his mare again, and all shall be well. - - - -Exit - - - - -ACT IV - -SCENE I. The same. LYSANDER, DEMETRIUS, HELENA, and HERMIA lying asleep. -Enter TITANIA and BOTTOM; PEASEBLOSSOM, COBWEB, MOTH, -MUSTARDSEED, and other Fairies attending; OBERON -behind unseen - - -TITANIA -Come, sit thee down upon this flowery bed, -While I thy amiable cheeks do coy, -And stick musk-roses in thy sleek smooth head, -And kiss thy fair large ears, my gentle joy. - - - -BOTTOM -Where's Peaseblossom? - - - -PEASEBLOSSOM -Ready. - - - -BOTTOM -Scratch my head Peaseblossom. Where's Mounsieur Cobweb? - - - -COBWEB -Ready. - - - -BOTTOM -Mounsieur Cobweb, good mounsieur, get you your -weapons in your hand, and kill me a red-hipped -humble-bee on the top of a thistle; and, good -mounsieur, bring me the honey-bag. Do not fret -yourself too much in the action, mounsieur; and, -good mounsieur, have a care the honey-bag break not; -I would be loath to have you overflown with a -honey-bag, signior. Where's Mounsieur Mustardseed? - - - -MUSTARDSEED -Ready. - - - -BOTTOM -Give me your neaf, Mounsieur Mustardseed. Pray you, -leave your courtesy, good mounsieur. - - - -MUSTARDSEED -What's your Will? - - - -BOTTOM -Nothing, good mounsieur, but to help Cavalery Cobweb -to scratch. I must to the barber's, monsieur; for -methinks I am marvellous hairy about the face; and I -am such a tender ass, if my hair do but tickle me, -I must scratch. - - - -TITANIA -What, wilt thou hear some music, -my sweet love? - - - -BOTTOM -I have a reasonable good ear in music. Let's have -the tongs and the bones. - - - -TITANIA -Or say, sweet love, what thou desirest to eat. - - - -BOTTOM -Truly, a peck of provender: I could munch your good -dry oats. Methinks I have a great desire to a bottle -of hay: good hay, sweet hay, hath no fellow. - - - -TITANIA -I have a venturous fairy that shall seek -The squirrel's hoard, and fetch thee new nuts. - - - -BOTTOM -I had rather have a handful or two of dried peas. -But, I pray you, let none of your people stir me: I -have an exposition of sleep come upon me. - - - -TITANIA -Sleep thou, and I will wind thee in my arms. -Fairies, begone, and be all ways away. -Exeunt fairies -So doth the woodbine the sweet honeysuckle -Gently entwist; the female ivy so -Enrings the barky fingers of the elm. -O, how I love thee! how I dote on thee! - - -They sleep -Enter PUCK - - -OBERON -Advancing Welcome, good Robin. -See'st thou this sweet sight? -Her dotage now I do begin to pity: -For, meeting her of late behind the wood, -Seeking sweet favours from this hateful fool, -I did upbraid her and fall out with her; -For she his hairy temples then had rounded -With a coronet of fresh and fragrant flowers; -And that same dew, which sometime on the buds -Was wont to swell like round and orient pearls, -Stood now within the pretty flowerets' eyes -Like tears that did their own disgrace bewail. -When I had at my pleasure taunted her -And she in mild terms begg'd my patience, -I then did ask of her her changeling child; -Which straight she gave me, and her fairy sent -To bear him to my bower in fairy land. -And now I have the boy, I will undo -This hateful imperfection of her eyes: -And, gentle Puck, take this transformed scalp -From off the head of this Athenian swain; -That, he awaking when the other do, -May all to Athens back again repair -And think no more of this night's accidents -But as the fierce vexation of a dream. -But first I will release the fairy queen. -Be as thou wast wont to be; -See as thou wast wont to see: -Dian's bud o'er Cupid's flower -Hath such force and blessed power. -Now, my Titania; wake you, my sweet queen. - - - -TITANIA -My Oberon! what visions have I seen! -Methought I was enamour'd of an ass. - - - -OBERON -There lies your love. - - - -TITANIA -How came these things to pass? -O, how mine eyes do loathe his visage now! - - - -OBERON -Silence awhile. Robin, take off this head. -Titania, music call; and strike more dead -Than common sleep of all these five the sense. - - - -TITANIA -Music, ho! music, such as charmeth sleep! - - - -Music, still - - -PUCK -Now, when thou wakest, with thine -own fool's eyes peep. - - - -OBERON -Sound, music! Come, my queen, take hands with me, -And rock the ground whereon these sleepers be. -Now thou and I are new in amity, -And will to-morrow midnight solemnly -Dance in Duke Theseus' house triumphantly, -And bless it to all fair prosperity: -There shall the pairs of faithful lovers be -Wedded, with Theseus, all in jollity. - - - -PUCK -Fairy king, attend, and mark: -I do hear the morning lark. - - - -OBERON -Then, my queen, in silence sad, -Trip we after the night's shade: -We the globe can compass soon, -Swifter than the wandering moon. - - - -TITANIA -Come, my lord, and in our flight -Tell me how it came this night -That I sleeping here was found -With these mortals on the ground. -Exeunt - - -Horns winded within -Enter THESEUS, HIPPOLYTA, EGEUS, and train - - -THESEUS -Go, one of you, find out the forester; -For now our observation is perform'd; -And since we have the vaward of the day, -My love shall hear the music of my hounds. -Uncouple in the western valley; let them go: -Dispatch, I say, and find the forester. -Exit an Attendant -We will, fair queen, up to the mountain's top, -And mark the musical confusion -Of hounds and echo in conjunction. - - - -HIPPOLYTA -I was with Hercules and Cadmus once, -When in a wood of Crete they bay'd the bear -With hounds of Sparta: never did I hear -Such gallant chiding: for, besides the groves, -The skies, the fountains, every region near -Seem'd all one mutual cry: I never heard -So musical a discord, such sweet thunder. - - - -THESEUS -My hounds are bred out of the Spartan kind, -So flew'd, so sanded, and their heads are hung -With ears that sweep away the morning dew; -Crook-knee'd, and dew-lapp'd like Thessalian bulls; -Slow in pursuit, but match'd in mouth like bells, -Each under each. A cry more tuneable -Was never holla'd to, nor cheer'd with horn, -In Crete, in Sparta, nor in Thessaly: -Judge when you hear. But, soft! what nymphs are these? - - - -EGEUS -My lord, this is my daughter here asleep; -And this, Lysander; this Demetrius is; -This Helena, old Nedar's Helena: -I wonder of their being here together. - - - -THESEUS -No doubt they rose up early to observe -The rite of May, and hearing our intent, -Came here in grace our solemnity. -But speak, Egeus; is not this the day -That Hermia should give answer of her choice? - - - -EGEUS -It is, my lord. - - - -THESEUS -Go, bid the huntsmen wake them with their horns. -Horns and shout within. LYSANDER, DEMETRIUS, -HELENA, and HERMIA wake and start up -Good morrow, friends. Saint Valentine is past: -Begin these wood-birds but to couple now? - - - -LYSANDER -Pardon, my lord. - - - -THESEUS -I pray you all, stand up. -I know you two are rival enemies: -How comes this gentle concord in the world, -That hatred is so far from jealousy, -To sleep by hate, and fear no enmity? - - - -LYSANDER -My lord, I shall reply amazedly, -Half sleep, half waking: but as yet, I swear, -I cannot truly say how I came here; -But, as I think,--for truly would I speak, -And now do I bethink me, so it is,-- -I came with Hermia hither: our intent -Was to be gone from Athens, where we might, -Without the peril of the Athenian law. - - - -EGEUS -Enough, enough, my lord; you have enough: -I beg the law, the law, upon his head. -They would have stolen away; they would, Demetrius, -Thereby to have defeated you and me, -You of your wife and me of my consent, -Of my consent that she should be your wife. - - - -DEMETRIUS -My lord, fair Helen told me of their stealth, -Of this their purpose hither to this wood; -And I in fury hither follow'd them, -Fair Helena in fancy following me. -But, my good lord, I wot not by what power,-- -But by some power it is,--my love to Hermia, -Melted as the snow, seems to me now -As the remembrance of an idle gaud -Which in my childhood I did dote upon; -And all the faith, the virtue of my heart, -The object and the pleasure of mine eye, -Is only Helena. To her, my lord, -Was I betroth'd ere I saw Hermia: -But, like in sickness, did I loathe this food; -But, as in health, come to my natural taste, -Now I do wish it, love it, long for it, -And will for evermore be true to it. - - - -THESEUS -Fair lovers, you are fortunately met: -Of this discourse we more will hear anon. -Egeus, I will overbear your will; -For in the temple by and by with us -These couples shall eternally be knit: -And, for the morning now is something worn, -Our purposed hunting shall be set aside. -Away with us to Athens; three and three, -We'll hold a feast in great solemnity. -Come, Hippolyta. - - - -Exeunt THESEUS, HIPPOLYTA, EGEUS, and train - - -DEMETRIUS -These things seem small and undistinguishable, - - - -HERMIA -Methinks I see these things with parted eye, -When every thing seems double. - - - -HELENA -So methinks: -And I have found Demetrius like a jewel, -Mine own, and not mine own. - - - -DEMETRIUS -Are you sure -That we are awake? It seems to me -That yet we sleep, we dream. Do not you think -The duke was here, and bid us follow him? - - - -HERMIA -Yea; and my father. - - - -HELENA -And Hippolyta. - - - -LYSANDER -And he did bid us follow to the temple. - - - -DEMETRIUS -Why, then, we are awake: let's follow him -And by the way let us recount our dreams. - - - -Exeunt - - -BOTTOM -Awaking When my cue comes, call me, and I will -answer: my next is, 'Most fair Pyramus.' Heigh-ho! -Peter Quince! Flute, the bellows-mender! Snout, -the tinker! Starveling! God's my life, stolen -hence, and left me asleep! I have had a most rare -vision. I have had a dream, past the wit of man to -say what dream it was: man is but an ass, if he go -about to expound this dream. Methought I was--there -is no man can tell what. Methought I was,--and -methought I had,--but man is but a patched fool, if -he will offer to say what methought I had. The eye -of man hath not heard, the ear of man hath not -seen, man's hand is not able to taste, his tongue -to conceive, nor his heart to report, what my dream -was. I will get Peter Quince to write a ballad of -this dream: it shall be called Bottom's Dream, -because it hath no bottom; and I will sing it in the -latter end of a play, before the duke: -peradventure, to make it the more gracious, I shall -sing it at her death. - - - -Exit - - -SCENE II. Athens. QUINCE'S house. -Enter QUINCE, FLUTE, SNOUT, and STARVELING - - -QUINCE -Have you sent to Bottom's house? is he come home yet? - - - -STARVELING -He cannot be heard of. Out of doubt he is -transported. - - - -FLUTE -If he come not, then the play is marred: it goes -not forward, doth it? - - - -QUINCE -It is not possible: you have not a man in all -Athens able to discharge Pyramus but he. - - - -FLUTE -No, he hath simply the best wit of any handicraft -man in Athens. - - - -QUINCE -Yea and the best person too; and he is a very -paramour for a sweet voice. - - - -FLUTE -You must say 'paragon:' a paramour is, God bless us, -a thing of naught. - - - -Enter SNUG - - -SNUG -Masters, the duke is coming from the temple, and -there is two or three lords and ladies more married: -if our sport had gone forward, we had all been made -men. - - - -FLUTE -O sweet bully Bottom! Thus hath he lost sixpence a -day during his life; he could not have 'scaped -sixpence a day: an the duke had not given him -sixpence a day for playing Pyramus, I'll be hanged; -he would have deserved it: sixpence a day in -Pyramus, or nothing. - - - -Enter BOTTOM - - -BOTTOM -Where are these lads? where are these hearts? - - - -QUINCE -Bottom! O most courageous day! O most happy hour! - - - -BOTTOM -Masters, I am to discourse wonders: but ask me not -what; for if I tell you, I am no true Athenian. I -will tell you every thing, right as it fell out. - - - -QUINCE -Let us hear, sweet Bottom. - - - -BOTTOM -Not a word of me. All that I will tell you is, that -the duke hath dined. Get your apparel together, -good strings to your beards, new ribbons to your -pumps; meet presently at the palace; every man look -o'er his part; for the short and the long is, our -play is preferred. In any case, let Thisby have -clean linen; and let not him that plays the lion -pair his nails, for they shall hang out for the -lion's claws. And, most dear actors, eat no onions -nor garlic, for we are to utter sweet breath; and I -do not doubt but to hear them say, it is a sweet -comedy. No more words: away! go, away! - - - -Exeunt - - - - -ACT V - -SCENE I. Athens. The palace of THESEUS. -Enter THESEUS, HIPPOLYTA, PHILOSTRATE, Lords and -Attendants - - -HIPPOLYTA -'Tis strange my Theseus, that these -lovers speak of. - - - -THESEUS -More strange than true: I never may believe -These antique fables, nor these fairy toys. -Lovers and madmen have such seething brains, -Such shaping fantasies, that apprehend -More than cool reason ever comprehends. -The lunatic, the lover and the poet -Are of imagination all compact: -One sees more devils than vast hell can hold, -That is, the madman: the lover, all as frantic, -Sees Helen's beauty in a brow of Egypt: -The poet's eye, in fine frenzy rolling, -Doth glance from heaven to earth, from earth to heaven; -And as imagination bodies forth -The forms of things unknown, the poet's pen -Turns them to shapes and gives to airy nothing -A local habitation and a name. -Such tricks hath strong imagination, -That if it would but apprehend some joy, -It comprehends some bringer of that joy; -Or in the night, imagining some fear, -How easy is a bush supposed a bear! - - - -HIPPOLYTA -But all the story of the night told over, -And all their minds transfigured so together, -More witnesseth than fancy's images -And grows to something of great constancy; -But, howsoever, strange and admirable. - - - -THESEUS -Here come the lovers, full of joy and mirth. -Enter LYSANDER, DEMETRIUS, HERMIA, and HELENA -Joy, gentle friends! joy and fresh days of love -Accompany your hearts! - - - -LYSANDER -More than to us -Wait in your royal walks, your board, your bed! - - - -THESEUS -Come now; what masques, what dances shall we have, -To wear away this long age of three hours -Between our after-supper and bed-time? -Where is our usual manager of mirth? -What revels are in hand? Is there no play, -To ease the anguish of a torturing hour? -Call Philostrate. - - - -PHILOSTRATE -Here, mighty Theseus. - - - -THESEUS -Say, what abridgement have you for this evening? -What masque? what music? How shall we beguile -The lazy time, if not with some delight? - - - -PHILOSTRATE -There is a brief how many sports are ripe: -Make choice of which your highness will see first. - - - -Giving a paper - - -THESEUS -Reads 'The battle with the Centaurs, to be sung -By an Athenian eunuch to the harp.' -We'll none of that: that have I told my love, -In glory of my kinsman Hercules. -Reads -'The riot of the tipsy Bacchanals, -Tearing the Thracian singer in their rage.' -That is an old device; and it was play'd -When I from Thebes came last a conqueror. -Reads -'The thrice three Muses mourning for the death -Of Learning, late deceased in beggary.' -That is some satire, keen and critical, -Not sorting with a nuptial ceremony. -Reads -'A tedious brief scene of young Pyramus -And his love Thisbe; very tragical mirth.' -Merry and tragical! tedious and brief! -That is, hot ice and wondrous strange snow. -How shall we find the concord of this discord? - - - -PHILOSTRATE -A play there is, my lord, some ten words long, -Which is as brief as I have known a play; -But by ten words, my lord, it is too long, -Which makes it tedious; for in all the play -There is not one word apt, one player fitted: -And tragical, my noble lord, it is; -For Pyramus therein doth kill himself. -Which, when I saw rehearsed, I must confess, -Made mine eyes water; but more merry tears -The passion of loud laughter never shed. - - - -THESEUS -What are they that do play it? - - - -PHILOSTRATE -Hard-handed men that work in Athens here, -Which never labour'd in their minds till now, -And now have toil'd their unbreathed memories -With this same play, against your nuptial. - - - -THESEUS -And we will hear it. - - - -PHILOSTRATE -No, my noble lord; -It is not for you: I have heard it over, -And it is nothing, nothing in the world; -Unless you can find sport in their intents, -Extremely stretch'd and conn'd with cruel pain, -To do you service. - - - -THESEUS -I will hear that play; -For never anything can be amiss, -When simpleness and duty tender it. -Go, bring them in: and take your places, ladies. - - - -Exit PHILOSTRATE - - -HIPPOLYTA -I love not to see wretchedness o'er charged -And duty in his service perishing. - - - -THESEUS -Why, gentle sweet, you shall see no such thing. - - - -HIPPOLYTA -He says they can do nothing in this kind. - - - -THESEUS -The kinder we, to give them thanks for nothing. -Our sport shall be to take what they mistake: -And what poor duty cannot do, noble respect -Takes it in might, not merit. -Where I have come, great clerks have purposed -To greet me with premeditated welcomes; -Where I have seen them shiver and look pale, -Make periods in the midst of sentences, -Throttle their practised accent in their fears -And in conclusion dumbly have broke off, -Not paying me a welcome. Trust me, sweet, -Out of this silence yet I pick'd a welcome; -And in the modesty of fearful duty -I read as much as from the rattling tongue -Of saucy and audacious eloquence. -Love, therefore, and tongue-tied simplicity -In least speak most, to my capacity. - - - -Re-enter PHILOSTRATE - - -PHILOSTRATE -So please your grace, the Prologue is address'd. - - - -THESEUS -Let him approach. - - -Flourish of trumpets -Enter QUINCE for the Prologue - - -Prologue -If we offend, it is with our good will. -That you should think, we come not to offend, -But with good will. To show our simple skill, -That is the true beginning of our end. -Consider then we come but in despite. -We do not come as minding to contest you, -Our true intent is. All for your delight -We are not here. That you should here repent you, -The actors are at hand and by their show -You shall know all that you are like to know. - - - -THESEUS -This fellow doth not stand upon points. - - - -LYSANDER -He hath rid his prologue like a rough colt; he knows -not the stop. A good moral, my lord: it is not -enough to speak, but to speak true. - - - -HIPPOLYTA -Indeed he hath played on his prologue like a child -on a recorder; a sound, but not in government. - - - -THESEUS -His speech, was like a tangled chain; nothing -impaired, but all disordered. Who is next? - - - -Enter Pyramus and Thisbe, Wall, Moonshine, and Lion - - -Prologue -Gentles, perchance you wonder at this show; -But wonder on, till truth make all things plain. -This man is Pyramus, if you would know; -This beauteous lady Thisby is certain. -This man, with lime and rough-cast, doth present -Wall, that vile Wall which did these lovers sunder; -And through Wall's chink, poor souls, they are content -To whisper. At the which let no man wonder. -This man, with lanthorn, dog, and bush of thorn, -Presenteth Moonshine; for, if you will know, -By moonshine did these lovers think no scorn -To meet at Ninus' tomb, there, there to woo. -This grisly beast, which Lion hight by name, -The trusty Thisby, coming first by night, -Did scare away, or rather did affright; -And, as she fled, her mantle she did fall, -Which Lion vile with bloody mouth did stain. -Anon comes Pyramus, sweet youth and tall, -And finds his trusty Thisby's mantle slain: -Whereat, with blade, with bloody blameful blade, -He bravely broach'd is boiling bloody breast; -And Thisby, tarrying in mulberry shade, -His dagger drew, and died. For all the rest, -Let Lion, Moonshine, Wall, and lovers twain -At large discourse, while here they do remain. - - - -Exeunt Prologue, Thisbe, Lion, and Moonshine - - -THESEUS -I wonder if the lion be to speak. - - - -DEMETRIUS -No wonder, my lord: one lion may, when many asses do. - - - -Wall -In this same interlude it doth befall -That I, one Snout by name, present a wall; -And such a wall, as I would have you think, -That had in it a crannied hole or chink, -Through which the lovers, Pyramus and Thisby, -Did whisper often very secretly. -This loam, this rough-cast and this stone doth show -That I am that same wall; the truth is so: -And this the cranny is, right and sinister, -Through which the fearful lovers are to whisper. - - - -THESEUS -Would you desire lime and hair to speak better? - - - -DEMETRIUS -It is the wittiest partition that ever I heard -discourse, my lord. - - - -Enter Pyramus - - -THESEUS -Pyramus draws near the wall: silence! - - - -Pyramus -O grim-look'd night! O night with hue so black! -O night, which ever art when day is not! -O night, O night! alack, alack, alack, -I fear my Thisby's promise is forgot! -And thou, O wall, O sweet, O lovely wall, -That stand'st between her father's ground and mine! -Thou wall, O wall, O sweet and lovely wall, -Show me thy chink, to blink through with mine eyne! -Wall holds up his fingers -Thanks, courteous wall: Jove shield thee well for this! -But what see I? No Thisby do I see. -O wicked wall, through whom I see no bliss! -Cursed be thy stones for thus deceiving me! - - - -THESEUS -The wall, methinks, being sensible, should curse again. - - - -Pyramus -No, in truth, sir, he should not. 'Deceiving me' -is Thisby's cue: she is to enter now, and I am to -spy her through the wall. You shall see, it will -fall pat as I told you. Yonder she comes. - - - -Enter Thisbe - - -Thisbe -O wall, full often hast thou heard my moans, -For parting my fair Pyramus and me! -My cherry lips have often kiss'd thy stones, -Thy stones with lime and hair knit up in thee. - - - -Pyramus -I see a voice: now will I to the chink, -To spy an I can hear my Thisby's face. Thisby! - - - -Thisbe -My love thou art, my love I think. - - - -Pyramus -Think what thou wilt, I am thy lover's grace; -And, like Limander, am I trusty still. - - - -Thisbe -And I like Helen, till the Fates me kill. - - - -Pyramus -Not Shafalus to Procrus was so true. - - - -Thisbe -As Shafalus to Procrus, I to you. - - - -Pyramus -O kiss me through the hole of this vile wall! - - - -Thisbe -I kiss the wall's hole, not your lips at all. - - - -Pyramus -Wilt thou at Ninny's tomb meet me straightway? - - - -Thisbe -'Tide life, 'tide death, I come without delay. - - - -Exeunt Pyramus and Thisbe - - -Wall -Thus have I, Wall, my part discharged so; -And, being done, thus Wall away doth go. - - - -Exit - - -THESEUS -Now is the mural down between the two neighbours. - - - -DEMETRIUS -No remedy, my lord, when walls are so wilful to hear -without warning. - - - -HIPPOLYTA -This is the silliest stuff that ever I heard. - - - -THESEUS -The best in this kind are but shadows; and the worst -are no worse, if imagination amend them. - - - -HIPPOLYTA -It must be your imagination then, and not theirs. - - - -THESEUS -If we imagine no worse of them than they of -themselves, they may pass for excellent men. Here -come two noble beasts in, a man and a lion. - - - -Enter Lion and Moonshine - - -Lion -You, ladies, you, whose gentle hearts do fear -The smallest monstrous mouse that creeps on floor, -May now perchance both quake and tremble here, -When lion rough in wildest rage doth roar. -Then know that I, one Snug the joiner, am -A lion-fell, nor else no lion's dam; -For, if I should as lion come in strife -Into this place, 'twere pity on my life. - - - -THESEUS -A very gentle beast, of a good conscience. - - - -DEMETRIUS -The very best at a beast, my lord, that e'er I saw. - - - -LYSANDER -This lion is a very fox for his valour. - - - -THESEUS -True; and a goose for his discretion. - - - -DEMETRIUS -Not so, my lord; for his valour cannot carry his -discretion; and the fox carries the goose. - - - -THESEUS -His discretion, I am sure, cannot carry his valour; -for the goose carries not the fox. It is well: -leave it to his discretion, and let us listen to the moon. - - - -Moonshine -This lanthorn doth the horned moon present;-- - - - -DEMETRIUS -He should have worn the horns on his head. - - - -THESEUS -He is no crescent, and his horns are -invisible within the circumference. - - - -Moonshine -This lanthorn doth the horned moon present; -Myself the man i' the moon do seem to be. - - - -THESEUS -This is the greatest error of all the rest: the man -should be put into the lanthorn. How is it else the -man i' the moon? - - - -DEMETRIUS -He dares not come there for the candle; for, you -see, it is already in snuff. - - - -HIPPOLYTA -I am aweary of this moon: would he would change! - - - -THESEUS -It appears, by his small light of discretion, that -he is in the wane; but yet, in courtesy, in all -reason, we must stay the time. - - - -LYSANDER -Proceed, Moon. - - - -Moonshine -All that I have to say, is, to tell you that the -lanthorn is the moon; I, the man in the moon; this -thorn-bush, my thorn-bush; and this dog, my dog. - - - -DEMETRIUS -Why, all these should be in the lanthorn; for all -these are in the moon. But, silence! here comes Thisbe. - - - -Enter Thisbe - - -Thisbe -This is old Ninny's tomb. Where is my love? - - - -Lion -Roaring Oh-- - - - -Thisbe runs off - - -DEMETRIUS -Well roared, Lion. - - - -THESEUS -Well run, Thisbe. - - - -HIPPOLYTA -Well shone, Moon. Truly, the moon shines with a -good grace. - - - -The Lion shakes Thisbe's mantle, and exit - - -THESEUS -Well moused, Lion. - - - -LYSANDER -And so the lion vanished. - - - -DEMETRIUS -And then came Pyramus. - - - -Enter Pyramus - - -Pyramus -Sweet Moon, I thank thee for thy sunny beams; -I thank thee, Moon, for shining now so bright; -For, by thy gracious, golden, glittering gleams, -I trust to take of truest Thisby sight. -But stay, O spite! -But mark, poor knight, -What dreadful dole is here! -Eyes, do you see? -How can it be? -O dainty duck! O dear! -Thy mantle good, -What, stain'd with blood! -Approach, ye Furies fell! -O Fates, come, come, -Cut thread and thrum; -Quail, crush, conclude, and quell! - - - -THESEUS -This passion, and the death of a dear friend, would -go near to make a man look sad. - - - -HIPPOLYTA -Beshrew my heart, but I pity the man. - - - -Pyramus -O wherefore, Nature, didst thou lions frame? -Since lion vile hath here deflower'd my dear: -Which is--no, no--which was the fairest dame -That lived, that loved, that liked, that look'd -with cheer. -Come, tears, confound; -Out, sword, and wound -The pap of Pyramus; -Ay, that left pap, -Where heart doth hop: -Stabs himself -Thus die I, thus, thus, thus. -Now am I dead, -Now am I fled; -My soul is in the sky: -Tongue, lose thy light; -Moon take thy flight: -Exit Moonshine -Now die, die, die, die, die. - - - -Dies - - -DEMETRIUS -No die, but an ace, for him; for he is but one. - - - -LYSANDER -Less than an ace, man; for he is dead; he is nothing. - - - -THESEUS -With the help of a surgeon he might yet recover, and -prove an ass. - - - -HIPPOLYTA -How chance Moonshine is gone before Thisbe comes -back and finds her lover? - - - -THESEUS -She will find him by starlight. Here she comes; and -her passion ends the play. - - - -Re-enter Thisbe - - -HIPPOLYTA -Methinks she should not use a long one for such a -Pyramus: I hope she will be brief. - - - -DEMETRIUS -A mote will turn the balance, which Pyramus, which -Thisbe, is the better; he for a man, God warrant us; -she for a woman, God bless us. - - - -LYSANDER -She hath spied him already with those sweet eyes. - - - -DEMETRIUS -And thus she means, videlicet:-- - - - -Thisbe -Asleep, my love? -What, dead, my dove? -O Pyramus, arise! -Speak, speak. Quite dumb? -Dead, dead? A tomb -Must cover thy sweet eyes. -These My lips, -This cherry nose, -These yellow cowslip cheeks, -Are gone, are gone: -Lovers, make moan: -His eyes were green as leeks. -O Sisters Three, -Come, come to me, -With hands as pale as milk; -Lay them in gore, -Since you have shore -With shears his thread of silk. -Tongue, not a word: -Come, trusty sword; -Come, blade, my breast imbrue: -Stabs herself -And, farewell, friends; -Thus Thisby ends: -Adieu, adieu, adieu. - - - -Dies - - -THESEUS -Moonshine and Lion are left to bury the dead. - - - -DEMETRIUS -Ay, and Wall too. - - - -BOTTOM -Starting up No assure you; the wall is down that -parted their fathers. Will it please you to see the -epilogue, or to hear a Bergomask dance between two -of our company? - - - -THESEUS -No epilogue, I pray you; for your play needs no -excuse. Never excuse; for when the players are all -dead, there needs none to be blamed. Marry, if he -that writ it had played Pyramus and hanged himself -in Thisbe's garter, it would have been a fine -tragedy: and so it is, truly; and very notably -discharged. But come, your Bergomask: let your -epilogue alone. -A dance -The iron tongue of midnight hath told twelve: -Lovers, to bed; 'tis almost fairy time. -I fear we shall out-sleep the coming morn -As much as we this night have overwatch'd. -This palpable-gross play hath well beguiled -The heavy gait of night. Sweet friends, to bed. -A fortnight hold we this solemnity, -In nightly revels and new jollity. - - -Exeunt -Enter PUCK - - -PUCK -Now the hungry lion roars, -And the wolf behowls the moon; -Whilst the heavy ploughman snores, -All with weary task fordone. -Now the wasted brands do glow, -Whilst the screech-owl, screeching loud, -Puts the wretch that lies in woe -In remembrance of a shroud. -Now it is the time of night -That the graves all gaping wide, -Every one lets forth his sprite, -In the church-way paths to glide: -And we fairies, that do run -By the triple Hecate's team, -From the presence of the sun, -Following darkness like a dream, -Now are frolic: not a mouse -Shall disturb this hallow'd house: -I am sent with broom before, -To sweep the dust behind the door. - - - -Enter OBERON and TITANIA with their train - - -OBERON -Through the house give gathering light, -By the dead and drowsy fire: -Every elf and fairy sprite -Hop as light as bird from brier; -And this ditty, after me, -Sing, and dance it trippingly. - - - -TITANIA -First, rehearse your song by rote -To each word a warbling note: -Hand in hand, with fairy grace, -Will we sing, and bless this place. - - - -Song and dance - - -OBERON -Now, until the break of day, -Through this house each fairy stray. -To the best bride-bed will we, -Which by us shall blessed be; -And the issue there create -Ever shall be fortunate. -So shall all the couples three -Ever true in loving be; -And the blots of Nature's hand -Shall not in their issue stand; -Never mole, hare lip, nor scar, -Nor mark prodigious, such as are -Despised in nativity, -Shall upon their children be. -With this field-dew consecrate, -Every fairy take his gait; -And each several chamber bless, -Through this palace, with sweet peace; -And the owner of it blest -Ever shall in safety rest. -Trip away; make no stay; -Meet me all by break of day. - - - -Exeunt OBERON, TITANIA, and train - - -PUCK -If we shadows have offended, -Think but this, and all is mended, -That you have but slumber'd here -While these visions did appear. -And this weak and idle theme, -No more yielding but a dream, -Gentles, do not reprehend: -if you pardon, we will mend: -And, as I am an honest Puck, -If we have unearned luck -Now to 'scape the serpent's tongue, -We will make amends ere long; -Else the Puck a liar call; -So, good night unto you all. -Give me your hands, if we be friends, -And Robin shall restore amends. - - - -
diff --git a/internal/tinyxml2-3.0.0/resources/empty.xml b/internal/tinyxml2-3.0.0/resources/empty.xml deleted file mode 100644 index e69de29..0000000 diff --git a/internal/tinyxml2-3.0.0/resources/utf8test.xml b/internal/tinyxml2-3.0.0/resources/utf8test.xml deleted file mode 100755 index c8e5837..0000000 --- a/internal/tinyxml2-3.0.0/resources/utf8test.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - The world has many languages - Мир имеет много Ñзыков - el mundo tiene muchos idiomas - 世界有很多语言 - <РуÑÑкий название="name" ценноÑÑ‚ÑŒ="value"><имеет> - <汉语 åå­—="name" 价值="value">世界有很多语言 - "Mëtæl!" - <ä>Umlaut Element - diff --git a/internal/tinyxml2-3.0.0/resources/utf8testverify.xml b/internal/tinyxml2-3.0.0/resources/utf8testverify.xml deleted file mode 100755 index 407f10a..0000000 --- a/internal/tinyxml2-3.0.0/resources/utf8testverify.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - The world has many languages - Мир имеет много Ñзыков - el mundo tiene muchos idiomas - 世界有很多语言 - <РуÑÑкий название="name" ценноÑÑ‚ÑŒ="value"><имеет> - <汉语 åå­—="name" 价值="value">世界有很多语言 - "Mëtæl!" - <ä>Umlaut Element - diff --git a/internal/tinyxml2-3.0.0/setversion.py b/internal/tinyxml2-3.0.0/setversion.py deleted file mode 100755 index 98d58de..0000000 --- a/internal/tinyxml2-3.0.0/setversion.py +++ /dev/null @@ -1,123 +0,0 @@ -# Python program to set the version. -############################################## - -import re -import sys -import optparse - -def fileProcess( name, lineFunction ): - filestream = open( name, 'r' ) - if filestream.closed: - print( "file " + name + " not open." ) - return - - output = "" - print( "--- Processing " + name + " ---------" ) - while 1: - line = filestream.readline() - if not line: break - output += lineFunction( line ) - filestream.close() - - if not output: return # basic error checking - - print( "Writing file " + name ) - filestream = open( name, "w" ); - filestream.write( output ); - filestream.close() - -def echoInput( line ): - return line - -parser = optparse.OptionParser( "usage: %prog major minor build" ) -(options, args) = parser.parse_args() -if len(args) != 3: - parser.error( "incorrect number of arguments" ); - -major = args[0] -minor = args[1] -build = args[2] -versionStr = major + "." + minor + "." + build - -print ("Setting dox,tinyxml2.h") -print ("Version: " + major + "." + minor + "." + build) - -#### Write the tinyxml.h #### - -def engineRule( line ): - - matchMajor = "static const int TIXML2_MAJOR_VERSION" - matchMinor = "static const int TIXML2_MINOR_VERSION" - matchBuild = "static const int TIXML2_PATCH_VERSION" - - if line[0:len(matchMajor)] == matchMajor: - print( "1)tinyxml2.h Major found" ) - return matchMajor + " = " + major + ";\n" - - elif line[0:len(matchMinor)] == matchMinor: - print( "2)tinyxml2.h Minor found" ) - return matchMinor + " = " + minor + ";\n" - - elif line[0:len(matchBuild)] == matchBuild: - print( "3)tinyxml2.h Build found" ) - return matchBuild + " = " + build + ";\n" - - else: - return line; - -fileProcess( "tinyxml2.h", engineRule ) - - -#### Write the dox #### - -def doxRule( line ): - - match = "PROJECT_NUMBER" - - if line[0:len( match )] == match: - print( "dox project found" ) - return "PROJECT_NUMBER = " + major + "." + minor + "." + build + "\n" - - else: - return line; - -fileProcess( "dox", doxRule ) - - -#### Write the CMakeLists.txt #### - -def cmakeRule1( line ): - - matchVersion = "set(GENERIC_LIB_VERSION" - - if line[0:len(matchVersion)] == matchVersion: - print( "1)tinyxml2.h Major found" ) - return matchVersion + " \"" + major + "." + minor + "." + build + "\")" + "\n" - - else: - return line; - -fileProcess( "CMakeLists.txt", cmakeRule1 ) - -def cmakeRule2( line ): - - matchSoversion = "set(GENERIC_LIB_SOVERSION" - - if line[0:len(matchSoversion)] == matchSoversion: - print( "1)tinyxml2.h Major found" ) - return matchSoversion + " \"" + major + "\")" + "\n" - - else: - return line; - -fileProcess( "CMakeLists.txt", cmakeRule2 ) - -print( "Release note:" ) -print( '1. Build. g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe' ) -print( '2. Commit. git commit -am"setting the version to ' + versionStr + '"' ) -print( '3. Tag. git tag ' + versionStr ) -print( ' OR git tag -a ' + versionStr + ' -m [tag message]' ) -print( 'Remember to "git push" both code and tag. For the tag:' ) -print( 'git push origin [tagname]') - - \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/tinyxml2.cpp b/internal/tinyxml2-3.0.0/tinyxml2.cpp deleted file mode 100755 index 245c747..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2.cpp +++ /dev/null @@ -1,2344 +0,0 @@ -/* -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include "tinyxml2.h" - -#include // yes, this one new style header, is in the Android SDK. -#if defined(ANDROID_NDK) || defined(__QNXNTO__) -# include -#else -# include -#endif - -static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF -static const char LF = LINE_FEED; -static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out -static const char CR = CARRIAGE_RETURN; -static const char SINGLE_QUOTE = '\''; -static const char DOUBLE_QUOTE = '\"'; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// ef bb bf (Microsoft "lead bytes") - designates UTF-8 - -static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -namespace tinyxml2 -{ - -struct Entity { - const char* pattern; - int length; - char value; -}; - -static const int NUM_ENTITIES = 5; -static const Entity entities[NUM_ENTITIES] = { - { "quot", 4, DOUBLE_QUOTE }, - { "amp", 3, '&' }, - { "apos", 4, SINGLE_QUOTE }, - { "lt", 2, '<' }, - { "gt", 2, '>' } -}; - - -StrPair::~StrPair() -{ - Reset(); -} - - -void StrPair::TransferTo( StrPair* other ) -{ - if ( this == other ) { - return; - } - // This in effect implements the assignment operator by "moving" - // ownership (as in auto_ptr). - - TIXMLASSERT( other->_flags == 0 ); - TIXMLASSERT( other->_start == 0 ); - TIXMLASSERT( other->_end == 0 ); - - other->Reset(); - - other->_flags = _flags; - other->_start = _start; - other->_end = _end; - - _flags = 0; - _start = 0; - _end = 0; -} - -void StrPair::Reset() -{ - if ( _flags & NEEDS_DELETE ) { - delete [] _start; - } - _flags = 0; - _start = 0; - _end = 0; -} - - -void StrPair::SetStr( const char* str, int flags ) -{ - Reset(); - size_t len = strlen( str ); - _start = new char[ len+1 ]; - memcpy( _start, str, len+1 ); - _end = _start + len; - _flags = flags | NEEDS_DELETE; -} - - -char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) -{ - TIXMLASSERT( endTag && *endTag ); - - char* start = p; - char endChar = *endTag; - size_t length = strlen( endTag ); - - // Inner loop of text parsing. - while ( *p ) { - if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { - Set( start, p, strFlags ); - return p + length; - } - ++p; - } - return 0; -} - - -char* StrPair::ParseName( char* p ) -{ - if ( !p || !(*p) ) { - return 0; - } - if ( !XMLUtil::IsNameStartChar( *p ) ) { - return 0; - } - - char* const start = p; - ++p; - while ( *p && XMLUtil::IsNameChar( *p ) ) { - ++p; - } - - Set( start, p, 0 ); - return p; -} - - -void StrPair::CollapseWhitespace() -{ - // Adjusting _start would cause undefined behavior on delete[] - TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); - // Trim leading space. - _start = XMLUtil::SkipWhiteSpace( _start ); - - if ( *_start ) { - char* p = _start; // the read pointer - char* q = _start; // the write pointer - - while( *p ) { - if ( XMLUtil::IsWhiteSpace( *p )) { - p = XMLUtil::SkipWhiteSpace( p ); - if ( *p == 0 ) { - break; // don't write to q; this trims the trailing space. - } - *q = ' '; - ++q; - } - *q = *p; - ++q; - ++p; - } - *q = 0; - } -} - - -const char* StrPair::GetStr() -{ - TIXMLASSERT( _start ); - TIXMLASSERT( _end ); - if ( _flags & NEEDS_FLUSH ) { - *_end = 0; - _flags ^= NEEDS_FLUSH; - - if ( _flags ) { - char* p = _start; // the read pointer - char* q = _start; // the write pointer - - while( p < _end ) { - if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { - // CR-LF pair becomes LF - // CR alone becomes LF - // LF-CR becomes LF - if ( *(p+1) == LF ) { - p += 2; - } - else { - ++p; - } - *q++ = LF; - } - else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { - if ( *(p+1) == CR ) { - p += 2; - } - else { - ++p; - } - *q++ = LF; - } - else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { - // Entities handled by tinyXML2: - // - special entities in the entity table [in/out] - // - numeric character reference [in] - // 中 or 中 - - if ( *(p+1) == '#' ) { - const int buflen = 10; - char buf[buflen] = { 0 }; - int len = 0; - char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); - if ( adjusted == 0 ) { - *q = *p; - ++p; - ++q; - } - else { - TIXMLASSERT( 0 <= len && len <= buflen ); - TIXMLASSERT( q + len <= adjusted ); - p = adjusted; - memcpy( q, buf, len ); - q += len; - } - } - else { - int i=0; - for(; i(p); - // Check for BOM: - if ( *(pu+0) == TIXML_UTF_LEAD_0 - && *(pu+1) == TIXML_UTF_LEAD_1 - && *(pu+2) == TIXML_UTF_LEAD_2 ) { - *bom = true; - p += 3; - } - TIXMLASSERT( p ); - return p; -} - - -void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) -{ - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) { - *length = 1; - } - else if ( input < 0x800 ) { - *length = 2; - } - else if ( input < 0x10000 ) { - *length = 3; - } - else if ( input < 0x200000 ) { - *length = 4; - } - else { - *length = 0; // This code won't covert this correctly anyway. - return; - } - - output += *length; - - // Scary scary fall throughs. - switch (*length) { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: - --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); - break; - default: - TIXMLASSERT( false ); - } -} - - -const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) -{ - // Presume an entity, and pull it out. - *length = 0; - - if ( *(p+1) == '#' && *(p+2) ) { - unsigned long ucs = 0; - TIXMLASSERT( sizeof( ucs ) >= 4 ); - ptrdiff_t delta = 0; - unsigned mult = 1; - static const char SEMICOLON = ';'; - - if ( *(p+2) == 'x' ) { - // Hexadecimal. - const char* q = p+3; - if ( !(*q) ) { - return 0; - } - - q = strchr( q, SEMICOLON ); - - if ( !q ) { - return 0; - } - TIXMLASSERT( *q == SEMICOLON ); - - delta = q-p; - --q; - - while ( *q != 'x' ) { - unsigned int digit = 0; - - if ( *q >= '0' && *q <= '9' ) { - digit = *q - '0'; - } - else if ( *q >= 'a' && *q <= 'f' ) { - digit = *q - 'a' + 10; - } - else if ( *q >= 'A' && *q <= 'F' ) { - digit = *q - 'A' + 10; - } - else { - return 0; - } - TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); - TIXMLASSERT( digit >= 0 && digit < 16); - const unsigned int digitScaled = mult * digit; - TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); - ucs += digitScaled; - TIXMLASSERT( mult <= UINT_MAX / 16 ); - mult *= 16; - --q; - } - } - else { - // Decimal. - const char* q = p+2; - if ( !(*q) ) { - return 0; - } - - q = strchr( q, SEMICOLON ); - - if ( !q ) { - return 0; - } - TIXMLASSERT( *q == SEMICOLON ); - - delta = q-p; - --q; - - while ( *q != '#' ) { - if ( *q >= '0' && *q <= '9' ) { - const unsigned int digit = *q - '0'; - TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); - const unsigned int digitScaled = mult * digit; - TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); - ucs += digitScaled; - } - else { - return 0; - } - TIXMLASSERT( mult <= UINT_MAX / 10 ); - mult *= 10; - --q; - } - } - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); - return p + delta + 1; - } - return p+1; -} - - -void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); -} - - -void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); -} - - -void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); -} - -/* - ToStr() of a number is a very tricky topic. - https://github.com/leethomason/tinyxml2/issues/106 -*/ -void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); -} - - -void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); -} - - -bool XMLUtil::ToInt( const char* str, int* value ) -{ - if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { - return true; - } - return false; -} - -bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) -{ - if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { - return true; - } - return false; -} - -bool XMLUtil::ToBool( const char* str, bool* value ) -{ - int ival = 0; - if ( ToInt( str, &ival )) { - *value = (ival==0) ? false : true; - return true; - } - if ( StringEqual( str, "true" ) ) { - *value = true; - return true; - } - else if ( StringEqual( str, "false" ) ) { - *value = false; - return true; - } - return false; -} - - -bool XMLUtil::ToFloat( const char* str, float* value ) -{ - if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { - return true; - } - return false; -} - -bool XMLUtil::ToDouble( const char* str, double* value ) -{ - if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { - return true; - } - return false; -} - - -char* XMLDocument::Identify( char* p, XMLNode** node ) -{ - TIXMLASSERT( node ); - TIXMLASSERT( p ); - char* const start = p; - p = XMLUtil::SkipWhiteSpace( p ); - if( !*p ) { - *node = 0; - TIXMLASSERT( p ); - return p; - } - - // What is this thing? - // These strings define the matching patters: - static const char* xmlHeader = { "_memPool = &_commentPool; - p += xmlHeaderLen; - } - else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { - TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); - returnNode = new (_commentPool.Alloc()) XMLComment( this ); - returnNode->_memPool = &_commentPool; - p += commentHeaderLen; - } - else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { - TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); - XMLText* text = new (_textPool.Alloc()) XMLText( this ); - returnNode = text; - returnNode->_memPool = &_textPool; - p += cdataHeaderLen; - text->SetCData( true ); - } - else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { - TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); - returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); - returnNode->_memPool = &_commentPool; - p += dtdHeaderLen; - } - else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { - TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); - returnNode = new (_elementPool.Alloc()) XMLElement( this ); - returnNode->_memPool = &_elementPool; - p += elementHeaderLen; - } - else { - TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); - returnNode = new (_textPool.Alloc()) XMLText( this ); - returnNode->_memPool = &_textPool; - p = start; // Back it up, all the text counts. - } - - TIXMLASSERT( returnNode ); - TIXMLASSERT( p ); - *node = returnNode; - return p; -} - - -bool XMLDocument::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - if ( visitor->VisitEnter( *this ) ) { - for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { - if ( !node->Accept( visitor ) ) { - break; - } - } - } - return visitor->VisitExit( *this ); -} - - -// --------- XMLNode ----------- // - -XMLNode::XMLNode( XMLDocument* doc ) : - _document( doc ), - _parent( 0 ), - _firstChild( 0 ), _lastChild( 0 ), - _prev( 0 ), _next( 0 ), - _memPool( 0 ) -{ -} - - -XMLNode::~XMLNode() -{ - DeleteChildren(); - if ( _parent ) { - _parent->Unlink( this ); - } -} - -const char* XMLNode::Value() const -{ - return _value.GetStr(); -} - -void XMLNode::SetValue( const char* str, bool staticMem ) -{ - if ( staticMem ) { - _value.SetInternedStr( str ); - } - else { - _value.SetStr( str ); - } -} - - -void XMLNode::DeleteChildren() -{ - while( _firstChild ) { - TIXMLASSERT( _firstChild->_document == _document ); - XMLNode* node = _firstChild; - Unlink( node ); - - DeleteNode( node ); - } - _firstChild = _lastChild = 0; -} - - -void XMLNode::Unlink( XMLNode* child ) -{ - TIXMLASSERT( child ); - TIXMLASSERT( child->_document == _document ); - if ( child == _firstChild ) { - _firstChild = _firstChild->_next; - } - if ( child == _lastChild ) { - _lastChild = _lastChild->_prev; - } - - if ( child->_prev ) { - child->_prev->_next = child->_next; - } - if ( child->_next ) { - child->_next->_prev = child->_prev; - } - child->_parent = 0; -} - - -void XMLNode::DeleteChild( XMLNode* node ) -{ - TIXMLASSERT( node ); - TIXMLASSERT( node->_document == _document ); - TIXMLASSERT( node->_parent == this ); - DeleteNode( node ); -} - - -XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) -{ - TIXMLASSERT( addThis ); - if ( addThis->_document != _document ) { - TIXMLASSERT( false ); - return 0; - } - InsertChildPreamble( addThis ); - - if ( _lastChild ) { - TIXMLASSERT( _firstChild ); - TIXMLASSERT( _lastChild->_next == 0 ); - _lastChild->_next = addThis; - addThis->_prev = _lastChild; - _lastChild = addThis; - - addThis->_next = 0; - } - else { - TIXMLASSERT( _firstChild == 0 ); - _firstChild = _lastChild = addThis; - - addThis->_prev = 0; - addThis->_next = 0; - } - addThis->_parent = this; - return addThis; -} - - -XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) -{ - TIXMLASSERT( addThis ); - if ( addThis->_document != _document ) { - TIXMLASSERT( false ); - return 0; - } - InsertChildPreamble( addThis ); - - if ( _firstChild ) { - TIXMLASSERT( _lastChild ); - TIXMLASSERT( _firstChild->_prev == 0 ); - - _firstChild->_prev = addThis; - addThis->_next = _firstChild; - _firstChild = addThis; - - addThis->_prev = 0; - } - else { - TIXMLASSERT( _lastChild == 0 ); - _firstChild = _lastChild = addThis; - - addThis->_prev = 0; - addThis->_next = 0; - } - addThis->_parent = this; - return addThis; -} - - -XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) -{ - TIXMLASSERT( addThis ); - if ( addThis->_document != _document ) { - TIXMLASSERT( false ); - return 0; - } - - TIXMLASSERT( afterThis ); - - if ( afterThis->_parent != this ) { - TIXMLASSERT( false ); - return 0; - } - - if ( afterThis->_next == 0 ) { - // The last node or the only node. - return InsertEndChild( addThis ); - } - InsertChildPreamble( addThis ); - addThis->_prev = afterThis; - addThis->_next = afterThis->_next; - afterThis->_next->_prev = addThis; - afterThis->_next = addThis; - addThis->_parent = this; - return addThis; -} - - - - -const XMLElement* XMLNode::FirstChildElement( const char* value ) const -{ - for( XMLNode* node=_firstChild; node; node=node->_next ) { - XMLElement* element = node->ToElement(); - if ( element ) { - if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { - return element; - } - } - } - return 0; -} - - -const XMLElement* XMLNode::LastChildElement( const char* value ) const -{ - for( XMLNode* node=_lastChild; node; node=node->_prev ) { - XMLElement* element = node->ToElement(); - if ( element ) { - if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { - return element; - } - } - } - return 0; -} - - -const XMLElement* XMLNode::NextSiblingElement( const char* value ) const -{ - for( XMLNode* node=this->_next; node; node = node->_next ) { - const XMLElement* element = node->ToElement(); - if ( element - && (!value || XMLUtil::StringEqual( value, node->Value() ))) { - return element; - } - } - return 0; -} - - -const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const -{ - for( XMLNode* node=_prev; node; node = node->_prev ) { - const XMLElement* element = node->ToElement(); - if ( element - && (!value || XMLUtil::StringEqual( value, node->Value() ))) { - return element; - } - } - return 0; -} - - -char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) -{ - // This is a recursive method, but thinking about it "at the current level" - // it is a pretty simple flat list: - // - // - // - // With a special case: - // - // - // - // - // Where the closing element (/foo) *must* be the next thing after the opening - // element, and the names must match. BUT the tricky bit is that the closing - // element will be read by the child. - // - // 'endTag' is the end tag for this node, it is returned by a call to a child. - // 'parentEnd' is the end tag for the parent, which is filled in and returned. - - while( p && *p ) { - XMLNode* node = 0; - - p = _document->Identify( p, &node ); - if ( node == 0 ) { - break; - } - - StrPair endTag; - p = node->ParseDeep( p, &endTag ); - if ( !p ) { - DeleteNode( node ); - if ( !_document->Error() ) { - _document->SetError( XML_ERROR_PARSING, 0, 0 ); - } - break; - } - - XMLElement* ele = node->ToElement(); - if ( ele ) { - // We read the end tag. Return it to the parent. - if ( ele->ClosingType() == XMLElement::CLOSING ) { - if ( parentEnd ) { - ele->_value.TransferTo( parentEnd ); - } - node->_memPool->SetTracked(); // created and then immediately deleted. - DeleteNode( node ); - return p; - } - - // Handle an end tag returned to this level. - // And handle a bunch of annoying errors. - bool mismatch = false; - if ( endTag.Empty() ) { - if ( ele->ClosingType() == XMLElement::OPEN ) { - mismatch = true; - } - } - else { - if ( ele->ClosingType() != XMLElement::OPEN ) { - mismatch = true; - } - else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) { - mismatch = true; - } - } - if ( mismatch ) { - _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); - DeleteNode( node ); - break; - } - } - InsertEndChild( node ); - } - return 0; -} - -void XMLNode::DeleteNode( XMLNode* node ) -{ - if ( node == 0 ) { - return; - } - MemPool* pool = node->_memPool; - node->~XMLNode(); - pool->Free( node ); -} - -void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const -{ - TIXMLASSERT( insertThis ); - TIXMLASSERT( insertThis->_document == _document ); - - if ( insertThis->_parent ) - insertThis->_parent->Unlink( insertThis ); - else - insertThis->_memPool->SetTracked(); -} - -// --------- XMLText ---------- // -char* XMLText::ParseDeep( char* p, StrPair* ) -{ - const char* start = p; - if ( this->CData() ) { - p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); - } - return p; - } - else { - int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; - if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { - flags |= StrPair::COLLAPSE_WHITESPACE; - } - - p = _value.ParseText( p, "<", flags ); - if ( p && *p ) { - return p-1; - } - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); - } - } - return 0; -} - - -XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? - text->SetCData( this->CData() ); - return text; -} - - -bool XMLText::ShallowEqual( const XMLNode* compare ) const -{ - const XMLText* text = compare->ToText(); - return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); -} - - -bool XMLText::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - - -// --------- XMLComment ---------- // - -XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) -{ -} - - -XMLComment::~XMLComment() -{ -} - - -char* XMLComment::ParseDeep( char* p, StrPair* ) -{ - // Comment parses as text. - const char* start = p; - p = _value.ParseText( p, "-->", StrPair::COMMENT ); - if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); - } - return p; -} - - -XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? - return comment; -} - - -bool XMLComment::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLComment* comment = compare->ToComment(); - return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); -} - - -bool XMLComment::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - - -// --------- XMLDeclaration ---------- // - -XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) -{ -} - - -XMLDeclaration::~XMLDeclaration() -{ - //printf( "~XMLDeclaration\n" ); -} - - -char* XMLDeclaration::ParseDeep( char* p, StrPair* ) -{ - // Declaration parses as text. - const char* start = p; - p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); - if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); - } - return p; -} - - -XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? - return dec; -} - - -bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLDeclaration* declaration = compare->ToDeclaration(); - return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); -} - - - -bool XMLDeclaration::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - -// --------- XMLUnknown ---------- // - -XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) -{ -} - - -XMLUnknown::~XMLUnknown() -{ -} - - -char* XMLUnknown::ParseDeep( char* p, StrPair* ) -{ - // Unknown parses as text. - const char* start = p; - - p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); - } - return p; -} - - -XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? - return text; -} - - -bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLUnknown* unknown = compare->ToUnknown(); - return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); -} - - -bool XMLUnknown::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - -// --------- XMLAttribute ---------- // - -const char* XMLAttribute::Name() const -{ - return _name.GetStr(); -} - -const char* XMLAttribute::Value() const -{ - return _value.GetStr(); -} - -char* XMLAttribute::ParseDeep( char* p, bool processEntities ) -{ - // Parse using the name rules: bug fix, was using ParseText before - p = _name.ParseName( p ); - if ( !p || !*p ) { - return 0; - } - - // Skip white space before = - p = XMLUtil::SkipWhiteSpace( p ); - if ( *p != '=' ) { - return 0; - } - - ++p; // move up to opening quote - p = XMLUtil::SkipWhiteSpace( p ); - if ( *p != '\"' && *p != '\'' ) { - return 0; - } - - char endTag[2] = { *p, 0 }; - ++p; // move past opening quote - - p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); - return p; -} - - -void XMLAttribute::SetName( const char* n ) -{ - _name.SetStr( n ); -} - - -XMLError XMLAttribute::QueryIntValue( int* value ) const -{ - if ( XMLUtil::ToInt( Value(), value )) { - return XML_NO_ERROR; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const -{ - if ( XMLUtil::ToUnsigned( Value(), value )) { - return XML_NO_ERROR; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryBoolValue( bool* value ) const -{ - if ( XMLUtil::ToBool( Value(), value )) { - return XML_NO_ERROR; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryFloatValue( float* value ) const -{ - if ( XMLUtil::ToFloat( Value(), value )) { - return XML_NO_ERROR; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryDoubleValue( double* value ) const -{ - if ( XMLUtil::ToDouble( Value(), value )) { - return XML_NO_ERROR; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -void XMLAttribute::SetAttribute( const char* v ) -{ - _value.SetStr( v ); -} - - -void XMLAttribute::SetAttribute( int v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - - -void XMLAttribute::SetAttribute( unsigned v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - - -void XMLAttribute::SetAttribute( bool v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - -void XMLAttribute::SetAttribute( double v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - -void XMLAttribute::SetAttribute( float v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - - -// --------- XMLElement ---------- // -XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), - _closingType( 0 ), - _rootAttribute( 0 ) -{ -} - - -XMLElement::~XMLElement() -{ - while( _rootAttribute ) { - XMLAttribute* next = _rootAttribute->_next; - DeleteAttribute( _rootAttribute ); - _rootAttribute = next; - } -} - - -const XMLAttribute* XMLElement::FindAttribute( const char* name ) const -{ - for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { - if ( XMLUtil::StringEqual( a->Name(), name ) ) { - return a; - } - } - return 0; -} - - -const char* XMLElement::Attribute( const char* name, const char* value ) const -{ - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return 0; - } - if ( !value || XMLUtil::StringEqual( a->Value(), value )) { - return a->Value(); - } - return 0; -} - - -const char* XMLElement::GetText() const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - return FirstChild()->Value(); - } - return 0; -} - - -void XMLElement::SetText( const char* inText ) -{ - if ( FirstChild() && FirstChild()->ToText() ) - FirstChild()->SetValue( inText ); - else { - XMLText* theText = GetDocument()->NewText( inText ); - InsertFirstChild( theText ); - } -} - - -void XMLElement::SetText( int v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( unsigned v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( bool v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( float v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( double v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -XMLError XMLElement::QueryIntText( int* ival ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToInt( t, ival ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToUnsigned( t, uval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryBoolText( bool* bval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToBool( t, bval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryDoubleText( double* dval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToDouble( t, dval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryFloatText( float* fval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToFloat( t, fval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - - -XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) -{ - XMLAttribute* last = 0; - XMLAttribute* attrib = 0; - for( attrib = _rootAttribute; - attrib; - last = attrib, attrib = attrib->_next ) { - if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { - break; - } - } - if ( !attrib ) { - TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); - attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); - attrib->_memPool = &_document->_attributePool; - if ( last ) { - last->_next = attrib; - } - else { - _rootAttribute = attrib; - } - attrib->SetName( name ); - attrib->_memPool->SetTracked(); // always created and linked. - } - return attrib; -} - - -void XMLElement::DeleteAttribute( const char* name ) -{ - XMLAttribute* prev = 0; - for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { - if ( XMLUtil::StringEqual( name, a->Name() ) ) { - if ( prev ) { - prev->_next = a->_next; - } - else { - _rootAttribute = a->_next; - } - DeleteAttribute( a ); - break; - } - prev = a; - } -} - - -char* XMLElement::ParseAttributes( char* p ) -{ - const char* start = p; - XMLAttribute* prevAttribute = 0; - - // Read the attributes. - while( p ) { - p = XMLUtil::SkipWhiteSpace( p ); - if ( !(*p) ) { - _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); - return 0; - } - - // attribute. - if (XMLUtil::IsNameStartChar( *p ) ) { - TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); - XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); - attrib->_memPool = &_document->_attributePool; - attrib->_memPool->SetTracked(); - - p = attrib->ParseDeep( p, _document->ProcessEntities() ); - if ( !p || Attribute( attrib->Name() ) ) { - DeleteAttribute( attrib ); - _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); - return 0; - } - // There is a minor bug here: if the attribute in the source xml - // document is duplicated, it will not be detected and the - // attribute will be doubly added. However, tracking the 'prevAttribute' - // avoids re-scanning the attribute list. Preferring performance for - // now, may reconsider in the future. - if ( prevAttribute ) { - prevAttribute->_next = attrib; - } - else { - _rootAttribute = attrib; - } - prevAttribute = attrib; - } - // end of the tag - else if ( *p == '/' && *(p+1) == '>' ) { - _closingType = CLOSED; - return p+2; // done; sealed element. - } - // end of the tag - else if ( *p == '>' ) { - ++p; - break; - } - else { - _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); - return 0; - } - } - return p; -} - -void XMLElement::DeleteAttribute( XMLAttribute* attribute ) -{ - if ( attribute == 0 ) { - return; - } - MemPool* pool = attribute->_memPool; - attribute->~XMLAttribute(); - pool->Free( attribute ); -} - -// -// -// foobar -// -char* XMLElement::ParseDeep( char* p, StrPair* strPair ) -{ - // Read the element name. - p = XMLUtil::SkipWhiteSpace( p ); - - // The closing element is the form. It is - // parsed just like a regular element then deleted from - // the DOM. - if ( *p == '/' ) { - _closingType = CLOSING; - ++p; - } - - p = _value.ParseName( p ); - if ( _value.Empty() ) { - return 0; - } - - p = ParseAttributes( p ); - if ( !p || !*p || _closingType ) { - return p; - } - - p = XMLNode::ParseDeep( p, strPair ); - return p; -} - - - -XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? - for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { - element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? - } - return element; -} - - -bool XMLElement::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLElement* other = compare->ToElement(); - if ( other && XMLUtil::StringEqual( other->Value(), Value() )) { - - const XMLAttribute* a=FirstAttribute(); - const XMLAttribute* b=other->FirstAttribute(); - - while ( a && b ) { - if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { - return false; - } - a = a->Next(); - b = b->Next(); - } - if ( a || b ) { - // different count - return false; - } - return true; - } - return false; -} - - -bool XMLElement::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - if ( visitor->VisitEnter( *this, _rootAttribute ) ) { - for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { - if ( !node->Accept( visitor ) ) { - break; - } - } - } - return visitor->VisitExit( *this ); -} - - -// --------- XMLDocument ----------- // - -// Warning: List must match 'enum XMLError' -const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { - "XML_SUCCESS", - "XML_NO_ATTRIBUTE", - "XML_WRONG_ATTRIBUTE_TYPE", - "XML_ERROR_FILE_NOT_FOUND", - "XML_ERROR_FILE_COULD_NOT_BE_OPENED", - "XML_ERROR_FILE_READ_ERROR", - "XML_ERROR_ELEMENT_MISMATCH", - "XML_ERROR_PARSING_ELEMENT", - "XML_ERROR_PARSING_ATTRIBUTE", - "XML_ERROR_IDENTIFYING_TAG", - "XML_ERROR_PARSING_TEXT", - "XML_ERROR_PARSING_CDATA", - "XML_ERROR_PARSING_COMMENT", - "XML_ERROR_PARSING_DECLARATION", - "XML_ERROR_PARSING_UNKNOWN", - "XML_ERROR_EMPTY_DOCUMENT", - "XML_ERROR_MISMATCHED_ELEMENT", - "XML_ERROR_PARSING", - "XML_CAN_NOT_CONVERT_TEXT", - "XML_NO_TEXT_NODE" -}; - - -XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : - XMLNode( 0 ), - _writeBOM( false ), - _processEntities( processEntities ), - _errorID( XML_NO_ERROR ), - _whitespace( whitespace ), - _errorStr1( 0 ), - _errorStr2( 0 ), - _charBuffer( 0 ) -{ - _document = this; // avoid warning about 'this' in initializer list -} - - -XMLDocument::~XMLDocument() -{ - Clear(); -} - - -void XMLDocument::Clear() -{ - DeleteChildren(); - -#ifdef DEBUG - const bool hadError = Error(); -#endif - _errorID = XML_NO_ERROR; - _errorStr1 = 0; - _errorStr2 = 0; - - delete [] _charBuffer; - _charBuffer = 0; - -#if 0 - _textPool.Trace( "text" ); - _elementPool.Trace( "element" ); - _commentPool.Trace( "comment" ); - _attributePool.Trace( "attribute" ); -#endif - -#ifdef DEBUG - if ( !hadError ) { - TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); - TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); - TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); - TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); - } -#endif -} - - -XMLElement* XMLDocument::NewElement( const char* name ) -{ - TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); - XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); - ele->_memPool = &_elementPool; - ele->SetName( name ); - return ele; -} - - -XMLComment* XMLDocument::NewComment( const char* str ) -{ - TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); - XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this ); - comment->_memPool = &_commentPool; - comment->SetValue( str ); - return comment; -} - - -XMLText* XMLDocument::NewText( const char* str ) -{ - TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); - XMLText* text = new (_textPool.Alloc()) XMLText( this ); - text->_memPool = &_textPool; - text->SetValue( str ); - return text; -} - - -XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) -{ - TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); - XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this ); - dec->_memPool = &_commentPool; - dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); - return dec; -} - - -XMLUnknown* XMLDocument::NewUnknown( const char* str ) -{ - TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); - XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this ); - unk->_memPool = &_commentPool; - unk->SetValue( str ); - return unk; -} - -static FILE* callfopen( const char* filepath, const char* mode ) -{ - TIXMLASSERT( filepath ); - TIXMLASSERT( mode ); -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) - FILE* fp = 0; - errno_t err = fopen_s( &fp, filepath, mode ); - if ( err ) { - return 0; - } -#else - FILE* fp = fopen( filepath, mode ); -#endif - return fp; -} - -void XMLDocument::DeleteNode( XMLNode* node ) { - TIXMLASSERT( node ); - TIXMLASSERT(node->_document == this ); - if (node->_parent) { - node->_parent->DeleteChild( node ); - } - else { - // Isn't in the tree. - // Use the parent delete. - // Also, we need to mark it tracked: we 'know' - // it was never used. - node->_memPool->SetTracked(); - // Call the static XMLNode version: - XMLNode::DeleteNode(node); - } -} - - -XMLError XMLDocument::LoadFile( const char* filename ) -{ - Clear(); - FILE* fp = callfopen( filename, "rb" ); - if ( !fp ) { - SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); - return _errorID; - } - LoadFile( fp ); - fclose( fp ); - return _errorID; -} - - -XMLError XMLDocument::LoadFile( FILE* fp ) -{ - Clear(); - - fseek( fp, 0, SEEK_SET ); - if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - - fseek( fp, 0, SEEK_END ); - const long filelength = ftell( fp ); - fseek( fp, 0, SEEK_SET ); - if ( filelength == -1L ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - - const size_t size = filelength; - if ( size == 0 ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return _errorID; - } - - _charBuffer = new char[size+1]; - size_t read = fread( _charBuffer, 1, size, fp ); - if ( read != size ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - - _charBuffer[size] = 0; - - Parse(); - return _errorID; -} - - -XMLError XMLDocument::SaveFile( const char* filename, bool compact ) -{ - FILE* fp = callfopen( filename, "w" ); - if ( !fp ) { - SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); - return _errorID; - } - SaveFile(fp, compact); - fclose( fp ); - return _errorID; -} - - -XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) -{ - XMLPrinter stream( fp, compact ); - Print( &stream ); - return _errorID; -} - - -XMLError XMLDocument::Parse( const char* p, size_t len ) -{ - Clear(); - - if ( len == 0 || !p || !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return _errorID; - } - if ( len == (size_t)(-1) ) { - len = strlen( p ); - } - _charBuffer = new char[ len+1 ]; - memcpy( _charBuffer, p, len ); - _charBuffer[len] = 0; - - Parse(); - if ( Error() ) { - // clean up now essentially dangling memory. - // and the parse fail can put objects in the - // pools that are dead and inaccessible. - DeleteChildren(); - _elementPool.Clear(); - _attributePool.Clear(); - _textPool.Clear(); - _commentPool.Clear(); - } - return _errorID; -} - - -void XMLDocument::Print( XMLPrinter* streamer ) const -{ - XMLPrinter stdStreamer( stdout ); - if ( !streamer ) { - streamer = &stdStreamer; - } - Accept( streamer ); -} - - -void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) -{ - TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); - _errorID = error; - _errorStr1 = str1; - _errorStr2 = str2; -} - -const char* XMLDocument::ErrorName() const -{ - TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); - return _errorNames[_errorID]; -} - -void XMLDocument::PrintError() const -{ - if ( Error() ) { - static const int LEN = 20; - char buf1[LEN] = { 0 }; - char buf2[LEN] = { 0 }; - - if ( _errorStr1 ) { - TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); - } - if ( _errorStr2 ) { - TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); - } - - printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", - _errorID, ErrorName(), buf1, buf2 ); - } -} - -void XMLDocument::Parse() -{ - TIXMLASSERT( NoChildren() ); // Clear() must have been called previously - TIXMLASSERT( _charBuffer ); - char* p = _charBuffer; - p = XMLUtil::SkipWhiteSpace( p ); - p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); - if ( !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return; - } - ParseDeep(p, 0 ); -} - -XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : - _elementJustOpened( false ), - _firstElement( true ), - _fp( file ), - _depth( depth ), - _textDepth( -1 ), - _processEntities( true ), - _compactMode( compact ) -{ - for( int i=0; i'] = true; // not required, but consistency is nice - _buffer.Push( 0 ); -} - - -void XMLPrinter::Print( const char* format, ... ) -{ - va_list va; - va_start( va, format ); - - if ( _fp ) { - vfprintf( _fp, format, va ); - } - else { -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - #if defined(WINCE) - int len = 512; - do { - len = len*2; - char* str = new char[len](); - len = _vsnprintf(str, len, format, va); - delete[] str; - }while (len < 0); - #else - int len = _vscprintf( format, va ); - #endif -#else - int len = vsnprintf( 0, 0, format, va ); -#endif - // Close out and re-start the va-args - va_end( va ); - va_start( va, format ); - TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); - char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - #if defined(WINCE) - _vsnprintf( p, len+1, format, va ); - #else - vsnprintf_s( p, len+1, _TRUNCATE, format, va ); - #endif -#else - vsnprintf( p, len+1, format, va ); -#endif - } - va_end( va ); -} - - -void XMLPrinter::PrintSpace( int depth ) -{ - for( int i=0; i 0 && *q < ENTITY_RANGE ) { - // Check for entities. If one is found, flush - // the stream up until the entity, write the - // entity, and keep looking. - if ( flag[(unsigned char)(*q)] ) { - while ( p < q ) { - Print( "%c", *p ); - ++p; - } - for( int i=0; i 0) ) { - Print( "%s", p ); - } -} - - -void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) -{ - if ( writeBOM ) { - static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; - Print( "%s", bom ); - } - if ( writeDec ) { - PushDeclaration( "xml version=\"1.0\"" ); - } -} - - -void XMLPrinter::OpenElement( const char* name, bool compactMode ) -{ - SealElementIfJustOpened(); - _stack.Push( name ); - - if ( _textDepth < 0 && !_firstElement && !compactMode ) { - Print( "\n" ); - } - if ( !compactMode ) { - PrintSpace( _depth ); - } - - Print( "<%s", name ); - _elementJustOpened = true; - _firstElement = false; - ++_depth; -} - - -void XMLPrinter::PushAttribute( const char* name, const char* value ) -{ - TIXMLASSERT( _elementJustOpened ); - Print( " %s=\"", name ); - PrintString( value, false ); - Print( "\"" ); -} - - -void XMLPrinter::PushAttribute( const char* name, int v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::PushAttribute( const char* name, unsigned v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::PushAttribute( const char* name, bool v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::PushAttribute( const char* name, double v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::CloseElement( bool compactMode ) -{ - --_depth; - const char* name = _stack.Pop(); - - if ( _elementJustOpened ) { - Print( "/>" ); - } - else { - if ( _textDepth < 0 && !compactMode) { - Print( "\n" ); - PrintSpace( _depth ); - } - Print( "", name ); - } - - if ( _textDepth == _depth ) { - _textDepth = -1; - } - if ( _depth == 0 && !compactMode) { - Print( "\n" ); - } - _elementJustOpened = false; -} - - -void XMLPrinter::SealElementIfJustOpened() -{ - if ( !_elementJustOpened ) { - return; - } - _elementJustOpened = false; - Print( ">" ); -} - - -void XMLPrinter::PushText( const char* text, bool cdata ) -{ - _textDepth = _depth-1; - - SealElementIfJustOpened(); - if ( cdata ) { - Print( "" ); - } - else { - PrintString( text, true ); - } -} - -void XMLPrinter::PushText( int value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( unsigned value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( bool value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( float value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( double value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushComment( const char* comment ) -{ - SealElementIfJustOpened(); - if ( _textDepth < 0 && !_firstElement && !_compactMode) { - Print( "\n" ); - PrintSpace( _depth ); - } - _firstElement = false; - Print( "", comment ); -} - - -void XMLPrinter::PushDeclaration( const char* value ) -{ - SealElementIfJustOpened(); - if ( _textDepth < 0 && !_firstElement && !_compactMode) { - Print( "\n" ); - PrintSpace( _depth ); - } - _firstElement = false; - Print( "", value ); -} - - -void XMLPrinter::PushUnknown( const char* value ) -{ - SealElementIfJustOpened(); - if ( _textDepth < 0 && !_firstElement && !_compactMode) { - Print( "\n" ); - PrintSpace( _depth ); - } - _firstElement = false; - Print( "", value ); -} - - -bool XMLPrinter::VisitEnter( const XMLDocument& doc ) -{ - _processEntities = doc.ProcessEntities(); - if ( doc.HasBOM() ) { - PushHeader( true, false ); - } - return true; -} - - -bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) -{ - const XMLElement* parentElem = element.Parent()->ToElement(); - bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode; - OpenElement( element.Name(), compactMode ); - while ( attribute ) { - PushAttribute( attribute->Name(), attribute->Value() ); - attribute = attribute->Next(); - } - return true; -} - - -bool XMLPrinter::VisitExit( const XMLElement& element ) -{ - CloseElement( CompactMode(element) ); - return true; -} - - -bool XMLPrinter::Visit( const XMLText& text ) -{ - PushText( text.Value(), text.CData() ); - return true; -} - - -bool XMLPrinter::Visit( const XMLComment& comment ) -{ - PushComment( comment.Value() ); - return true; -} - -bool XMLPrinter::Visit( const XMLDeclaration& declaration ) -{ - PushDeclaration( declaration.Value() ); - return true; -} - - -bool XMLPrinter::Visit( const XMLUnknown& unknown ) -{ - PushUnknown( unknown.Value() ); - return true; -} - -} // namespace tinyxml2 - diff --git a/internal/tinyxml2-3.0.0/tinyxml2.h b/internal/tinyxml2-3.0.0/tinyxml2.h deleted file mode 100755 index a4769c8..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2.h +++ /dev/null @@ -1,2130 +0,0 @@ -/* -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef TINYXML2_INCLUDED -#define TINYXML2_INCLUDED - -#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) -# include -# include -# include -# include -# include -# include -#else -# include -# include -# include -# include -# include -# include -#endif - -/* - TODO: intern strings instead of allocation. -*/ -/* - gcc: - g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe - - Formatting, Artistic Style: - AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h -*/ - -#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) -# ifndef DEBUG -# define DEBUG -# endif -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif - -#ifdef _WIN32 -# ifdef TINYXML2_EXPORT -# define TINYXML2_LIB __declspec(dllexport) -# elif defined(TINYXML2_IMPORT) -# define TINYXML2_LIB __declspec(dllimport) -# else -# define TINYXML2_LIB -# endif -#else -# define TINYXML2_LIB -#endif - - -#if defined(DEBUG) -# if defined(_MSC_VER) -# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like -# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } //if ( !(x)) WinDebugBreak() -# elif defined (ANDROID_NDK) -# include -# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } -# else -# include -# define TIXMLASSERT assert -# endif -# else -# define TIXMLASSERT( x ) {} -#endif - - -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) -// Microsoft visual studio, version 2005 and higher. -/*int _snprintf_s( - char *buffer, - size_t sizeOfBuffer, - size_t count, - const char *format [, - argument] ... -);*/ -inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) -{ - va_list va; - va_start( va, format ); - int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); - va_end( va ); - return result; -} -#define TIXML_SSCANF sscanf_s -#elif defined WINCE -#define TIXML_SNPRINTF _snprintf -#define TIXML_SSCANF sscanf -#else -// GCC version 3 and higher -//#warning( "Using sn* functions." ) -#define TIXML_SNPRINTF snprintf -#define TIXML_SSCANF sscanf -#endif - -/* Versioning, past 1.0.14: - http://semver.org/ -*/ -static const int TIXML2_MAJOR_VERSION = 3; -static const int TIXML2_MINOR_VERSION = 0; -static const int TIXML2_PATCH_VERSION = 0; - -namespace tinyxml2 -{ -class XMLDocument; -class XMLElement; -class XMLAttribute; -class XMLComment; -class XMLText; -class XMLDeclaration; -class XMLUnknown; -class XMLPrinter; - -/* - A class that wraps strings. Normally stores the start and end - pointers into the XML file itself, and will apply normalization - and entity translation if actually read. Can also store (and memory - manage) a traditional char[] -*/ -class StrPair -{ -public: - enum { - NEEDS_ENTITY_PROCESSING = 0x01, - NEEDS_NEWLINE_NORMALIZATION = 0x02, - COLLAPSE_WHITESPACE = 0x04, - - TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, - TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, - ATTRIBUTE_NAME = 0, - ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, - ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, - COMMENT = NEEDS_NEWLINE_NORMALIZATION - }; - - StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} - ~StrPair(); - - void Set( char* start, char* end, int flags ) { - Reset(); - _start = start; - _end = end; - _flags = flags | NEEDS_FLUSH; - } - - const char* GetStr(); - - bool Empty() const { - return _start == _end; - } - - void SetInternedStr( const char* str ) { - Reset(); - _start = const_cast(str); - } - - void SetStr( const char* str, int flags=0 ); - - char* ParseText( char* in, const char* endTag, int strFlags ); - char* ParseName( char* in ); - - void TransferTo( StrPair* other ); - -private: - void Reset(); - void CollapseWhitespace(); - - enum { - NEEDS_FLUSH = 0x100, - NEEDS_DELETE = 0x200 - }; - - // After parsing, if *_end != 0, it can be set to zero. - int _flags; - char* _start; - char* _end; - - StrPair( const StrPair& other ); // not supported - void operator=( StrPair& other ); // not supported, use TransferTo() -}; - - -/* - A dynamic array of Plain Old Data. Doesn't support constructors, etc. - Has a small initial memory pool, so that low or no usage will not - cause a call to new/delete -*/ -template -class DynArray -{ -public: - DynArray() { - _mem = _pool; - _allocated = INIT; - _size = 0; - } - - ~DynArray() { - if ( _mem != _pool ) { - delete [] _mem; - } - } - - void Clear() { - _size = 0; - } - - void Push( T t ) { - TIXMLASSERT( _size < INT_MAX ); - EnsureCapacity( _size+1 ); - _mem[_size++] = t; - } - - T* PushArr( int count ) { - TIXMLASSERT( count >= 0 ); - TIXMLASSERT( _size <= INT_MAX - count ); - EnsureCapacity( _size+count ); - T* ret = &_mem[_size]; - _size += count; - return ret; - } - - T Pop() { - TIXMLASSERT( _size > 0 ); - return _mem[--_size]; - } - - void PopArr( int count ) { - TIXMLASSERT( _size >= count ); - _size -= count; - } - - bool Empty() const { - return _size == 0; - } - - T& operator[](int i) { - TIXMLASSERT( i>= 0 && i < _size ); - return _mem[i]; - } - - const T& operator[](int i) const { - TIXMLASSERT( i>= 0 && i < _size ); - return _mem[i]; - } - - const T& PeekTop() const { - TIXMLASSERT( _size > 0 ); - return _mem[ _size - 1]; - } - - int Size() const { - TIXMLASSERT( _size >= 0 ); - return _size; - } - - int Capacity() const { - return _allocated; - } - - const T* Mem() const { - return _mem; - } - - T* Mem() { - return _mem; - } - -private: - DynArray( const DynArray& ); // not supported - void operator=( const DynArray& ); // not supported - - void EnsureCapacity( int cap ) { - TIXMLASSERT( cap > 0 ); - if ( cap > _allocated ) { - TIXMLASSERT( cap <= INT_MAX / 2 ); - int newAllocated = cap * 2; - T* newMem = new T[newAllocated]; - memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs - if ( _mem != _pool ) { - delete [] _mem; - } - _mem = newMem; - _allocated = newAllocated; - } - } - - T* _mem; - T _pool[INIT]; - int _allocated; // objects allocated - int _size; // number objects in use -}; - - -/* - Parent virtual class of a pool for fast allocation - and deallocation of objects. -*/ -class MemPool -{ -public: - MemPool() {} - virtual ~MemPool() {} - - virtual int ItemSize() const = 0; - virtual void* Alloc() = 0; - virtual void Free( void* ) = 0; - virtual void SetTracked() = 0; - virtual void Clear() = 0; -}; - - -/* - Template child class to create pools of the correct type. -*/ -template< int SIZE > -class MemPoolT : public MemPool -{ -public: - MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} - ~MemPoolT() { - Clear(); - } - - void Clear() { - // Delete the blocks. - while( !_blockPtrs.Empty()) { - Block* b = _blockPtrs.Pop(); - delete b; - } - _root = 0; - _currentAllocs = 0; - _nAllocs = 0; - _maxAllocs = 0; - _nUntracked = 0; - } - - virtual int ItemSize() const { - return SIZE; - } - int CurrentAllocs() const { - return _currentAllocs; - } - - virtual void* Alloc() { - if ( !_root ) { - // Need a new block. - Block* block = new Block(); - _blockPtrs.Push( block ); - - for( int i=0; ichunk[i].next = &block->chunk[i+1]; - } - block->chunk[COUNT-1].next = 0; - _root = block->chunk; - } - void* result = _root; - _root = _root->next; - - ++_currentAllocs; - if ( _currentAllocs > _maxAllocs ) { - _maxAllocs = _currentAllocs; - } - _nAllocs++; - _nUntracked++; - return result; - } - - virtual void Free( void* mem ) { - if ( !mem ) { - return; - } - --_currentAllocs; - Chunk* chunk = static_cast( mem ); -#ifdef DEBUG - memset( chunk, 0xfe, sizeof(Chunk) ); -#endif - chunk->next = _root; - _root = chunk; - } - void Trace( const char* name ) { - printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", - name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); - } - - void SetTracked() { - _nUntracked--; - } - - int Untracked() const { - return _nUntracked; - } - - // This number is perf sensitive. 4k seems like a good tradeoff on my machine. - // The test file is large, 170k. - // Release: VS2010 gcc(no opt) - // 1k: 4000 - // 2k: 4000 - // 4k: 3900 21000 - // 16k: 5200 - // 32k: 4300 - // 64k: 4000 21000 - enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private - -private: - MemPoolT( const MemPoolT& ); // not supported - void operator=( const MemPoolT& ); // not supported - - union Chunk { - Chunk* next; - char mem[SIZE]; - }; - struct Block { - Chunk chunk[COUNT]; - }; - DynArray< Block*, 10 > _blockPtrs; - Chunk* _root; - - int _currentAllocs; - int _nAllocs; - int _maxAllocs; - int _nUntracked; -}; - - - -/** - Implements the interface to the "Visitor pattern" (see the Accept() method.) - If you call the Accept() method, it requires being passed a XMLVisitor - class to handle callbacks. For nodes that contain other nodes (Document, Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs - are simply called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will continue. If you return - false, no children of this node or its siblings will be visited. - - All flavors of Visit methods have a default implementation that returns 'true' (continue - visiting). You need to only override methods that are interesting to you. - - Generally Accept() is called on the XMLDocument, although all nodes support visiting. - - You should never change the document from a callback. - - @sa XMLNode::Accept() -*/ -class TINYXML2_LIB XMLVisitor -{ -public: - virtual ~XMLVisitor() {} - - /// Visit a document. - virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { - return true; - } - /// Visit a document. - virtual bool VisitExit( const XMLDocument& /*doc*/ ) { - return true; - } - - /// Visit an element. - virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { - return true; - } - /// Visit an element. - virtual bool VisitExit( const XMLElement& /*element*/ ) { - return true; - } - - /// Visit a declaration. - virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { - return true; - } - /// Visit a text node. - virtual bool Visit( const XMLText& /*text*/ ) { - return true; - } - /// Visit a comment node. - virtual bool Visit( const XMLComment& /*comment*/ ) { - return true; - } - /// Visit an unknown node. - virtual bool Visit( const XMLUnknown& /*unknown*/ ) { - return true; - } -}; - -// WARNING: must match XMLDocument::_errorNames[] -enum XMLError { - XML_SUCCESS = 0, - XML_NO_ERROR = 0, - XML_NO_ATTRIBUTE, - XML_WRONG_ATTRIBUTE_TYPE, - XML_ERROR_FILE_NOT_FOUND, - XML_ERROR_FILE_COULD_NOT_BE_OPENED, - XML_ERROR_FILE_READ_ERROR, - XML_ERROR_ELEMENT_MISMATCH, - XML_ERROR_PARSING_ELEMENT, - XML_ERROR_PARSING_ATTRIBUTE, - XML_ERROR_IDENTIFYING_TAG, - XML_ERROR_PARSING_TEXT, - XML_ERROR_PARSING_CDATA, - XML_ERROR_PARSING_COMMENT, - XML_ERROR_PARSING_DECLARATION, - XML_ERROR_PARSING_UNKNOWN, - XML_ERROR_EMPTY_DOCUMENT, - XML_ERROR_MISMATCHED_ELEMENT, - XML_ERROR_PARSING, - XML_CAN_NOT_CONVERT_TEXT, - XML_NO_TEXT_NODE, - - XML_ERROR_COUNT -}; - - -/* - Utility functionality. -*/ -class XMLUtil -{ -public: - static const char* SkipWhiteSpace( const char* p ) { - TIXMLASSERT( p ); - while( IsWhiteSpace(*p) ) { - ++p; - } - TIXMLASSERT( p ); - return p; - } - static char* SkipWhiteSpace( char* p ) { - return const_cast( SkipWhiteSpace( const_cast(p) ) ); - } - - // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't - // correct, but simple, and usually works. - static bool IsWhiteSpace( char p ) { - return !IsUTF8Continuation(p) && isspace( static_cast(p) ); - } - - inline static bool IsNameStartChar( unsigned char ch ) { - if ( ch >= 128 ) { - // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() - return true; - } - if ( isalpha( ch ) ) { - return true; - } - return ch == ':' || ch == '_'; - } - - inline static bool IsNameChar( unsigned char ch ) { - return IsNameStartChar( ch ) - || isdigit( ch ) - || ch == '.' - || ch == '-'; - } - - inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { - if ( p == q ) { - return true; - } - int n = 0; - while( *p && *q && *p == *q && n(const_cast(this)->FirstChildElement( value )); - } - - /// Get the last child node, or null if none exists. - const XMLNode* LastChild() const { - return _lastChild; - } - - XMLNode* LastChild() { - return const_cast(const_cast(this)->LastChild() ); - } - - /** Get the last child element or optionally the last child - element with the specified name. - */ - const XMLElement* LastChildElement( const char* value=0 ) const; - - XMLElement* LastChildElement( const char* value=0 ) { - return const_cast(const_cast(this)->LastChildElement(value) ); - } - - /// Get the previous (left) sibling node of this node. - const XMLNode* PreviousSibling() const { - return _prev; - } - - XMLNode* PreviousSibling() { - return _prev; - } - - /// Get the previous (left) sibling element of this node, with an optionally supplied name. - const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; - - XMLElement* PreviousSiblingElement( const char* value=0 ) { - return const_cast(const_cast(this)->PreviousSiblingElement( value ) ); - } - - /// Get the next (right) sibling node of this node. - const XMLNode* NextSibling() const { - return _next; - } - - XMLNode* NextSibling() { - return _next; - } - - /// Get the next (right) sibling element of this node, with an optionally supplied name. - const XMLElement* NextSiblingElement( const char* value=0 ) const; - - XMLElement* NextSiblingElement( const char* value=0 ) { - return const_cast(const_cast(this)->NextSiblingElement( value ) ); - } - - /** - Add a child node as the last (right) child. - If the child node is already part of the document, - it is moved from its old location to the new location. - Returns the addThis argument or 0 if the node does not - belong to the same document. - */ - XMLNode* InsertEndChild( XMLNode* addThis ); - - XMLNode* LinkEndChild( XMLNode* addThis ) { - return InsertEndChild( addThis ); - } - /** - Add a child node as the first (left) child. - If the child node is already part of the document, - it is moved from its old location to the new location. - Returns the addThis argument or 0 if the node does not - belong to the same document. - */ - XMLNode* InsertFirstChild( XMLNode* addThis ); - /** - Add a node after the specified child node. - If the child node is already part of the document, - it is moved from its old location to the new location. - Returns the addThis argument or 0 if the afterThis node - is not a child of this node, or if the node does not - belong to the same document. - */ - XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); - - /** - Delete all the children of this node. - */ - void DeleteChildren(); - - /** - Delete a child of this node. - */ - void DeleteChild( XMLNode* node ); - - /** - Make a copy of this node, but not its children. - You may pass in a Document pointer that will be - the owner of the new Node. If the 'document' is - null, then the node returned will be allocated - from the current Document. (this->GetDocument()) - - Note: if called on a XMLDocument, this will return null. - */ - virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; - - /** - Test if 2 nodes are the same, but don't test children. - The 2 nodes do not need to be in the same Document. - - Note: if called on a XMLDocument, this will return false. - */ - virtual bool ShallowEqual( const XMLNode* compare ) const = 0; - - /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the - XML tree will be conditionally visited and the host will be called back - via the XMLVisitor interface. - - This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse - the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - XMLPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept( XMLVisitor* visitor ) const = 0; - - // internal - virtual char* ParseDeep( char*, StrPair* ); - -protected: - XMLNode( XMLDocument* ); - virtual ~XMLNode(); - - XMLDocument* _document; - XMLNode* _parent; - mutable StrPair _value; - - XMLNode* _firstChild; - XMLNode* _lastChild; - - XMLNode* _prev; - XMLNode* _next; - -private: - MemPool* _memPool; - void Unlink( XMLNode* child ); - static void DeleteNode( XMLNode* node ); - void InsertChildPreamble( XMLNode* insertThis ) const; - - XMLNode( const XMLNode& ); // not supported - XMLNode& operator=( const XMLNode& ); // not supported -}; - - -/** XML text. - - Note that a text node can have child element nodes, for example: - @verbatim - This is bold - @endverbatim - - A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file and - you generally want to leave it alone, but you can change the output mode with - SetCData() and query it with CData(). -*/ -class TINYXML2_LIB XMLText : public XMLNode -{ - friend class XMLBase; - friend class XMLDocument; -public: - virtual bool Accept( XMLVisitor* visitor ) const; - - virtual XMLText* ToText() { - return this; - } - virtual const XMLText* ToText() const { - return this; - } - - /// Declare whether this should be CDATA or standard text. - void SetCData( bool isCData ) { - _isCData = isCData; - } - /// Returns true if this is a CDATA text element. - bool CData() const { - return _isCData; - } - - char* ParseDeep( char*, StrPair* endTag ); - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; - -protected: - XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} - virtual ~XMLText() {} - -private: - bool _isCData; - - XMLText( const XMLText& ); // not supported - XMLText& operator=( const XMLText& ); // not supported -}; - - -/** An XML Comment. */ -class TINYXML2_LIB XMLComment : public XMLNode -{ - friend class XMLDocument; -public: - virtual XMLComment* ToComment() { - return this; - } - virtual const XMLComment* ToComment() const { - return this; - } - - virtual bool Accept( XMLVisitor* visitor ) const; - - char* ParseDeep( char*, StrPair* endTag ); - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; - -protected: - XMLComment( XMLDocument* doc ); - virtual ~XMLComment(); - -private: - XMLComment( const XMLComment& ); // not supported - XMLComment& operator=( const XMLComment& ); // not supported -}; - - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXML-2 will happily read or write files without a declaration, - however. - - The text of the declaration isn't interpreted. It is parsed - and written as a string. -*/ -class TINYXML2_LIB XMLDeclaration : public XMLNode -{ - friend class XMLDocument; -public: - virtual XMLDeclaration* ToDeclaration() { - return this; - } - virtual const XMLDeclaration* ToDeclaration() const { - return this; - } - - virtual bool Accept( XMLVisitor* visitor ) const; - - char* ParseDeep( char*, StrPair* endTag ); - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; - -protected: - XMLDeclaration( XMLDocument* doc ); - virtual ~XMLDeclaration(); - -private: - XMLDeclaration( const XMLDeclaration& ); // not supported - XMLDeclaration& operator=( const XMLDeclaration& ); // not supported -}; - - -/** Any tag that TinyXML-2 doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into XMLUnknowns. -*/ -class TINYXML2_LIB XMLUnknown : public XMLNode -{ - friend class XMLDocument; -public: - virtual XMLUnknown* ToUnknown() { - return this; - } - virtual const XMLUnknown* ToUnknown() const { - return this; - } - - virtual bool Accept( XMLVisitor* visitor ) const; - - char* ParseDeep( char*, StrPair* endTag ); - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; - -protected: - XMLUnknown( XMLDocument* doc ); - virtual ~XMLUnknown(); - -private: - XMLUnknown( const XMLUnknown& ); // not supported - XMLUnknown& operator=( const XMLUnknown& ); // not supported -}; - - - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not XMLNodes. You may only query the - Next() attribute in a list. -*/ -class TINYXML2_LIB XMLAttribute -{ - friend class XMLElement; -public: - /// The name of the attribute. - const char* Name() const; - - /// The value of the attribute. - const char* Value() const; - - /// The next attribute in the list. - const XMLAttribute* Next() const { - return _next; - } - - /** IntValue interprets the attribute as an integer, and returns the value. - If the value isn't an integer, 0 will be returned. There is no error checking; - use QueryIntValue() if you need error checking. - */ - int IntValue() const { - int i=0; - QueryIntValue( &i ); - return i; - } - /// Query as an unsigned integer. See IntValue() - unsigned UnsignedValue() const { - unsigned i=0; - QueryUnsignedValue( &i ); - return i; - } - /// Query as a boolean. See IntValue() - bool BoolValue() const { - bool b=false; - QueryBoolValue( &b ); - return b; - } - /// Query as a double. See IntValue() - double DoubleValue() const { - double d=0; - QueryDoubleValue( &d ); - return d; - } - /// Query as a float. See IntValue() - float FloatValue() const { - float f=0; - QueryFloatValue( &f ); - return f; - } - - /** QueryIntValue interprets the attribute as an integer, and returns the value - in the provided parameter. The function will return XML_NO_ERROR on success, - and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. - */ - XMLError QueryIntValue( int* value ) const; - /// See QueryIntValue - XMLError QueryUnsignedValue( unsigned int* value ) const; - /// See QueryIntValue - XMLError QueryBoolValue( bool* value ) const; - /// See QueryIntValue - XMLError QueryDoubleValue( double* value ) const; - /// See QueryIntValue - XMLError QueryFloatValue( float* value ) const; - - /// Set the attribute to a string value. - void SetAttribute( const char* value ); - /// Set the attribute to value. - void SetAttribute( int value ); - /// Set the attribute to value. - void SetAttribute( unsigned value ); - /// Set the attribute to value. - void SetAttribute( bool value ); - /// Set the attribute to value. - void SetAttribute( double value ); - /// Set the attribute to value. - void SetAttribute( float value ); - -private: - enum { BUF_SIZE = 200 }; - - XMLAttribute() : _next( 0 ), _memPool( 0 ) {} - virtual ~XMLAttribute() {} - - XMLAttribute( const XMLAttribute& ); // not supported - void operator=( const XMLAttribute& ); // not supported - void SetName( const char* name ); - - char* ParseDeep( char* p, bool processEntities ); - - mutable StrPair _name; - mutable StrPair _value; - XMLAttribute* _next; - MemPool* _memPool; -}; - - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TINYXML2_LIB XMLElement : public XMLNode -{ - friend class XMLBase; - friend class XMLDocument; -public: - /// Get the name of an element (which is the Value() of the node.) - const char* Name() const { - return Value(); - } - /// Set the name of the element. - void SetName( const char* str, bool staticMem=false ) { - SetValue( str, staticMem ); - } - - virtual XMLElement* ToElement() { - return this; - } - virtual const XMLElement* ToElement() const { - return this; - } - virtual bool Accept( XMLVisitor* visitor ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none - exists. For example: - - @verbatim - const char* value = ele->Attribute( "foo" ); - @endverbatim - - The 'value' parameter is normally null. However, if specified, - the attribute will only be returned if the 'name' and 'value' - match. This allow you to write code: - - @verbatim - if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); - @endverbatim - - rather than: - @verbatim - if ( ele->Attribute( "foo" ) ) { - if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); - } - @endverbatim - */ - const char* Attribute( const char* name, const char* value=0 ) const; - - /** Given an attribute name, IntAttribute() returns the value - of the attribute interpreted as an integer. 0 will be - returned if there is an error. For a method with error - checking, see QueryIntAttribute() - */ - int IntAttribute( const char* name ) const { - int i=0; - QueryIntAttribute( name, &i ); - return i; - } - /// See IntAttribute() - unsigned UnsignedAttribute( const char* name ) const { - unsigned i=0; - QueryUnsignedAttribute( name, &i ); - return i; - } - /// See IntAttribute() - bool BoolAttribute( const char* name ) const { - bool b=false; - QueryBoolAttribute( name, &b ); - return b; - } - /// See IntAttribute() - double DoubleAttribute( const char* name ) const { - double d=0; - QueryDoubleAttribute( name, &d ); - return d; - } - /// See IntAttribute() - float FloatAttribute( const char* name ) const { - float f=0; - QueryFloatAttribute( name, &f ); - return f; - } - - /** Given an attribute name, QueryIntAttribute() returns - XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion - can't be performed, or XML_NO_ATTRIBUTE if the attribute - doesn't exist. If successful, the result of the conversion - will be written to 'value'. If not successful, nothing will - be written to 'value'. This allows you to provide default - value: - - @verbatim - int value = 10; - QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 - @endverbatim - */ - XMLError QueryIntAttribute( const char* name, int* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryIntValue( value ); - } - /// See QueryIntAttribute() - XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryUnsignedValue( value ); - } - /// See QueryIntAttribute() - XMLError QueryBoolAttribute( const char* name, bool* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryBoolValue( value ); - } - /// See QueryIntAttribute() - XMLError QueryDoubleAttribute( const char* name, double* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryDoubleValue( value ); - } - /// See QueryIntAttribute() - XMLError QueryFloatAttribute( const char* name, float* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryFloatValue( value ); - } - - - /** Given an attribute name, QueryAttribute() returns - XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion - can't be performed, or XML_NO_ATTRIBUTE if the attribute - doesn't exist. It is overloaded for the primitive types, - and is a generally more convenient replacement of - QueryIntAttribute() and related functions. - - If successful, the result of the conversion - will be written to 'value'. If not successful, nothing will - be written to 'value'. This allows you to provide default - value: - - @verbatim - int value = 10; - QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 - @endverbatim - */ - int QueryAttribute( const char* name, int* value ) const { - return QueryIntAttribute( name, value ); - } - - int QueryAttribute( const char* name, unsigned int* value ) const { - return QueryUnsignedAttribute( name, value ); - } - - int QueryAttribute( const char* name, bool* value ) const { - return QueryBoolAttribute( name, value ); - } - - int QueryAttribute( const char* name, double* value ) const { - return QueryDoubleAttribute( name, value ); - } - - int QueryAttribute( const char* name, float* value ) const { - return QueryFloatAttribute( name, value ); - } - - /// Sets the named attribute to value. - void SetAttribute( const char* name, const char* value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, int value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, unsigned value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, bool value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, double value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, float value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - - /** - Delete an attribute. - */ - void DeleteAttribute( const char* name ); - - /// Return the first attribute in the list. - const XMLAttribute* FirstAttribute() const { - return _rootAttribute; - } - /// Query a specific attribute in the list. - const XMLAttribute* FindAttribute( const char* name ) const; - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, GetText() is limited compared to getting the XMLText child - and accessing it directly. - - If the first child of 'this' is a XMLText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - */ - const char* GetText() const; - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, SetText() is limited compared to creating an XMLText child - and mutating it directly. - - If the first child of 'this' is a XMLText, SetText() sets its value to - the given string, otherwise it will create a first child that is an XMLText. - - This is a convenient method for setting the text of simple contained text: - @verbatim - This is text - fooElement->SetText( "Hullaballoo!" ); - Hullaballoo! - @endverbatim - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then it will not change "This is text", but rather prefix it with a text element: - @verbatim - Hullaballoo!This is text - @endverbatim - - For this XML: - @verbatim - - @endverbatim - SetText() will generate - @verbatim - Hullaballoo! - @endverbatim - */ - void SetText( const char* inText ); - /// Convenience method for setting text inside and element. See SetText() for important limitations. - void SetText( int value ); - /// Convenience method for setting text inside and element. See SetText() for important limitations. - void SetText( unsigned value ); - /// Convenience method for setting text inside and element. See SetText() for important limitations. - void SetText( bool value ); - /// Convenience method for setting text inside and element. See SetText() for important limitations. - void SetText( double value ); - /// Convenience method for setting text inside and element. See SetText() for important limitations. - void SetText( float value ); - - /** - Convenience method to query the value of a child text node. This is probably best - shown by example. Given you have a document is this form: - @verbatim - - 1 - 1.4 - - @endverbatim - - The QueryIntText() and similar functions provide a safe and easier way to get to the - "value" of x and y. - - @verbatim - int x = 0; - float y = 0; // types of x and y are contrived for example - const XMLElement* xElement = pointElement->FirstChildElement( "x" ); - const XMLElement* yElement = pointElement->FirstChildElement( "y" ); - xElement->QueryIntText( &x ); - yElement->QueryFloatText( &y ); - @endverbatim - - @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted - to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. - - */ - XMLError QueryIntText( int* ival ) const; - /// See QueryIntText() - XMLError QueryUnsignedText( unsigned* uval ) const; - /// See QueryIntText() - XMLError QueryBoolText( bool* bval ) const; - /// See QueryIntText() - XMLError QueryDoubleText( double* dval ) const; - /// See QueryIntText() - XMLError QueryFloatText( float* fval ) const; - - // internal: - enum { - OPEN, // - CLOSED, // - CLOSING // - }; - int ClosingType() const { - return _closingType; - } - char* ParseDeep( char* p, StrPair* endTag ); - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; - -private: - XMLElement( XMLDocument* doc ); - virtual ~XMLElement(); - XMLElement( const XMLElement& ); // not supported - void operator=( const XMLElement& ); // not supported - - XMLAttribute* FindAttribute( const char* name ) { - return const_cast(const_cast(this)->FindAttribute( name )); - } - XMLAttribute* FindOrCreateAttribute( const char* name ); - //void LinkAttribute( XMLAttribute* attrib ); - char* ParseAttributes( char* p ); - static void DeleteAttribute( XMLAttribute* attribute ); - - enum { BUF_SIZE = 200 }; - int _closingType; - // The attribute list is ordered; there is no 'lastAttribute' - // because the list needs to be scanned for dupes before adding - // a new attribute. - XMLAttribute* _rootAttribute; -}; - - -enum Whitespace { - PRESERVE_WHITESPACE, - COLLAPSE_WHITESPACE -}; - - -/** A Document binds together all the functionality. - It can be saved, loaded, and printed to the screen. - All Nodes are connected and allocated to a Document. - If the Document is deleted, all its Nodes are also deleted. -*/ -class TINYXML2_LIB XMLDocument : public XMLNode -{ - friend class XMLElement; -public: - /// constructor - XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); - ~XMLDocument(); - - virtual XMLDocument* ToDocument() { - return this; - } - virtual const XMLDocument* ToDocument() const { - return this; - } - - /** - Parse an XML file from a character string. - Returns XML_NO_ERROR (0) on success, or - an errorID. - - You may optionally pass in the 'nBytes', which is - the number of bytes which will be parsed. If not - specified, TinyXML-2 will assume 'xml' points to a - null terminated string. - */ - XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); - - /** - Load an XML file from disk. - Returns XML_NO_ERROR (0) on success, or - an errorID. - */ - XMLError LoadFile( const char* filename ); - - /** - Load an XML file from disk. You are responsible - for providing and closing the FILE*. - - NOTE: The file should be opened as binary ("rb") - not text in order for TinyXML-2 to correctly - do newline normalization. - - Returns XML_NO_ERROR (0) on success, or - an errorID. - */ - XMLError LoadFile( FILE* ); - - /** - Save the XML file to disk. - Returns XML_NO_ERROR (0) on success, or - an errorID. - */ - XMLError SaveFile( const char* filename, bool compact = false ); - - /** - Save the XML file to disk. You are responsible - for providing and closing the FILE*. - - Returns XML_NO_ERROR (0) on success, or - an errorID. - */ - XMLError SaveFile( FILE* fp, bool compact = false ); - - bool ProcessEntities() const { - return _processEntities; - } - Whitespace WhitespaceMode() const { - return _whitespace; - } - - /** - Returns true if this document has a leading Byte Order Mark of UTF8. - */ - bool HasBOM() const { - return _writeBOM; - } - /** Sets whether to write the BOM when writing the file. - */ - void SetBOM( bool useBOM ) { - _writeBOM = useBOM; - } - - /** Return the root element of DOM. Equivalent to FirstChildElement(). - To get the first node, use FirstChild(). - */ - XMLElement* RootElement() { - return FirstChildElement(); - } - const XMLElement* RootElement() const { - return FirstChildElement(); - } - - /** Print the Document. If the Printer is not provided, it will - print to stdout. If you provide Printer, this can print to a file: - @verbatim - XMLPrinter printer( fp ); - doc.Print( &printer ); - @endverbatim - - Or you can use a printer to print to memory: - @verbatim - XMLPrinter printer; - doc.Print( &printer ); - // printer.CStr() has a const char* to the XML - @endverbatim - */ - void Print( XMLPrinter* streamer=0 ) const; - virtual bool Accept( XMLVisitor* visitor ) const; - - /** - Create a new Element associated with - this Document. The memory for the Element - is managed by the Document. - */ - XMLElement* NewElement( const char* name ); - /** - Create a new Comment associated with - this Document. The memory for the Comment - is managed by the Document. - */ - XMLComment* NewComment( const char* comment ); - /** - Create a new Text associated with - this Document. The memory for the Text - is managed by the Document. - */ - XMLText* NewText( const char* text ); - /** - Create a new Declaration associated with - this Document. The memory for the object - is managed by the Document. - - If the 'text' param is null, the standard - declaration is used.: - @verbatim - - @endverbatim - */ - XMLDeclaration* NewDeclaration( const char* text=0 ); - /** - Create a new Unknown associated with - this Document. The memory for the object - is managed by the Document. - */ - XMLUnknown* NewUnknown( const char* text ); - - /** - Delete a node associated with this document. - It will be unlinked from the DOM. - */ - void DeleteNode( XMLNode* node ); - - void SetError( XMLError error, const char* str1, const char* str2 ); - - /// Return true if there was an error parsing the document. - bool Error() const { - return _errorID != XML_NO_ERROR; - } - /// Return the errorID. - XMLError ErrorID() const { - return _errorID; - } - const char* ErrorName() const; - - /// Return a possibly helpful diagnostic location or string. - const char* GetErrorStr1() const { - return _errorStr1; - } - /// Return a possibly helpful secondary diagnostic location or string. - const char* GetErrorStr2() const { - return _errorStr2; - } - /// If there is an error, print it to stdout. - void PrintError() const; - - /// Clear the document, resetting it to the initial state. - void Clear(); - - // internal - char* Identify( char* p, XMLNode** node ); - - virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { - return 0; - } - virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { - return false; - } - -private: - XMLDocument( const XMLDocument& ); // not supported - void operator=( const XMLDocument& ); // not supported - - bool _writeBOM; - bool _processEntities; - XMLError _errorID; - Whitespace _whitespace; - const char* _errorStr1; - const char* _errorStr2; - char* _charBuffer; - - MemPoolT< sizeof(XMLElement) > _elementPool; - MemPoolT< sizeof(XMLAttribute) > _attributePool; - MemPoolT< sizeof(XMLText) > _textPool; - MemPoolT< sizeof(XMLComment) > _commentPool; - - static const char* _errorNames[XML_ERROR_COUNT]; - - void Parse(); -}; - - -/** - A XMLHandle is a class that wraps a node pointer with null checks; this is - an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very - easy to write a *lot* of code that looks like: - - @verbatim - XMLElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - XMLElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - XMLElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - XMLElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. XMLHandle addresses the verbosity - of such code. A XMLHandle checks for null pointers so it is perfectly safe - and correct to use: - - @verbatim - XMLHandle docHandle( &document ); - XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than node pointers. - @verbatim - XMLHandle handleCopy = handle; - @endverbatim - - See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. -*/ -class TINYXML2_LIB XMLHandle -{ -public: - /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - XMLHandle( XMLNode* node ) { - _node = node; - } - /// Create a handle from a node. - XMLHandle( XMLNode& node ) { - _node = &node; - } - /// Copy constructor - XMLHandle( const XMLHandle& ref ) { - _node = ref._node; - } - /// Assignment - XMLHandle& operator=( const XMLHandle& ref ) { - _node = ref._node; - return *this; - } - - /// Get the first child of this handle. - XMLHandle FirstChild() { - return XMLHandle( _node ? _node->FirstChild() : 0 ); - } - /// Get the first child element of this handle. - XMLHandle FirstChildElement( const char* value=0 ) { - return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 ); - } - /// Get the last child of this handle. - XMLHandle LastChild() { - return XMLHandle( _node ? _node->LastChild() : 0 ); - } - /// Get the last child element of this handle. - XMLHandle LastChildElement( const char* _value=0 ) { - return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 ); - } - /// Get the previous sibling of this handle. - XMLHandle PreviousSibling() { - return XMLHandle( _node ? _node->PreviousSibling() : 0 ); - } - /// Get the previous sibling element of this handle. - XMLHandle PreviousSiblingElement( const char* _value=0 ) { - return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); - } - /// Get the next sibling of this handle. - XMLHandle NextSibling() { - return XMLHandle( _node ? _node->NextSibling() : 0 ); - } - /// Get the next sibling element of this handle. - XMLHandle NextSiblingElement( const char* _value=0 ) { - return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); - } - - /// Safe cast to XMLNode. This can return null. - XMLNode* ToNode() { - return _node; - } - /// Safe cast to XMLElement. This can return null. - XMLElement* ToElement() { - return ( ( _node == 0 ) ? 0 : _node->ToElement() ); - } - /// Safe cast to XMLText. This can return null. - XMLText* ToText() { - return ( ( _node == 0 ) ? 0 : _node->ToText() ); - } - /// Safe cast to XMLUnknown. This can return null. - XMLUnknown* ToUnknown() { - return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); - } - /// Safe cast to XMLDeclaration. This can return null. - XMLDeclaration* ToDeclaration() { - return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); - } - -private: - XMLNode* _node; -}; - - -/** - A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the - same in all regards, except for the 'const' qualifiers. See XMLHandle for API. -*/ -class TINYXML2_LIB XMLConstHandle -{ -public: - XMLConstHandle( const XMLNode* node ) { - _node = node; - } - XMLConstHandle( const XMLNode& node ) { - _node = &node; - } - XMLConstHandle( const XMLConstHandle& ref ) { - _node = ref._node; - } - - XMLConstHandle& operator=( const XMLConstHandle& ref ) { - _node = ref._node; - return *this; - } - - const XMLConstHandle FirstChild() const { - return XMLConstHandle( _node ? _node->FirstChild() : 0 ); - } - const XMLConstHandle FirstChildElement( const char* value=0 ) const { - return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 ); - } - const XMLConstHandle LastChild() const { - return XMLConstHandle( _node ? _node->LastChild() : 0 ); - } - const XMLConstHandle LastChildElement( const char* _value=0 ) const { - return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 ); - } - const XMLConstHandle PreviousSibling() const { - return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); - } - const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { - return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); - } - const XMLConstHandle NextSibling() const { - return XMLConstHandle( _node ? _node->NextSibling() : 0 ); - } - const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { - return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); - } - - - const XMLNode* ToNode() const { - return _node; - } - const XMLElement* ToElement() const { - return ( ( _node == 0 ) ? 0 : _node->ToElement() ); - } - const XMLText* ToText() const { - return ( ( _node == 0 ) ? 0 : _node->ToText() ); - } - const XMLUnknown* ToUnknown() const { - return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); - } - const XMLDeclaration* ToDeclaration() const { - return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); - } - -private: - const XMLNode* _node; -}; - - -/** - Printing functionality. The XMLPrinter gives you more - options than the XMLDocument::Print() method. - - It can: - -# Print to memory. - -# Print to a file you provide. - -# Print XML without a XMLDocument. - - Print to Memory - - @verbatim - XMLPrinter printer; - doc.Print( &printer ); - SomeFunction( printer.CStr() ); - @endverbatim - - Print to a File - - You provide the file pointer. - @verbatim - XMLPrinter printer( fp ); - doc.Print( &printer ); - @endverbatim - - Print without a XMLDocument - - When loading, an XML parser is very useful. However, sometimes - when saving, it just gets in the way. The code is often set up - for streaming, and constructing the DOM is just overhead. - - The Printer supports the streaming case. The following code - prints out a trivially simple XML file without ever creating - an XML document. - - @verbatim - XMLPrinter printer( fp ); - printer.OpenElement( "foo" ); - printer.PushAttribute( "foo", "bar" ); - printer.CloseElement(); - @endverbatim -*/ -class TINYXML2_LIB XMLPrinter : public XMLVisitor -{ -public: - /** Construct the printer. If the FILE* is specified, - this will print to the FILE. Else it will print - to memory, and the result is available in CStr(). - If 'compact' is set to true, then output is created - with only required whitespace and newlines. - */ - XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); - virtual ~XMLPrinter() {} - - /** If streaming, write the BOM and declaration. */ - void PushHeader( bool writeBOM, bool writeDeclaration ); - /** If streaming, start writing an element. - The element must be closed with CloseElement() - */ - void OpenElement( const char* name, bool compactMode=false ); - /// If streaming, add an attribute to an open element. - void PushAttribute( const char* name, const char* value ); - void PushAttribute( const char* name, int value ); - void PushAttribute( const char* name, unsigned value ); - void PushAttribute( const char* name, bool value ); - void PushAttribute( const char* name, double value ); - /// If streaming, close the Element. - virtual void CloseElement( bool compactMode=false ); - - /// Add a text node. - void PushText( const char* text, bool cdata=false ); - /// Add a text node from an integer. - void PushText( int value ); - /// Add a text node from an unsigned. - void PushText( unsigned value ); - /// Add a text node from a bool. - void PushText( bool value ); - /// Add a text node from a float. - void PushText( float value ); - /// Add a text node from a double. - void PushText( double value ); - - /// Add a comment - void PushComment( const char* comment ); - - void PushDeclaration( const char* value ); - void PushUnknown( const char* value ); - - virtual bool VisitEnter( const XMLDocument& /*doc*/ ); - virtual bool VisitExit( const XMLDocument& /*doc*/ ) { - return true; - } - - virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); - virtual bool VisitExit( const XMLElement& element ); - - virtual bool Visit( const XMLText& text ); - virtual bool Visit( const XMLComment& comment ); - virtual bool Visit( const XMLDeclaration& declaration ); - virtual bool Visit( const XMLUnknown& unknown ); - - /** - If in print to memory mode, return a pointer to - the XML file in memory. - */ - const char* CStr() const { - return _buffer.Mem(); - } - /** - If in print to memory mode, return the size - of the XML file in memory. (Note the size returned - includes the terminating null.) - */ - int CStrSize() const { - return _buffer.Size(); - } - /** - If in print to memory mode, reset the buffer to the - beginning. - */ - void ClearBuffer() { - _buffer.Clear(); - _buffer.Push(0); - } - -protected: - virtual bool CompactMode( const XMLElement& ) { return _compactMode; } - - /** Prints out the space before an element. You may override to change - the space and tabs used. A PrintSpace() override should call Print(). - */ - virtual void PrintSpace( int depth ); - void Print( const char* format, ... ); - - void SealElementIfJustOpened(); - bool _elementJustOpened; - DynArray< const char*, 10 > _stack; - -private: - void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. - - bool _firstElement; - FILE* _fp; - int _depth; - int _textDepth; - bool _processEntities; - bool _compactMode; - - enum { - ENTITY_RANGE = 64, - BUF_SIZE = 200 - }; - bool _entityFlag[ENTITY_RANGE]; - bool _restrictedEntityFlag[ENTITY_RANGE]; - - DynArray< char, 20 > _buffer; -}; - - -} // tinyxml2 - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif // TINYXML2_INCLUDED diff --git a/internal/tinyxml2-3.0.0/tinyxml2.pc.in b/internal/tinyxml2-3.0.0/tinyxml2.pc.in deleted file mode 100644 index 5a44e89..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=@CMAKE_INSTALL_LIBDIR@ -includedir=@CMAKE_INSTALL_INCLUDEDIR@ - -Name: TinyXML2 -Description: simple, small, C++ XML parser -Version: @GENERIC_LIB_VERSION@ -Libs: -L${libdir} -ltinyxml2 -Cflags: -I${includedir} diff --git a/internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj b/internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj deleted file mode 100644 index 0f04034..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj +++ /dev/null @@ -1,347 +0,0 @@ - - - - - Debug-Dll - Win32 - - - Debug-Dll - x64 - - - Debug-Lib - Win32 - - - Debug-Lib - x64 - - - Release-Dll - Win32 - - - Release-Dll - x64 - - - Release-Lib - Win32 - - - Release-Lib - x64 - - - - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260} - test - - - - Application - true - Unicode - - - Application - true - Unicode - - - Application - true - Unicode - - - Application - true - Unicode - - - Application - false - true - Unicode - - - Application - false - true - Unicode - - - Application - false - true - Unicode - - - Application - false - true - Unicode - - - Unicode - - - Unicode - true - - - Unicode - - - Unicode - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - - - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - - Level4 - Disabled - - - true - - - - - Level4 - Disabled - - - true - - - - - Level4 - Disabled - TINYXML2_IMPORT;%(PreprocessorDefinitions) - - - true - Console - - - - - Level4 - Disabled - TINYXML2_IMPORT;%(PreprocessorDefinitions) - - - true - Console - - - - - Level4 - MaxSpeed - true - true - - - true - true - true - - - - - Level4 - MaxSpeed - true - true - - - true - true - true - - - - - Level4 - MaxSpeed - true - true - AnySuitable - Speed - true - true - true - TINYXML2_IMPORT;%(PreprocessorDefinitions) - - - false - true - true - Console - true - - - - - Level4 - MaxSpeed - true - true - AnySuitable - Speed - true - true - true - TINYXML2_IMPORT;%(PreprocessorDefinitions) - - - false - true - true - Console - true - - - - - Level4 - - - Console - - - - - Level4 - AnySuitable - true - Speed - true - true - true - - - false - Console - true - true - true - - - - - Level4 - - - Console - - - - - Level4 - AnySuitable - true - Speed - true - true - true - - - false - Console - true - true - true - - - - - - - - {d1c528b6-aa02-4d29-9d61-dc08e317a70d} - - - - - - \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj.filters b/internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj.filters deleted file mode 100644 index 271c2cf..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/test.vcxproj.filters +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/README b/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/README deleted file mode 100644 index 828448e..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/README +++ /dev/null @@ -1,3 +0,0 @@ -The (default) Release configuration of this project builds a ready to use static library. -The Debug configuration of this project builds an executable console application that -executes all tests provided for tinyxml2 in the xmltest.cpp file. \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp b/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp deleted file mode 100644 index 915746f..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - diff --git a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.sln b/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.sln deleted file mode 100755 index b91b0fe..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.sln +++ /dev/null @@ -1,56 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyxml2", "tinyxml2.vcxproj", "{D1C528B6-AA02-4D29-9D61-DC08E317A70D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{E8FB2712-8666-4662-A5B8-2B5B0FB1A260}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug-Dll|Win32 = Debug-Dll|Win32 - Debug-Dll|x64 = Debug-Dll|x64 - Debug-Lib|Win32 = Debug-Lib|Win32 - Debug-Lib|x64 = Debug-Lib|x64 - Release-Dll|Win32 = Release-Dll|Win32 - Release-Dll|x64 = Release-Dll|x64 - Release-Lib|Win32 = Release-Lib|Win32 - Release-Lib|x64 = Release-Lib|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Dll|Win32.ActiveCfg = Debug-Dll|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Dll|Win32.Build.0 = Debug-Dll|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Dll|x64.ActiveCfg = Debug-Dll|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Dll|x64.Build.0 = Debug-Dll|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Lib|Win32.ActiveCfg = Debug-Lib|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Lib|Win32.Build.0 = Debug-Lib|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Lib|x64.ActiveCfg = Debug-Lib|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Debug-Lib|x64.Build.0 = Debug-Lib|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Dll|Win32.ActiveCfg = Release-Dll|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Dll|Win32.Build.0 = Release-Dll|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Dll|x64.ActiveCfg = Release-Dll|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Dll|x64.Build.0 = Release-Dll|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Lib|Win32.ActiveCfg = Release-Lib|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Lib|Win32.Build.0 = Release-Lib|Win32 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Lib|x64.ActiveCfg = Release-Lib|x64 - {D1C528B6-AA02-4D29-9D61-DC08E317A70D}.Release-Lib|x64.Build.0 = Release-Lib|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Dll|Win32.ActiveCfg = Debug-Dll|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Dll|Win32.Build.0 = Debug-Dll|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Dll|x64.ActiveCfg = Debug-Dll|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Dll|x64.Build.0 = Debug-Dll|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Lib|Win32.ActiveCfg = Debug-Lib|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Lib|Win32.Build.0 = Debug-Lib|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Lib|x64.ActiveCfg = Debug-Lib|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Debug-Lib|x64.Build.0 = Debug-Lib|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Dll|Win32.ActiveCfg = Release-Dll|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Dll|Win32.Build.0 = Release-Dll|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Dll|x64.ActiveCfg = Release-Dll|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Dll|x64.Build.0 = Release-Dll|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Lib|Win32.ActiveCfg = Release-Lib|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Lib|Win32.Build.0 = Release-Lib|Win32 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Lib|x64.ActiveCfg = Release-Lib|x64 - {E8FB2712-8666-4662-A5B8-2B5B0FB1A260}.Release-Lib|x64.Build.0 = Release-Lib|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj b/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj deleted file mode 100755 index 1257faf..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj +++ /dev/null @@ -1,384 +0,0 @@ - - - - - Debug-Dll - Win32 - - - Debug-Dll - x64 - - - Debug-Lib - Win32 - - - Debug-Lib - x64 - - - Release-Dll - Win32 - - - Release-Dll - x64 - - - Release-Lib - Win32 - - - Release-Lib - x64 - - - - {D1C528B6-AA02-4D29-9D61-DC08E317A70D} - Win32Proj - tinyxml2 - - - - StaticLibrary - true - Unicode - - - DynamicLibrary - true - Unicode - - - StaticLibrary - true - Unicode - - - DynamicLibrary - true - Unicode - - - StaticLibrary - false - true - Unicode - - - DynamicLibrary - false - true - Unicode - - - StaticLibrary - false - true - Unicode - - - DynamicLibrary - false - true - Unicode - - - StaticLibrary - Unicode - - - StaticLibrary - true - Unicode - - - StaticLibrary - Unicode - - - StaticLibrary - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - true - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - true - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - true - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - false - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - false - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - false - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - false - $(SolutionDir)bin\$(Platform)-$(Configuration)\ - $(SolutionDir)temp\$(Platform)-$(Configuration)\ - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - Console - true - - - - - - - Level4 - Disabled - WIN32;TINYXML2_EXPORT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - NotSet - true - - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - Console - true - - - - - - - Level4 - Disabled - WIN32;TINYXML2_EXPORT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - NotSet - true - - - - - Level4 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - AnySuitable - Speed - true - true - true - false - - - Console - true - true - true - true - - - - - Level4 - - - MaxSpeed - true - true - WIN32;TINYXML2_EXPORT;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - AnySuitable - Speed - true - true - true - false - - - NotSet - true - true - true - true - - - - - Level4 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - AnySuitable - Speed - true - true - true - false - - - Console - true - true - true - true - - - - - Level4 - - - MaxSpeed - true - true - WIN32;TINYXML2_EXPORT;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - AnySuitable - Speed - true - true - true - false - - - NotSet - true - true - true - true - - - - - true - - - - - true - - - AnySuitable - - - true - - - Speed - - - true - - - true - true - false - - - - - true - - - - - true - - - AnySuitable - - - true - - - Speed - - - true - - - true - true - false - - - - - - - - - - - - \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj.filters b/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj.filters deleted file mode 100755 index ee188b2..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.vcxproj.filters +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.xcodeproj/project.pbxproj b/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.xcodeproj/project.pbxproj deleted file mode 100644 index 58c4fcc..0000000 --- a/internal/tinyxml2-3.0.0/tinyxml2/tinyxml2.xcodeproj/project.pbxproj +++ /dev/null @@ -1,211 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 037AE8A5151E692700E0F29F /* xmltest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 037AE8A3151E692700E0F29F /* xmltest.cpp */; }; - 03F28B53152E9B1B00D4CD90 /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F28B4A152E9B1B00D4CD90 /* tinyxml2.cpp */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 037AE86D151E685F00E0F29F /* xmltest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xmltest; sourceTree = BUILT_PRODUCTS_DIR; }; - 037AE8A3151E692700E0F29F /* xmltest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = xmltest.cpp; path = ../xmltest.cpp; sourceTree = SOURCE_ROOT; }; - 03F28B4A152E9B1B00D4CD90 /* tinyxml2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxml2.cpp; sourceTree = ""; }; - 03F28B4B152E9B1B00D4CD90 /* tinyxml2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyxml2.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 037AE86B151E685F00E0F29F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 037AE056151CCC5200E0F29F = { - isa = PBXGroup; - children = ( - 037AE069151CCC7000E0F29F /* Classes */, - 03F28B60152E9B4C00D4CD90 /* Libraries */, - 037AE06F151CCCB900E0F29F /* Products */, - ); - sourceTree = ""; - }; - 037AE069151CCC7000E0F29F /* Classes */ = { - isa = PBXGroup; - children = ( - 037AE8A3151E692700E0F29F /* xmltest.cpp */, - ); - name = Classes; - sourceTree = ""; - }; - 037AE06F151CCCB900E0F29F /* Products */ = { - isa = PBXGroup; - children = ( - 037AE86D151E685F00E0F29F /* xmltest */, - ); - name = Products; - sourceTree = ""; - }; - 03F28AD7152E9B1B00D4CD90 /* tinyxml2 */ = { - isa = PBXGroup; - children = ( - 03F28B4A152E9B1B00D4CD90 /* tinyxml2.cpp */, - 03F28B4B152E9B1B00D4CD90 /* tinyxml2.h */, - ); - name = tinyxml2; - path = ..; - sourceTree = SOURCE_ROOT; - }; - 03F28B60152E9B4C00D4CD90 /* Libraries */ = { - isa = PBXGroup; - children = ( - 03F28AD7152E9B1B00D4CD90 /* tinyxml2 */, - ); - name = Libraries; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 037AE86C151E685F00E0F29F /* xmltest */ = { - isa = PBXNativeTarget; - buildConfigurationList = 037AE873151E687E00E0F29F /* Build configuration list for PBXNativeTarget "xmltest" */; - buildPhases = ( - 037AE86A151E685F00E0F29F /* Sources */, - 037AE86B151E685F00E0F29F /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = xmltest; - productName = tinyxml2; - productReference = 037AE86D151E685F00E0F29F /* xmltest */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 037AE058151CCC5200E0F29F /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0610; - }; - buildConfigurationList = 037AE05B151CCC5200E0F29F /* Build configuration list for PBXProject "tinyxml2" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 037AE056151CCC5200E0F29F; - productRefGroup = 037AE06F151CCCB900E0F29F /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 037AE86C151E685F00E0F29F /* xmltest */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 037AE86A151E685F00E0F29F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 037AE8A5151E692700E0F29F /* xmltest.cpp in Sources */, - 03F28B53152E9B1B00D4CD90 /* tinyxml2.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 037AE059151CCC5200E0F29F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CONFIGURATION_BUILD_DIR = "$(SYMROOT)/Debug"; - COPY_PHASE_STRIP = NO; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = DEBUG; - ONLY_ACTIVE_ARCH = YES; - SYMROOT = build; - }; - name = Debug; - }; - 037AE05A151CCC5200E0F29F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = YES; - }; - name = Release; - }; - 037AE86F151E686000E0F29F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CONFIGURATION_BUILD_DIR = ..; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_MODEL_TUNING = G5; - GCC_OPTIMIZATION_LEVEL = 0; - INSTALL_PATH = /usr/local/bin; - MACOSX_DEPLOYMENT_TARGET = ""; - PREBINDING = NO; - PRODUCT_NAME = xmltest; - }; - name = Debug; - }; - 037AE870151E686000E0F29F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CONFIGURATION_BUILD_DIR = ..; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - GCC_MODEL_TUNING = G5; - INSTALL_PATH = /usr/local/bin; - MACOSX_DEPLOYMENT_TARGET = ""; - PREBINDING = NO; - PRODUCT_NAME = tinyxml2; - ZERO_LINK = NO; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 037AE05B151CCC5200E0F29F /* Build configuration list for PBXProject "tinyxml2" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 037AE059151CCC5200E0F29F /* Debug */, - 037AE05A151CCC5200E0F29F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 037AE873151E687E00E0F29F /* Build configuration list for PBXNativeTarget "xmltest" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 037AE86F151E686000E0F29F /* Debug */, - 037AE870151E686000E0F29F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 037AE058151CCC5200E0F29F /* Project object */; -} diff --git a/internal/tinyxml2-3.0.0/xmltest.cpp b/internal/tinyxml2-3.0.0/xmltest.cpp deleted file mode 100644 index 7a14759..0000000 --- a/internal/tinyxml2-3.0.0/xmltest.cpp +++ /dev/null @@ -1,1489 +0,0 @@ -#if defined( _MSC_VER ) - #if !defined( _CRT_SECURE_NO_WARNINGS ) - #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure. - #endif -#endif - -#include "tinyxml2.h" -#include -#include -#include - -#if defined( _MSC_VER ) - #include // _mkdir - #include - #define WIN32_LEAN_AND_MEAN - #include - _CrtMemState startMemState; - _CrtMemState endMemState; -#elif defined(MINGW32) || defined(__MINGW32__) - #include // mkdir -#else - #include // mkdir -#endif - -using namespace tinyxml2; -using namespace std; -int gPass = 0; -int gFail = 0; - - -bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false ) -{ - bool pass = !strcmp( expected, found ); - if ( pass ) - printf ("[pass]"); - else - printf ("[fail]"); - - if ( !echo ) { - printf (" %s\n", testString); - } - else { - if ( extraNL ) { - printf( " %s\n", testString ); - printf( "%s\n", expected ); - printf( "%s\n", found ); - } - else { - printf (" %s [%s][%s]\n", testString, expected, found); - } - } - - if ( pass ) - ++gPass; - else - ++gFail; - return pass; -} - - -template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true ) -{ - bool pass = ( expected == found ); - if ( pass ) - printf ("[pass]"); - else - printf ("[fail]"); - - if ( !echo ) - printf (" %s\n", testString); - else - printf (" %s [%d][%d]\n", testString, static_cast(expected), static_cast(found) ); - - if ( pass ) - ++gPass; - else - ++gFail; - return pass; -} - - -void NullLineEndings( char* p ) -{ - while( p && *p ) { - if ( *p == '\n' || *p == '\r' ) { - *p = 0; - return; - } - ++p; - } -} - - -int example_1() -{ - XMLDocument doc; - doc.LoadFile( "resources/dream.xml" ); - - return doc.ErrorID(); -} -/** @page Example-1 Load an XML File - * @dontinclude ./xmltest.cpp - * Basic XML file loading. - * The basic syntax to load an XML file from - * disk and check for an error. (ErrorID() - * will return 0 for no error.) - * @skip example_1() - * @until } - */ - - -int example_2() -{ - static const char* xml = ""; - XMLDocument doc; - doc.Parse( xml ); - - return doc.ErrorID(); -} -/** @page Example-2 Parse an XML from char buffer - * @dontinclude ./xmltest.cpp - * Basic XML string parsing. - * The basic syntax to parse an XML for - * a char* and check for an error. (ErrorID() - * will return 0 for no error.) - * @skip example_2() - * @until } - */ - - -int example_3() -{ - static const char* xml = - "" - "" - "" - "A Midsummer Night's Dream" - ""; - - XMLDocument doc; - doc.Parse( xml ); - - XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" ); - const char* title = titleElement->GetText(); - printf( "Name of play (1): %s\n", title ); - - XMLText* textNode = titleElement->FirstChild()->ToText(); - title = textNode->Value(); - printf( "Name of play (2): %s\n", title ); - - return doc.ErrorID(); -} -/** @page Example-3 Get information out of XML - @dontinclude ./xmltest.cpp - In this example, we navigate a simple XML - file, and read some interesting text. Note - that this example doesn't use error - checking; working code should check for null - pointers when walking an XML tree, or use - XMLHandle. - - (The XML is an excerpt from "dream.xml"). - - @skip example_3() - @until "; - - The structure of the XML file is: - -
    -
  • (declaration)
  • -
  • (dtd stuff)
  • -
  • Element "PLAY"
  • -
      -
    • Element "TITLE"
    • -
        -
      • Text "A Midsummer Night's Dream"
      • -
      -
    -
- - For this example, we want to print out the - title of the play. The text of the title (what - we want) is child of the "TITLE" element which - is a child of the "PLAY" element. - - We want to skip the declaration and dtd, so the - method FirstChildElement() is a good choice. The - FirstChildElement() of the Document is the "PLAY" - Element, the FirstChildElement() of the "PLAY" Element - is the "TITLE" Element. - - @until ( "TITLE" ); - - We can then use the convenience function GetText() - to get the title of the play. - - @until title ); - - Text is just another Node in the XML DOM. And in - fact you should be a little cautious with it, as - text nodes can contain elements. - - @verbatim - Consider: A Midsummer Night's Dream - @endverbatim - - It is more correct to actually query the Text Node - if in doubt: - - @until title ); - - Noting that here we use FirstChild() since we are - looking for XMLText, not an element, and ToText() - is a cast from a Node to a XMLText. -*/ - - -bool example_4() -{ - static const char* xml = - "" - " " - " " - " 2" - " " - ""; - - XMLDocument doc; - doc.Parse( xml ); - - int v0 = 0; - int v1 = 0; - - XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" ); - attributeApproachElement->QueryIntAttribute( "v", &v0 ); - - XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" ); - textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 ); - - printf( "Both values are the same: %d and %d\n", v0, v1 ); - - return !doc.Error() && ( v0 == v1 ); -} -/** @page Example-4 Read attributes and text information. - @dontinclude ./xmltest.cpp - - There are fundamentally 2 ways of writing a key-value - pair into an XML file. (Something that's always annoyed - me about XML.) Either by using attributes, or by writing - the key name into an element and the value into - the text node wrapped by the element. Both approaches - are illustrated in this example, which shows two ways - to encode the value "2" into the key "v": - - @skip example_4() - @until ""; - - TinyXML-2 has accessors for both approaches. - - When using an attribute, you navigate to the XMLElement - with that attribute and use the QueryIntAttribute() - group of methods. (Also QueryFloatAttribute(), etc.) - - @skip XMLElement* attributeApproachElement - @until &v0 ); - - When using the text approach, you need to navigate - down one more step to the XMLElement that contains - the text. Note the extra FirstChildElement( "v" ) - in the code below. The value of the text can then - be safely queried with the QueryIntText() group - of methods. (Also QueryFloatText(), etc.) - - @skip XMLElement* textApproachElement - @until &v1 ); -*/ - - -int main( int argc, const char ** argv ) -{ - #if defined( _MSC_VER ) && defined( DEBUG ) - _CrtMemCheckpoint( &startMemState ); - // Enable MS Visual C++ debug heap memory leaks dump on exit - _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); - #endif - - #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__) - #if defined __MINGW64_VERSION_MAJOR && defined __MINGW64_VERSION_MINOR - //MINGW64: both 32 and 64-bit - mkdir( "resources/out/" ); - #else - _mkdir( "resources/out/" ); - #endif - #else - mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - #endif - - { - TIXMLASSERT( true ); - } - - if ( argc > 1 ) { - XMLDocument* doc = new XMLDocument(); - clock_t startTime = clock(); - doc->LoadFile( argv[1] ); - clock_t loadTime = clock(); - int errorID = doc->ErrorID(); - delete doc; doc = 0; - clock_t deleteTime = clock(); - - printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID ); - if ( !errorID ) { - printf( "Load time=%u\n", (unsigned)(loadTime - startTime) ); - printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) ); - printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) ); - } - exit(0); - } - - FILE* fp = fopen( "resources/dream.xml", "r" ); - if ( !fp ) { - printf( "Error opening test file 'dream.xml'.\n" - "Is your working directory the same as where \n" - "the xmltest.cpp and dream.xml file are?\n\n" - #if defined( _MSC_VER ) - "In windows Visual Studio you may need to set\n" - "Properties->Debugging->Working Directory to '..'\n" - #endif - ); - exit( 1 ); - } - fclose( fp ); - - XMLTest( "Example-1", 0, example_1() ); - XMLTest( "Example-2", 0, example_2() ); - XMLTest( "Example-3", 0, example_3() ); - XMLTest( "Example-4", true, example_4() ); - - /* ------ Example 2: Lookup information. ---- */ - - { - static const char* test[] = { "", - "", - "", - "", - "", - "", - " \n \n ", - "", - "", - "Text inside element.", - "", - "Text inside and bolded in the element.", - "Text inside and bolded in the element.", - "This & That.", - "", - 0 - }; - for( int i=0; test[i]; ++i ) { - XMLDocument doc; - doc.Parse( test[i] ); - doc.Print(); - printf( "----------------------------------------------\n" ); - } - } -#if 1 - { - static const char* test = ""; - - XMLDocument doc; - doc.Parse( test ); - doc.Print(); - } - - { - static const char* test = "Text before."; - XMLDocument doc; - doc.Parse( test ); - XMLElement* root = doc.FirstChildElement(); - XMLElement* newElement = doc.NewElement( "Subelement" ); - root->InsertEndChild( newElement ); - doc.Print(); - } - { - XMLDocument* doc = new XMLDocument(); - static const char* test = ""; - doc->Parse( test ); - delete doc; - } - { - // Test: Programmatic DOM - // Build: - // - // - // - // - // & Text! - // - - XMLDocument* doc = new XMLDocument(); - XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) ); - - XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) }; - for( int i=0; i<3; ++i ) { - sub[i]->SetAttribute( "attrib", i ); - } - element->InsertEndChild( sub[2] ); - XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) ); - element->InsertAfterChild( comment, sub[0] ); - element->InsertAfterChild( sub[0], sub[1] ); - sub[2]->InsertFirstChild( doc->NewText( "& Text!" )); - doc->Print(); - XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() ); - XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) ); - XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) ); - XMLTest( "Programmatic DOM", "& Text!", - doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() ); - - // And now deletion: - element->DeleteChild( sub[2] ); - doc->DeleteNode( comment ); - - element->FirstChildElement()->SetAttribute( "attrib", true ); - element->LastChildElement()->DeleteAttribute( "attrib" ); - - XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) ); - int value = 10; - int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value ); - XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE ); - XMLTest( "Programmatic DOM", value, 10 ); - - doc->Print(); - - { - XMLPrinter streamer; - doc->Print( &streamer ); - printf( "%s", streamer.CStr() ); - } - { - XMLPrinter streamer( 0, true ); - doc->Print( &streamer ); - XMLTest( "Compact mode", "", streamer.CStr(), false ); - } - doc->SaveFile( "./resources/out/pretty.xml" ); - doc->SaveFile( "./resources/out/compact.xml", true ); - delete doc; - } - { - // Test: Dream - // XML1 : 1,187,569 bytes in 31,209 allocations - // XML2 : 469,073 bytes in 323 allocations - //int newStart = gNew; - XMLDocument doc; - doc.LoadFile( "resources/dream.xml" ); - - doc.SaveFile( "resources/out/dreamout.xml" ); - doc.PrintError(); - - XMLTest( "Dream", "xml version=\"1.0\"", - doc.FirstChild()->ToDeclaration()->Value() ); - XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false ); - XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"", - doc.FirstChild()->NextSibling()->ToUnknown()->Value() ); - XMLTest( "Dream", "And Robin shall restore amends.", - doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); - XMLTest( "Dream", "And Robin shall restore amends.", - doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); - - XMLDocument doc2; - doc2.LoadFile( "resources/out/dreamout.xml" ); - XMLTest( "Dream-out", "xml version=\"1.0\"", - doc2.FirstChild()->ToDeclaration()->Value() ); - XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false ); - XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"", - doc2.FirstChild()->NextSibling()->ToUnknown()->Value() ); - XMLTest( "Dream-out", "And Robin shall restore amends.", - doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); - - //gNewTotal = gNew - newStart; - } - - - { - const char* error = "\n" - "\n" - " \n" - ""; - - XMLDocument doc; - doc.Parse( error ); - XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE ); - } - - { - const char* str = ""; - - XMLDocument doc; - doc.Parse( str ); - - XMLElement* ele = doc.FirstChildElement(); - - int iVal, result; - double dVal; - - result = ele->QueryDoubleAttribute( "attr0", &dVal ); - XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR ); - XMLTest( "Query attribute: int as double", (int)dVal, 1 ); - result = ele->QueryDoubleAttribute( "attr1", &dVal ); - XMLTest( "Query attribute: double as double", result, (int)XML_NO_ERROR ); - XMLTest( "Query attribute: double as double", (int)dVal, 2 ); - result = ele->QueryIntAttribute( "attr1", &iVal ); - XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR ); - XMLTest( "Query attribute: double as int", iVal, 2 ); - result = ele->QueryIntAttribute( "attr2", &iVal ); - XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE ); - result = ele->QueryIntAttribute( "bar", &iVal ); - XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE ); - } - - { - const char* str = ""; - - XMLDocument doc; - doc.Parse( str ); - - XMLElement* ele = doc.FirstChildElement(); - - int iVal, iVal2; - double dVal, dVal2; - - ele->SetAttribute( "str", "strValue" ); - ele->SetAttribute( "int", 1 ); - ele->SetAttribute( "double", -1.0 ); - - const char* cStr = ele->Attribute( "str" ); - ele->QueryIntAttribute( "int", &iVal ); - ele->QueryDoubleAttribute( "double", &dVal ); - - ele->QueryAttribute( "int", &iVal2 ); - ele->QueryAttribute( "double", &dVal2 ); - - XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" ); - XMLTest( "Attribute round trip. c-string.", "strValue", cStr ); - XMLTest( "Attribute round trip. int.", 1, iVal ); - XMLTest( "Attribute round trip. double.", -1, (int)dVal ); - XMLTest( "Alternate query", true, iVal == iVal2 ); - XMLTest( "Alternate query", true, dVal == dVal2 ); - } - - { - XMLDocument doc; - doc.LoadFile( "resources/utf8test.xml" ); - - // Get the attribute "value" from the "Russian" element and check it. - XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" ); - const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU, - 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 }; - - XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) ); - - const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U, - 0xd1U, 0x81U, 0xd1U, 0x81U, - 0xd0U, 0xbaU, 0xd0U, 0xb8U, - 0xd0U, 0xb9U, 0 }; - const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>"; - - XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText(); - XMLTest( "UTF-8: Browsing russian element name.", - russianText, - text->Value() ); - - // Now try for a round trip. - doc.SaveFile( "resources/out/utf8testout.xml" ); - - // Check the round trip. - int okay = 0; - - FILE* saved = fopen( "resources/out/utf8testout.xml", "r" ); - FILE* verify = fopen( "resources/utf8testverify.xml", "r" ); - - if ( saved && verify ) - { - okay = 1; - char verifyBuf[256]; - while ( fgets( verifyBuf, 256, verify ) ) - { - char savedBuf[256]; - fgets( savedBuf, 256, saved ); - NullLineEndings( verifyBuf ); - NullLineEndings( savedBuf ); - - if ( strcmp( verifyBuf, savedBuf ) ) - { - printf( "verify:%s<\n", verifyBuf ); - printf( "saved :%s<\n", savedBuf ); - okay = 0; - break; - } - } - } - if ( saved ) - fclose( saved ); - if ( verify ) - fclose( verify ); - XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay ); - } - - // --------GetText()----------- - { - const char* str = "This is text"; - XMLDocument doc; - doc.Parse( str ); - const XMLElement* element = doc.RootElement(); - - XMLTest( "GetText() normal use.", "This is text", element->GetText() ); - - str = "This is text"; - doc.Parse( str ); - element = doc.RootElement(); - - XMLTest( "GetText() contained element.", element->GetText() == 0, true ); - } - - - // --------SetText()----------- - { - const char* str = ""; - XMLDocument doc; - doc.Parse( str ); - XMLElement* element = doc.RootElement(); - - element->SetText("darkness."); - XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() ); - - element->SetText("blue flame."); - XMLTest( "SetText() replace.", "blue flame.", element->GetText() ); - - str = ""; - doc.Parse( str ); - element = doc.RootElement(); - - element->SetText("The driver"); - XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() ); - - element->SetText("horses"); - XMLTest( "SetText() replace with tag-like text.", "horses", element->GetText() ); - //doc.Print(); - - str = "Text in nested element"; - doc.Parse( str ); - element = doc.RootElement(); - - element->SetText("wolves"); - XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() ); - - str = ""; - doc.Parse( str ); - element = doc.RootElement(); - - element->SetText( "str" ); - XMLTest( "SetText types", "str", element->GetText() ); - - element->SetText( 1 ); - XMLTest( "SetText types", "1", element->GetText() ); - - element->SetText( 1U ); - XMLTest( "SetText types", "1", element->GetText() ); - - element->SetText( true ); - XMLTest( "SetText types", "1", element->GetText() ); // TODO: should be 'true'? - - element->SetText( 1.5f ); - XMLTest( "SetText types", "1.5", element->GetText() ); - - element->SetText( 1.5 ); - XMLTest( "SetText types", "1.5", element->GetText() ); - } - - - // ---------- CDATA --------------- - { - const char* str = "" - " the rules!\n" - "...since I make symbolic puns" - "]]>" - ""; - XMLDocument doc; - doc.Parse( str ); - doc.Print(); - - XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(), - "I am > the rules!\n...since I make symbolic puns", - false ); - } - - // ----------- CDATA ------------- - { - const char* str = "" - "I am > the rules!\n" - "...since I make symbolic puns" - "]]>" - ""; - XMLDocument doc; - doc.Parse( str ); - doc.Print(); - - XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), - "I am > the rules!\n...since I make symbolic puns", - false ); - } - - // InsertAfterChild causes crash. - { - // InsertBeforeChild and InsertAfterChild causes crash. - XMLDocument doc; - XMLElement* parent = doc.NewElement( "Parent" ); - doc.InsertFirstChild( parent ); - - XMLElement* childText0 = doc.NewElement( "childText0" ); - XMLElement* childText1 = doc.NewElement( "childText1" ); - - XMLNode* childNode0 = parent->InsertEndChild( childText0 ); - XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 ); - - XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true ); - } - - { - // Entities not being written correctly. - // From Lynn Allen - - const char* passages = - "" - "" - " " - ""; - - XMLDocument doc; - doc.Parse( passages ); - XMLElement* psg = doc.RootElement()->FirstChildElement(); - const char* context = psg->Attribute( "context" ); - const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; - - XMLTest( "Entity transformation: read. ", expected, context, true ); - - FILE* textfile = fopen( "resources/out/textfile.txt", "w" ); - if ( textfile ) - { - XMLPrinter streamer( textfile ); - psg->Accept( &streamer ); - fclose( textfile ); - } - - textfile = fopen( "resources/out/textfile.txt", "r" ); - TIXMLASSERT( textfile ); - if ( textfile ) - { - char buf[ 1024 ]; - fgets( buf, 1024, textfile ); - XMLTest( "Entity transformation: write. ", - "\n", - buf, false ); - fclose( textfile ); - } - } - - { - // Suppress entities. - const char* passages = - "" - "" - "Crazy &ttk;" - ""; - - XMLDocument doc( false ); - doc.Parse( passages ); - - XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ), - "Line 5 has "quotation marks" and 'apostrophe marks'." ); - XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(), - "Crazy &ttk;" ); - doc.Print(); - } - - { - const char* test = ""; - - XMLDocument doc; - doc.Parse( test ); - XMLTest( "dot in names", doc.Error(), false ); - XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" ); - XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" ); - } - - { - const char* test = "1.1 Start easy ignore fin thickness "; - - XMLDocument doc; - doc.Parse( test ); - - XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); - XMLTest( "Entity with one digit.", - text->Value(), "1.1 Start easy ignore fin thickness\n", - false ); - } - - { - // DOCTYPE not preserved (950171) - // - const char* doctype = - "" - "" - "" - "" - ""; - - XMLDocument doc; - doc.Parse( doctype ); - doc.SaveFile( "resources/out/test7.xml" ); - doc.DeleteChild( doc.RootElement() ); - doc.LoadFile( "resources/out/test7.xml" ); - doc.Print(); - - const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown(); - XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() ); - - } - - { - // Comments do not stream out correctly. - const char* doctype = - ""; - XMLDocument doc; - doc.Parse( doctype ); - - XMLComment* comment = doc.FirstChild()->ToComment(); - - XMLTest( "Comment formatting.", " Somewhat ", comment->Value() ); - } - { - // Double attributes - const char* doctype = ""; - - XMLDocument doc; - doc.Parse( doctype ); - - XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues) - doc.PrintError(); - } - - { - // Embedded null in stream. - const char* doctype = ""; - - XMLDocument doc; - doc.Parse( doctype ); - XMLTest( "Embedded null throws error.", true, doc.Error() ); - } - - { - // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717 - const char* str = ""; - XMLDocument doc; - doc.Parse( str ); - XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() ); - } - - { - // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717 - const char* str = " "; - XMLDocument doc; - doc.Parse( str ); - XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() ); - } - - { - // Low entities - XMLDocument doc; - doc.Parse( "" ); - const char result[] = { 0x0e, 0 }; - XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result ); - doc.Print(); - } - - { - // Attribute values with trailing quotes not handled correctly - XMLDocument doc; - doc.Parse( "" ); - XMLTest( "Throw error with bad end quotes.", doc.Error(), true ); - } - - { - // [ 1663758 ] Failure to report error on bad XML - XMLDocument xml; - xml.Parse(""); - XMLTest("Missing end tag at end of input", xml.Error(), true); - xml.Parse(" "); - XMLTest("Missing end tag with trailing whitespace", xml.Error(), true); - xml.Parse(""); - XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT); - } - - - { - // [ 1475201 ] TinyXML parses entities in comments - XMLDocument xml; - xml.Parse("" - "" ); - - XMLNode* e0 = xml.FirstChild(); - XMLNode* e1 = e0->NextSibling(); - XMLComment* c0 = e0->ToComment(); - XMLComment* c1 = e1->ToComment(); - - XMLTest( "Comments ignore entities.", " declarations for & ", c0->Value(), true ); - XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); - } - - { - XMLDocument xml; - xml.Parse( "" - "" - "" - "" - "" ); - xml.Print(); - - int count = 0; - - for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild(); - ele; - ele = ele->NextSibling() ) - { - ++count; - } - - XMLTest( "Comments iterate correctly.", 3, count ); - } - - { - // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well. - unsigned char buf[] = " " ); - XMLTest( "Handle end tag whitespace", false, xml.Error() ); - } - - { - // This one must not result in an infinite loop - XMLDocument xml; - xml.Parse( "loop" ); - XMLTest( "Infinite loop test.", true, true ); - } -#endif - { - const char* pub = " "; - XMLDocument doc; - doc.Parse( pub ); - - XMLDocument clone; - for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) { - XMLNode* copy = node->ShallowClone( &clone ); - clone.InsertEndChild( copy ); - } - - clone.Print(); - - int count=0; - const XMLNode* a=clone.FirstChild(); - const XMLNode* b=doc.FirstChild(); - for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) { - ++count; - XMLTest( "Clone and Equal", true, a->ShallowEqual( b )); - } - XMLTest( "Clone and Equal", 4, count ); - } - - { - // This shouldn't crash. - XMLDocument doc; - if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" )) - { - doc.PrintError(); - } - XMLTest( "Error in snprinf handling.", true, doc.Error() ); - } - - { - // Attribute ordering. - static const char* xml = ""; - XMLDocument doc; - doc.Parse( xml ); - XMLElement* ele = doc.FirstChildElement(); - - const XMLAttribute* a = ele->FirstAttribute(); - XMLTest( "Attribute order", "1", a->Value() ); - a = a->Next(); - XMLTest( "Attribute order", "2", a->Value() ); - a = a->Next(); - XMLTest( "Attribute order", "3", a->Value() ); - XMLTest( "Attribute order", "attrib3", a->Name() ); - - ele->DeleteAttribute( "attrib2" ); - a = ele->FirstAttribute(); - XMLTest( "Attribute order", "1", a->Value() ); - a = a->Next(); - XMLTest( "Attribute order", "3", a->Value() ); - - ele->DeleteAttribute( "attrib1" ); - ele->DeleteAttribute( "attrib3" ); - XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false ); - } - - { - // Make sure an attribute with a space in it succeeds. - static const char* xml0 = ""; - static const char* xml1 = ""; - static const char* xml2 = ""; - XMLDocument doc0; - doc0.Parse( xml0 ); - XMLDocument doc1; - doc1.Parse( xml1 ); - XMLDocument doc2; - doc2.Parse( xml2 ); - - XMLElement* ele = 0; - ele = doc0.FirstChildElement(); - XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) ); - ele = doc1.FirstChildElement(); - XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) ); - ele = doc2.FirstChildElement(); - XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) ); - } - - { - // Make sure we don't go into an infinite loop. - static const char* xml = ""; - XMLDocument doc; - doc.Parse( xml ); - XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement(); - XMLElement* ele1 = ele0->NextSiblingElement(); - bool equal = ele0->ShallowEqual( ele1 ); - - XMLTest( "Infinite loop in shallow equal.", true, equal ); - } - - // -------- Handles ------------ - { - static const char* xml = "Text"; - XMLDocument doc; - doc.Parse( xml ); - - XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement(); - XMLTest( "Handle, success, mutable", ele->Value(), "sub" ); - - XMLHandle docH( doc ); - ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement(); - XMLTest( "Handle, dne, mutable", false, ele != 0 ); - } - - { - static const char* xml = "Text"; - XMLDocument doc; - doc.Parse( xml ); - XMLConstHandle docH( doc ); - - const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement(); - XMLTest( "Handle, success, const", ele->Value(), "sub" ); - - ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement(); - XMLTest( "Handle, dne, const", false, ele != 0 ); - } - { - // Default Declaration & BOM - XMLDocument doc; - doc.InsertEndChild( doc.NewDeclaration() ); - doc.SetBOM( true ); - - XMLPrinter printer; - doc.Print( &printer ); - - static const char* result = "\xef\xbb\xbf"; - XMLTest( "BOM and default declaration", printer.CStr(), result, false ); - XMLTest( "CStrSize", printer.CStrSize(), 42, false ); - } - { - const char* xml = " This \nis ' text ' " - " This is ' text ' \n" - "This is ' \n\n text '" - ""; - XMLDocument doc( true, COLLAPSE_WHITESPACE ); - doc.Parse( xml ); - - const XMLElement* element = doc.FirstChildElement(); - for( const XMLElement* parent = element->FirstChildElement(); - parent; - parent = parent->NextSiblingElement() ) - { - XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() ); - } - } - -#if 0 - { - // Passes if assert doesn't fire. - XMLDocument xmlDoc; - - xmlDoc.NewDeclaration(); - xmlDoc.NewComment("Configuration file"); - - XMLElement *root = xmlDoc.NewElement("settings"); - root->SetAttribute("version", 2); - } -#endif - - { - const char* xml = " "; - XMLDocument doc( true, COLLAPSE_WHITESPACE ); - doc.Parse( xml ); - XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() ); - } - - { - // An assert should not fire. - const char* xml = ""; - XMLDocument doc; - doc.Parse( xml ); - XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope. - XMLTest( "Tracking unused elements", true, ele != 0, false ); - } - - - { - const char* xml = "abc"; - XMLDocument doc; - doc.Parse( xml ); - XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child"); - - XMLPrinter printer; - ele->Accept( &printer ); - XMLTest( "Printing of sub-element", "abc\n", printer.CStr(), false ); - } - - - { - XMLDocument doc; - XMLError error = doc.LoadFile( "resources/empty.xml" ); - XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error ); - XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() ); - doc.PrintError(); - } - - { - // BOM preservation - static const char* xml_bom_preservation = "\xef\xbb\xbf\n"; - { - XMLDocument doc; - XMLTest( "BOM preservation (parse)", XML_NO_ERROR, doc.Parse( xml_bom_preservation ), false ); - XMLPrinter printer; - doc.Print( &printer ); - - XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); - doc.SaveFile( "resources/bomtest.xml" ); - } - { - XMLDocument doc; - doc.LoadFile( "resources/bomtest.xml" ); - XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false ); - - XMLPrinter printer; - doc.Print( &printer ); - XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); - } - } - - { - // Insertion with Removal - const char* xml = "" - "" - "" - "" - "element 1text" - "" - "" - "" - ""; - const char* xmlInsideTwo = "" - "" - "" - "" - "" - "element 1text" - "" - "" - ""; - const char* xmlAfterOne = "" - "" - "" - "" - "element 1text" - "" - "" - ""; - const char* xmlAfterTwo = "" - "" - "" - "" - "" - "element 1text" - "" - ""; - - XMLDocument doc; - doc.Parse(xml); - XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); - XMLElement* two = doc.RootElement()->FirstChildElement("two"); - two->InsertFirstChild(subtree); - XMLPrinter printer1(0, true); - doc.Accept(&printer1); - XMLTest("Move node from within to ", xmlInsideTwo, printer1.CStr()); - - doc.Parse(xml); - subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); - two = doc.RootElement()->FirstChildElement("two"); - doc.RootElement()->InsertAfterChild(two, subtree); - XMLPrinter printer2(0, true); - doc.Accept(&printer2); - XMLTest("Move node from within after ", xmlAfterTwo, printer2.CStr(), false); - - doc.Parse(xml); - XMLNode* one = doc.RootElement()->FirstChildElement("one"); - subtree = one->FirstChildElement("subtree"); - doc.RootElement()->InsertAfterChild(one, subtree); - XMLPrinter printer3(0, true); - doc.Accept(&printer3); - XMLTest("Move node from within after ", xmlAfterOne, printer3.CStr(), false); - - doc.Parse(xml); - subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); - two = doc.RootElement()->FirstChildElement("two"); - doc.RootElement()->InsertEndChild(subtree); - XMLPrinter printer4(0, true); - doc.Accept(&printer4); - XMLTest("Move node from within after ", xmlAfterTwo, printer4.CStr(), false); - } - - { - const char* xml = "" - " " - ""; - XMLDocument doc; - doc.Parse(xml); - doc.Print(); - } - - { - // Test that it doesn't crash. - const char* xml = "<12"; - XMLDocument doc; - doc.Parse(xml); - doc.PrintError(); - } - -#if 1 - // the question being explored is what kind of print to use: - // https://github.com/leethomason/tinyxml2/issues/63 - { - //const char* xml = ""; - const char* xml = ""; - XMLDocument doc; - doc.Parse( xml ); - doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 ); - doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 ); - doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 ); - doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 ); - doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 ); - doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 ); - - doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f ); - doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f ); - doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f ); - doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f ); - doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f ); - doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f ); - - doc.Print(); - - /* The result of this test is platform, compiler, and library version dependent. :(" - XMLPrinter printer; - doc.Print( &printer ); - XMLTest( "Float and double formatting.", - "\n", - printer.CStr(), - true ); - */ - } -#endif - - { - // Issue #184 - // If it doesn't assert, it passes. Caused by objects - // getting created during parsing which are then - // inaccessible in the memory pools. - { - XMLDocument doc; - doc.Parse(""); - } - { - XMLDocument doc; - doc.Parse(""); - doc.Clear(); - } - } - - { - // If this doesn't assert in DEBUG, all is well. - tinyxml2::XMLDocument doc; - tinyxml2::XMLElement *pRoot = doc.NewElement("Root"); - doc.DeleteNode(pRoot); - } - - { - // Should not assert in DEBUG - XMLPrinter printer; - } - - { - // Issue 291. Should not crash - const char* xml = "�"; - XMLDocument doc; - doc.Parse( xml ); - - XMLPrinter printer; - doc.Print( &printer ); - } - - // ----------- Performance tracking -------------- - { -#if defined( _MSC_VER ) - __int64 start, end, freq; - QueryPerformanceFrequency( (LARGE_INTEGER*) &freq ); -#endif - - FILE* fp = fopen( "resources/dream.xml", "r" ); - fseek( fp, 0, SEEK_END ); - long size = ftell( fp ); - fseek( fp, 0, SEEK_SET ); - - char* mem = new char[size+1]; - fread( mem, size, 1, fp ); - fclose( fp ); - mem[size] = 0; - -#if defined( _MSC_VER ) - QueryPerformanceCounter( (LARGE_INTEGER*) &start ); -#else - clock_t cstart = clock(); -#endif - static const int COUNT = 10; - for( int i=0; i Date: Sat, 5 Aug 2017 22:59:49 -0700 Subject: [PATCH 06/25] update tinyxml2 build rules --- CMakeLists.txt | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4829e25..27f671c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,17 +69,6 @@ add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26) find_package (OpenSSL REQUIRED) include_directories (${OPENSSL_INCLUDE_DIR}) -if (USE_INTERNAL_TINYXML) - message("-- Using local TinyXML2 copy") - add_subdirectory(internal/tinyxml2-3.0.0) - include_directories(${CMAKE_CURRENT_LIST_DIR}/internal/tinyxml2-3.0.0) - link_directories(${CMAKE_BINARY_DIR}/internal/tinyxml2-3.0.0) - set(TINYXML_LIBRARIES tinyxml2) -else () - find_package (TinyXML REQUIRED) - include_directories (${TINYXML_INCLUDE_DIR}) -endif () - find_program (POD2MAN pod2man) # Check for include files and stdlib properties. @@ -151,6 +140,21 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.5) # Need 3.6 or abo endif() endif() +if (USE_INTERNAL_TINYXML) + message("-- Using local TinyXML2 copy") + set(TINYXML_DIR vendor/github.com/leethomason/tinyxml2) + set(BUILD_STATIC_LIBS ON CACHE BOOL "build static libs") + set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared libs") + set(BUILD_TESTS OFF CACHE BOOL "build tests") + add_subdirectory(${TINYXML_DIR}) + include_directories(${CMAKE_CURRENT_LIST_DIR}/${TINYXML_DIR}/) + link_directories(${CMAKE_BINARY_DIR}/${TINYXML_DIR}/) + set(TINYXML_LIBRARIES tinyxml2) +else () + find_package (TinyXML REQUIRED) + include_directories (${TINYXML_INCLUDE_DIR}) +endif () + set(SOURCE_FILES internal/easylogging++.cc encfs/autosprintf.cpp From d1e14b4ac867fec81c876bd2971efb5817d0a843 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 5 Aug 2017 23:20:33 -0700 Subject: [PATCH 07/25] switch to vendored easylogging --- CMakeLists.txt | 20 +- encfs/BlockNameIO.cpp | 2 +- encfs/CipherFileIO.cpp | 2 +- encfs/ConfigVar.cpp | 2 +- encfs/Context.cpp | 2 +- encfs/DirNode.cpp | 2 +- encfs/Error.h | 2 +- encfs/FileUtils.cpp | 2 +- encfs/MACFileIO.cpp | 2 +- encfs/NameIO.cpp | 2 +- encfs/RawFileIO.cpp | 2 +- encfs/SSL_Cipher.cpp | 2 +- encfs/StreamNameIO.cpp | 2 +- encfs/encfs.cpp | 2 +- encfs/encfs.h | 2 +- encfs/test.cpp | 2 +- internal/easylogging++.cc | 2979 ------------------------ internal/easylogging++.h | 4579 ------------------------------------- vendor/README.md | 24 + 19 files changed, 53 insertions(+), 7579 deletions(-) delete mode 100644 internal/easylogging++.cc delete mode 100644 internal/easylogging++.h create mode 100644 vendor/README.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 27f671c..28f3d87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,10 +36,10 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0) else () if (CMAKE_COMPILER_IS_GNUCXX) message ("** Assuming that GNU CXX uses -std=c++11 flag for C++11 compatibility.") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + list(APPEND CMAKE_CXX_FLAGS "-std=c++11") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") message ("** Assuming that Clang uses -std=c++11 flag for C++11 compatibility.") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + list(APPEND CMAKE_CXX_FLAGS "-std=c++11") else() message ("** No CMAKE C++11 check. If the build breaks, you're on your own.") endif() @@ -141,22 +141,29 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.5) # Need 3.6 or abo endif() if (USE_INTERNAL_TINYXML) - message("-- Using local TinyXML2 copy") + message("-- Using vendored TinyXML2") set(TINYXML_DIR vendor/github.com/leethomason/tinyxml2) set(BUILD_STATIC_LIBS ON CACHE BOOL "build static libs") set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared libs") set(BUILD_TESTS OFF CACHE BOOL "build tests") add_subdirectory(${TINYXML_DIR}) - include_directories(${CMAKE_CURRENT_LIST_DIR}/${TINYXML_DIR}/) - link_directories(${CMAKE_BINARY_DIR}/${TINYXML_DIR}/) + include_directories(${CMAKE_CURRENT_LIST_DIR}/${TINYXML_DIR}) + link_directories(${CMAKE_BINARY_DIR}/${TINYXML_DIR}) set(TINYXML_LIBRARIES tinyxml2) else () find_package (TinyXML REQUIRED) include_directories (${TINYXML_INCLUDE_DIR}) endif () +message("-- Using vendored easylogging++") +set(EASYLOGGING_DIR vendor/github.com/muflihun/easyloggingpp) +set(build_static_lib ON CACHE BOOL "build static libs") +add_subdirectory(${EASYLOGGING_DIR}) +include_directories(${CMAKE_CURRENT_LIST_DIR}/${EASYLOGGING_DIR}/src) +link_directories(${CMAKE_BINARY_DIR}/${EASYLOGGING_DIR}) +set(EASYLOGGING_LIBRARIES easyloggingpp) + set(SOURCE_FILES - internal/easylogging++.cc encfs/autosprintf.cpp encfs/base64.cpp encfs/BlockFileIO.cpp @@ -194,6 +201,7 @@ target_link_libraries(encfs ${FUSE_LIBRARIES} ${OPENSSL_LIBRARIES} ${TINYXML_LIBRARIES} + ${EASYLOGGING_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Intl_LIBRARIES} ) diff --git a/encfs/BlockNameIO.cpp b/encfs/BlockNameIO.cpp index 3a25016..3389e91 100644 --- a/encfs/BlockNameIO.cpp +++ b/encfs/BlockNameIO.cpp @@ -30,7 +30,7 @@ #include "Interface.h" #include "NameIO.h" #include "base64.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include "intl/gettext.h" namespace encfs { diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp index e825b6e..e67095a 100644 --- a/encfs/CipherFileIO.cpp +++ b/encfs/CipherFileIO.cpp @@ -20,7 +20,7 @@ #include "CipherFileIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/ConfigVar.cpp b/encfs/ConfigVar.cpp index b9dceef..4a39f00 100644 --- a/encfs/ConfigVar.cpp +++ b/encfs/ConfigVar.cpp @@ -20,7 +20,7 @@ #include "ConfigVar.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include "Error.h" diff --git a/encfs/Context.cpp b/encfs/Context.cpp index f8151b9..bfbcbf3 100644 --- a/encfs/Context.cpp +++ b/encfs/Context.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include "Context.h" diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 2494084..2457d1c 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -35,7 +35,7 @@ #include #endif -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include diff --git a/encfs/Error.h b/encfs/Error.h index c045871..50cabdf 100644 --- a/encfs/Error.h +++ b/encfs/Error.h @@ -3,7 +3,7 @@ // Provides compatibility with RLog's rAssert, which throws an Error exception. -#include "internal/easylogging++.h" +#include "easylogging++.h" #include namespace encfs { diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 3374ce5..5080952 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -25,7 +25,7 @@ #define _BSD_SOURCE // pick up setenv on RH7.3 #define _DEFAULT_SOURCE // Replaces _BSD_SOURCE -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp index bc03605..b606c2a 100644 --- a/encfs/MACFileIO.cpp +++ b/encfs/MACFileIO.cpp @@ -20,7 +20,7 @@ #include "MACFileIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/NameIO.cpp b/encfs/NameIO.cpp index 2d9582f..99c563c 100644 --- a/encfs/NameIO.cpp +++ b/encfs/NameIO.cpp @@ -20,7 +20,7 @@ #include "NameIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include // for static build. Need to reference the modules which are registered at // run-time, to ensure that the linker doesn't optimize them away. diff --git a/encfs/RawFileIO.cpp b/encfs/RawFileIO.cpp index b8dae9a..b4373fd 100644 --- a/encfs/RawFileIO.cpp +++ b/encfs/RawFileIO.cpp @@ -21,7 +21,7 @@ #ifdef linux #define _XOPEN_SOURCE 500 // pick up pread , pwrite #endif -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp index c68466b..69c3212 100644 --- a/encfs/SSL_Cipher.cpp +++ b/encfs/SSL_Cipher.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/StreamNameIO.cpp b/encfs/StreamNameIO.cpp index 682d32b..5b6a6c5 100644 --- a/encfs/StreamNameIO.cpp +++ b/encfs/StreamNameIO.cpp @@ -20,7 +20,7 @@ #include "StreamNameIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include diff --git a/encfs/encfs.cpp b/encfs/encfs.cpp index 8787719..c8b72d6 100644 --- a/encfs/encfs.cpp +++ b/encfs/encfs.cpp @@ -41,7 +41,7 @@ #include #endif -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/encfs.h b/encfs/encfs.h index 2988af2..eada993 100644 --- a/encfs/encfs.h +++ b/encfs/encfs.h @@ -21,7 +21,7 @@ #ifndef _encfs_incl_ #define _encfs_incl_ -#include "internal/easylogging++.h" +#include "easylogging++.h" #include #include #include diff --git a/encfs/test.cpp b/encfs/test.cpp index dff8bbf..8da058e 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -38,7 +38,7 @@ #include "NameIO.h" #include "Range.h" #include "StreamNameIO.h" -#include "internal/easylogging++.h" +#include "easylogging++.h" #define NO_DES #include diff --git a/internal/easylogging++.cc b/internal/easylogging++.cc deleted file mode 100644 index cf6958a..0000000 --- a/internal/easylogging++.cc +++ /dev/null @@ -1,2979 +0,0 @@ -// -// Bismillah ar-Rahmaan ar-Raheem -// -// Easylogging++ v9.94.1 -// Cross-platform logging library for C++ applications -// -// Copyright (c) 2017 muflihun.com -// -// This library is released under the MIT Licence. -// http://labs.muflihun.com/easyloggingpp/licence.php -// -// https://github.com/muflihun/easyloggingpp -// https://muflihun.github.io/easyloggingpp -// http://muflihun.com -// - -#include "easylogging++.h" - -#if defined(AUTO_INITIALIZE_EASYLOGGINGPP) -INITIALIZE_EASYLOGGINGPP -#endif - -namespace el { - -// el::base::utils -namespace base { -namespace utils { - -/// @brief Aborts application due with user-defined status -static void abort(int status, const std::string& reason) { - // Both status and reason params are there for debugging with tools like gdb etc - ELPP_UNUSED(status); - ELPP_UNUSED(reason); -#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) - // Ignore msvc critical error dialog - break instead (on debug mode) - _asm int 3 -#else - ::abort(); -#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) -} - -} // namespace utils -} // namespace base - -// el - -// LevelHelper - -const char* LevelHelper::convertToString(Level level) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (level == Level::Global) return "GLOBAL"; - if (level == Level::Debug) return "DEBUG"; - if (level == Level::Info) return "INFO"; - if (level == Level::Warning) return "WARNING"; - if (level == Level::Error) return "ERROR"; - if (level == Level::Fatal) return "FATAL"; - if (level == Level::Verbose) return "VERBOSE"; - if (level == Level::Trace) return "TRACE"; - return "UNKNOWN"; -} - -struct StringToLevelItem { - const char* levelString; - Level level; -}; - -static struct StringToLevelItem stringToLevelMap[] = { - { "global", Level::Global }, - { "debug", Level::Debug }, - { "info", Level::Info }, - { "warning", Level::Warning }, - { "error", Level::Error }, - { "fatal", Level::Fatal }, - { "verbose", Level::Verbose }, - { "trace", Level::Trace } -}; - -Level LevelHelper::convertFromString(const char* levelStr) { - for (auto& item : stringToLevelMap) { - if (base::utils::Str::cStringCaseEq(levelStr, item.levelString)) { - return item.level; - } - } - return Level::Unknown; -} - -void LevelHelper::forEachLevel(base::type::EnumType* startIndex, const std::function& fn) { - base::type::EnumType lIndexMax = LevelHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast(*startIndex << 1); - } while (*startIndex <= lIndexMax); -} - -// ConfigurationTypeHelper - -const char* ConfigurationTypeHelper::convertToString(ConfigurationType configurationType) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (configurationType == ConfigurationType::Enabled) return "ENABLED"; - if (configurationType == ConfigurationType::Filename) return "FILENAME"; - if (configurationType == ConfigurationType::Format) return "FORMAT"; - if (configurationType == ConfigurationType::ToFile) return "TO_FILE"; - if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT"; - if (configurationType == ConfigurationType::SubsecondPrecision) return "SUBSECOND_PRECISION"; - if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING"; - if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE"; - if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD"; - return "UNKNOWN"; -} - -struct ConfigurationStringToTypeItem { - const char* configString; - ConfigurationType configType; -}; - -static struct ConfigurationStringToTypeItem configStringToTypeMap[] = { - { "enabled", ConfigurationType::Enabled }, - { "to_file", ConfigurationType::ToFile }, - { "to_standard_output", ConfigurationType::ToStandardOutput }, - { "format", ConfigurationType::Format }, - { "filename", ConfigurationType::Filename }, - { "subsecond_precision", ConfigurationType::SubsecondPrecision }, - { "milliseconds_width", ConfigurationType::MillisecondsWidth }, - { "performance_tracking", ConfigurationType::PerformanceTracking }, - { "max_log_file_size", ConfigurationType::MaxLogFileSize }, - { "log_flush_threshold", ConfigurationType::LogFlushThreshold }, -}; - -ConfigurationType ConfigurationTypeHelper::convertFromString(const char* configStr) { - for (auto& item : configStringToTypeMap) { - if (base::utils::Str::cStringCaseEq(configStr, item.configString)) { - return item.configType; - } - } - return ConfigurationType::Unknown; -} - -void ConfigurationTypeHelper::forEachConfigType(base::type::EnumType* startIndex, const std::function& fn) { - base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast(*startIndex << 1); - } while (*startIndex <= cIndexMax); -} - -// Configuration - -Configuration::Configuration(const Configuration& c) : - m_level(c.m_level), - m_configurationType(c.m_configurationType), - m_value(c.m_value) { -} - -Configuration& Configuration::operator=(const Configuration& c) { - if (&c != this) { - m_level = c.m_level; - m_configurationType = c.m_configurationType; - m_value = c.m_value; - } - return *this; -} - -/// @brief Full constructor used to sets value of configuration -Configuration::Configuration(Level level, ConfigurationType configurationType, const std::string& value) : - m_level(level), - m_configurationType(configurationType), - m_value(value) { -} - -void Configuration::log(el::base::type::ostream_t& os) const { - os << LevelHelper::convertToString(m_level) - << ELPP_LITERAL(" ") << ConfigurationTypeHelper::convertToString(m_configurationType) - << ELPP_LITERAL(" = ") << m_value.c_str(); -} - -/// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. -Configuration::Predicate::Predicate(Level level, ConfigurationType configurationType) : - m_level(level), - m_configurationType(configurationType) { -} - -bool Configuration::Predicate::operator()(const Configuration* conf) const { - return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType)); -} - -// Configurations - -Configurations::Configurations(void) : - m_configurationFile(std::string()), - m_isFromFile(false) { -} - -Configurations::Configurations(const std::string& configurationFile, bool useDefaultsForRemaining, - Configurations* base) : - m_configurationFile(configurationFile), - m_isFromFile(false) { - parseFromFile(configurationFile, base); - if (useDefaultsForRemaining) { - setRemainingToDefault(); - } -} - -bool Configurations::parseFromFile(const std::string& configurationFile, Configurations* base) { - // We initial assertion with true because if we have assertion diabled, we want to pass this - // check and if assertion is enabled we will have values re-assigned any way. - bool assertionPassed = true; - ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)) == true, - "Configuration file [" << configurationFile << "] does not exist!"); - if (!assertionPassed) { - return false; - } - bool success = Parser::parseFromFile(configurationFile, this, base); - m_isFromFile = success; - return success; -} - -bool Configurations::parseFromText(const std::string& configurationsString, Configurations* base) { - bool success = Parser::parseFromText(configurationsString, this, base); - if (success) { - m_isFromFile = false; - } - return success; -} - -void Configurations::setFromBase(Configurations* base) { - if (base == nullptr || base == this) { - return; - } - base::threading::ScopedLock scopedLock(base->lock()); - for (Configuration*& conf : base->list()) { - set(conf); - } -} - -bool Configurations::hasConfiguration(ConfigurationType configurationType) { - base::type::EnumType lIndex = LevelHelper::kMinValid; - bool result = false; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) { - result = true; - } - return result; - }); - return result; -} - -bool Configurations::hasConfiguration(Level level, ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); -#if ELPP_COMPILER_INTEL - // We cant specify template types here, Intel C++ throws compilation error - // "error: type name is not allowed" - return RegistryWithPred::get(level, configurationType) != nullptr; -#else - return RegistryWithPred::get(level, configurationType) != nullptr; -#endif // ELPP_COMPILER_INTEL -} - -void Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) { - base::threading::ScopedLock scopedLock(lock()); - unsafeSet(level, configurationType, value); // This is not unsafe anymore as we have locked mutex - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); // Again this is not unsafe either - } -} - -void Configurations::set(Configuration* conf) { - if (conf == nullptr) { - return; - } - set(conf->level(), conf->configurationType(), conf->value()); -} - -void Configurations::setToDefault(void) { - setGlobally(ConfigurationType::Enabled, std::string("true"), true); -#if !defined(ELPP_NO_DEFAULT_LOG_FILE) - setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true); -#else - ELPP_UNUSED(base::consts::kDefaultLogFile); -#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) -#if defined(ELPP_NO_LOG_TO_FILE) - setGlobally(ConfigurationType::ToFile, std::string("false"), true); -#else - setGlobally(ConfigurationType::ToFile, std::string("true"), true); -#endif // defined(ELPP_NO_LOG_TO_FILE) - setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true); - setGlobally(ConfigurationType::SubsecondPrecision, std::string("3"), true); - setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), true); - setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true); - setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true); - - setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true); - set(Level::Debug, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); - set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg")); -} - -void Configurations::setRemainingToDefault(void) { - base::threading::ScopedLock scopedLock(lock()); -#if defined(ELPP_NO_LOG_TO_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("false")); -#else - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true")); -#endif // defined(ELPP_NO_LOG_TO_FILE) -#if !defined(ELPP_NO_DEFAULT_LOG_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile)); -#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, std::string("3")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, std::string("0")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Debug, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); - unsafeSetIfNotExist(Level::Trace, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%func] [%loc] %msg")); -} - -bool Configurations::Parser::parseFromFile(const std::string& configurationFile, Configurations* sender, - Configurations* base) { - sender->setFromBase(base); - std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in); - ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing."); - bool parsedSuccessfully = false; - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (fileStream_.good()) { - std::getline(fileStream_, line); - parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; -} - -bool Configurations::Parser::parseFromText(const std::string& configurationsString, Configurations* sender, - Configurations* base) { - sender->setFromBase(base); - bool parsedSuccessfully = false; - std::stringstream ss(configurationsString); - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (std::getline(ss, line)) { - parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; -} - -void Configurations::Parser::ignoreComments(std::string* line) { - std::size_t foundAt = 0; - std::size_t quotesStart = line->find("\""); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = line->find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') { - // Do not erase slash yet - we will erase it in parseLine(..) while loop - quotesEnd = line->find("\"", quotesEnd + 2); - } - } - if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) { - if (foundAt < quotesEnd) { - foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1); - } - *line = line->substr(0, foundAt); - } -} - -bool Configurations::Parser::isLevel(const std::string& line) { - return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLevel)); -} - -bool Configurations::Parser::isComment(const std::string& line) { - return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationComment)); -} - -bool Configurations::Parser::isConfig(const std::string& line) { - std::size_t assignment = line.find('='); - return line != "" && - ((line[0] >= 'A' && line[0] <= 'Z') || (line[0] >= 'a' && line[0] <= 'z')) && - (assignment != std::string::npos) && - (line.size() > assignment); -} - -bool Configurations::Parser::parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, - Level* currLevel, - Configurations* conf) { - ConfigurationType currConfig = ConfigurationType::Unknown; - std::string currValue = std::string(); - *line = base::utils::Str::trim(*line); - if (isComment(*line)) return true; - ignoreComments(line); - *line = base::utils::Str::trim(*line); - if (line->empty()) { - // Comment ignored - return true; - } - if (isLevel(*line)) { - if (line->size() <= 2) { - return true; - } - *currLevelStr = line->substr(1, line->size() - 2); - *currLevelStr = base::utils::Str::toUpper(*currLevelStr); - *currLevelStr = base::utils::Str::trim(*currLevelStr); - *currLevel = LevelHelper::convertFromString(currLevelStr->c_str()); - return true; - } - if (isConfig(*line)) { - std::size_t assignment = line->find('='); - *currConfigStr = line->substr(0, assignment); - *currConfigStr = base::utils::Str::toUpper(*currConfigStr); - *currConfigStr = base::utils::Str::trim(*currConfigStr); - currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str()); - currValue = line->substr(assignment + 1); - currValue = base::utils::Str::trim(currValue); - std::size_t quotesStart = currValue.find("\"", 0); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = currValue.find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') { - currValue = currValue.erase(quotesEnd - 1, 1); - quotesEnd = currValue.find("\"", quotesEnd + 2); - } - } - if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { - // Quote provided - check and strip if valid - ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" - << currConfigStr << "]"); - ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]"); - if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { - // Explicit check in case if assertion is disabled - currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); - } - } - } - ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]"); - ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]"); - if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) { - return false; // unrecognizable level or config - } - conf->set(*currLevel, currConfig, currValue); - return true; -} - -void Configurations::unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value) { - Configuration* conf = RegistryWithPred::get(level, configurationType); - if (conf == nullptr) { - unsafeSet(level, configurationType, value); - } -} - -void Configurations::unsafeSet(Level level, ConfigurationType configurationType, const std::string& value) { - Configuration* conf = RegistryWithPred::get(level, configurationType); - if (conf == nullptr) { - registerNew(new Configuration(level, configurationType, value)); - } else { - conf->setValue(value); - } - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); - } -} - -void Configurations::setGlobally(ConfigurationType configurationType, const std::string& value, - bool includeGlobalLevel) { - if (includeGlobalLevel) { - set(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - set(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all levels regardless - }); -} - -void Configurations::unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, - bool includeGlobalLevel) { - if (includeGlobalLevel) { - unsafeSet(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all levels regardless - }); -} - -// LogBuilder - -void LogBuilder::convertToColoredOutput(base::type::string_t* logLine, Level level) { - if (!m_termSupportsColor) return; - const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m"); - if (level == Level::Error || level == Level::Fatal) - *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; - else if (level == Level::Warning) - *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; - else if (level == Level::Debug) - *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; - else if (level == Level::Info) - *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; - else if (level == Level::Trace) - *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; -} - -// Logger - -Logger::Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference) : - m_id(id), - m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), - m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); -} - -Logger::Logger(const std::string& id, const Configurations& configurations, - base::LogStreamsReferenceMap* logStreamsReference) : - m_id(id), - m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), - m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); - configure(configurations); -} - -Logger::Logger(const Logger& logger) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; -} - -Logger& Logger::operator=(const Logger& logger) { - if (&logger != this) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; - } - return *this; -} - -void Logger::configure(const Configurations& configurations) { - m_isConfigured = false; // we set it to false in case if we fail - initUnflushedCount(); - if (m_typedConfigurations != nullptr) { - Configurations* c = const_cast(m_typedConfigurations->configurations()); - if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) { - // This check is definitely needed for cases like ELPP_NO_DEFAULT_LOG_FILE - flush(); - } - } - base::threading::ScopedLock scopedLock(lock()); - if (m_configurations != configurations) { - m_configurations.setFromBase(const_cast(&configurations)); - } - base::utils::safeDelete(m_typedConfigurations); - m_typedConfigurations = new base::TypedConfigurations(&m_configurations, m_logStreamsReference); - resolveLoggerFormatSpec(); - m_isConfigured = true; -} - -void Logger::reconfigure(void) { - ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]"); - configure(m_configurations); -} - -bool Logger::isValidId(const std::string& id) { - for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) { - if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) { - return false; - } - } - return true; -} - -void Logger::flush(void) { - ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels"); - base::threading::ScopedLock scopedLock(lock()); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - flush(LevelHelper::castFromInt(lIndex), nullptr); - return false; - }); -} - -void Logger::flush(Level level, base::type::fstream_t* fs) { - if (fs == nullptr && m_typedConfigurations->toFile(level)) { - fs = m_typedConfigurations->fileStream(level); - } - if (fs != nullptr) { - fs->flush(); - m_unflushedCount.find(level)->second = 0; - } -} - -void Logger::initUnflushedCount(void) { - m_unflushedCount.clear(); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0)); - return false; - }); -} - -void Logger::resolveLoggerFormatSpec(void) const { - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - base::LogFormat* logFormat = - const_cast(&m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex))); - base::utils::Str::replaceFirstWithEscape(logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id); - return false; - }); -} - -// el::base -namespace base { - -// el::base::utils -namespace utils { - -// File - -base::type::fstream_t* File::newFileStream(const std::string& filename) { - base::type::fstream_t *fs = new base::type::fstream_t(filename.c_str(), - base::type::fstream_t::out -#if !defined(ELPP_FRESH_LOG_FILE) - | base::type::fstream_t::app -#endif - ); -#if defined(ELPP_UNICODE) - std::locale elppUnicodeLocale(""); -# if ELPP_OS_WINDOWS - std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16); - elppUnicodeLocale = elppUnicodeLocaleWindows; -# endif // ELPP_OS_WINDOWS - fs->imbue(elppUnicodeLocale); -#endif // defined(ELPP_UNICODE) - if (fs->is_open()) { - fs->flush(); - } else { - base::utils::safeDelete(fs); - ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true); - } - return fs; -} - -std::size_t File::getSizeOfFile(base::type::fstream_t* fs) { - if (fs == nullptr) { - return 0; - } - std::streampos currPos = fs->tellg(); - fs->seekg(0, fs->end); - std::size_t size = static_cast(fs->tellg()); - fs->seekg(currPos); - return size; -} - -bool File::pathExists(const char* path, bool considerFile) { - if (path == nullptr) { - return false; - } -#if ELPP_OS_UNIX - ELPP_UNUSED(considerFile); - struct stat st; - return (stat(path, &st) == 0); -#elif ELPP_OS_WINDOWS - DWORD fileType = GetFileAttributesA(path); - if (fileType == INVALID_FILE_ATTRIBUTES) { - return false; - } - return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true); -#endif // ELPP_OS_UNIX -} - -bool File::createPath(const std::string& path) { - if (path.empty()) { - return false; - } - if (base::utils::File::pathExists(path.c_str())) { - return true; - } - int status = -1; - - char* currPath = const_cast(path.c_str()); - std::string builtPath = std::string(); -#if ELPP_OS_UNIX - if (path[0] == '/') { - builtPath = "/"; - } - currPath = STRTOK(currPath, base::consts::kFilePathSeperator, 0); -#elif ELPP_OS_WINDOWS - // Use secure functions API - char* nextTok_ = nullptr; - currPath = STRTOK(currPath, base::consts::kFilePathSeperator, &nextTok_); - ELPP_UNUSED(nextTok_); -#endif // ELPP_OS_UNIX - while (currPath != nullptr) { - builtPath.append(currPath); - builtPath.append(base::consts::kFilePathSeperator); -#if ELPP_OS_UNIX - status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS); - currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, 0); -#elif ELPP_OS_WINDOWS - status = _mkdir(builtPath.c_str()); - currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, &nextTok_); -#endif // ELPP_OS_UNIX - } - if (status == -1) { - ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true); - return false; - } - return true; -} - -std::string File::extractPathFromFilename(const std::string& fullPath, const char* separator) { - if ((fullPath == "") || (fullPath.find(separator) == std::string::npos)) { - return fullPath; - } - std::size_t lastSlashAt = fullPath.find_last_of(separator); - if (lastSlashAt == 0) { - return std::string(separator); - } - return fullPath.substr(0, lastSlashAt + 1); -} - -void File::buildStrippedFilename(const char* filename, char buff[], std::size_t limit) { - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); -} - -void File::buildBaseFilename(const std::string& fullPath, char buff[], std::size_t limit, const char* separator) { - const char *filename = fullPath.c_str(); - std::size_t lastSlashAt = fullPath.find_last_of(separator); - filename += lastSlashAt ? lastSlashAt+1 : 0; - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); -} - -// Str - -bool Str::wildCardMatch(const char* str, const char* pattern) { - while (*pattern) { - switch (*pattern) { - case '?': - if (!*str) - return false; - ++str; - ++pattern; - break; - case '*': - if (wildCardMatch(str, pattern + 1)) - return true; - if (*str && wildCardMatch(str + 1, pattern)) - return true; - return false; - default: - if (*str++ != *pattern++) - return false; - break; - } - } - return !*str && !*pattern; -} - -std::string& Str::ltrim(std::string& str) { - str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](char c) { - return !std::isspace(c); - } )); - return str; -} - -std::string& Str::rtrim(std::string& str) { - str.erase(std::find_if(str.rbegin(), str.rend(), [](char c) { - return !std::isspace(c); - }).base(), str.end()); - return str; -} - -std::string& Str::trim(std::string& str) { - return ltrim(rtrim(str)); -} - -bool Str::startsWith(const std::string& str, const std::string& start) { - return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0); -} - -bool Str::endsWith(const std::string& str, const std::string& end) { - return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0); -} - -std::string& Str::replaceAll(std::string& str, char replaceWhat, char replaceWith) { - std::replace(str.begin(), str.end(), replaceWhat, replaceWith); - return str; -} - -std::string& Str::replaceAll(std::string& str, const std::string& replaceWhat, - const std::string& replaceWith) { - if (replaceWhat == replaceWith) - return str; - std::size_t foundAt = std::string::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) { - str.replace(foundAt, replaceWhat.length(), replaceWith); - } - return str; -} - -void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const base::type::string_t& replaceWith) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) { - if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) { - str.erase(foundAt > 0 ? foundAt - 1 : 0, 1); - ++foundAt; - } else { - str.replace(foundAt, replaceWhat.length(), replaceWith); - return; - } - } -} -#if defined(ELPP_UNICODE) -void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const std::string& replaceWith) { - replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end())); -} -#endif // defined(ELPP_UNICODE) - -std::string& Str::toUpper(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), ::toupper); - return str; -} - -bool Str::cStringEq(const char* s1, const char* s2) { - if (s1 == nullptr && s2 == nullptr) return true; - if (s1 == nullptr || s2 == nullptr) return false; - return strcmp(s1, s2) == 0; -} - -bool Str::cStringCaseEq(const char* s1, const char* s2) { - if (s1 == nullptr && s2 == nullptr) return true; - if (s1 == nullptr || s2 == nullptr) return false; - - // With thanks to cygwin for this code - int d = 0; - - while (true) { - const int c1 = toupper(*s1++); - const int c2 = toupper(*s2++); - - if (((d = c1 - c2) != 0) || (c2 == '\0')) { - break; - } - } - - return d == 0; -} - -bool Str::contains(const char* str, char c) { - for (; *str; ++str) { - if (*str == c) - return true; - } - return false; -} - -char* Str::convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded) { - char localBuff[10] = ""; - char* p = localBuff + sizeof(localBuff) - 2; - if (n > 0) { - for (; n > 0 && p > localBuff && len > 0; n /= 10, --len) - *--p = static_cast(n % 10 + '0'); - } else { - *--p = '0'; - --len; - } - if (zeroPadded) - while (p > localBuff && len-- > 0) *--p = static_cast('0'); - return addToBuff(p, buf, bufLim); -} - -char* Str::addToBuff(const char* str, char* buf, const char* bufLim) { - while ((buf < bufLim) && ((*buf = *str++) != '\0')) - ++buf; - return buf; -} - -char* Str::clearBuff(char buff[], std::size_t lim) { - STRCPY(buff, "", lim); - ELPP_UNUSED(lim); // For *nix we dont have anything using lim in above STRCPY macro - return buff; -} - -/// @brief Converst wchar* to char* -/// NOTE: Need to free return value after use! -char* Str::wcharPtrToCharPtr(const wchar_t* line) { - std::size_t len_ = wcslen(line) + 1; - char* buff_ = static_cast(malloc(len_ + 1)); -# if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - std::wcstombs(buff_, line, len_); -# elif ELPP_OS_WINDOWS - std::size_t convCount_ = 0; - mbstate_t mbState_; - ::memset(static_cast(&mbState_), 0, sizeof(mbState_)); - wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_); -# endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - return buff_; -} - -// OS - -#if ELPP_OS_WINDOWS -/// @brief Gets environment variables for Windows based OS. -/// We are not using getenv(const char*) because of CRT deprecation -/// @param varname Variable name to get environment variable value for -/// @return If variable exist the value of it otherwise nullptr -const char* OS::getWindowsEnvironmentVariable(const char* varname) { - const DWORD bufferLen = 50; - static char buffer[bufferLen]; - if (GetEnvironmentVariableA(varname, buffer, bufferLen)) { - return buffer; - } - return nullptr; -} -#endif // ELPP_OS_WINDOWS -#if ELPP_OS_ANDROID -std::string OS::getProperty(const char* prop) { - char propVal[PROP_VALUE_MAX + 1]; - int ret = __system_property_get(prop, propVal); - return ret == 0 ? std::string() : std::string(propVal); -} - -static std::string OS::getDeviceName(void) { - std::stringstream ss; - std::string manufacturer = getProperty("ro.product.manufacturer"); - std::string model = getProperty("ro.product.model"); - if (manufacturer.empty() || model.empty()) { - return std::string(); - } - ss << manufacturer << "-" << model; - return ss.str(); -} -#endif // ELPP_OS_ANDROID - -const std::string OS::getBashOutput(const char* command) { -#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) - if (command == nullptr) { - return std::string(); - } - FILE* proc = nullptr; - if ((proc = popen(command, "r")) == nullptr) { - ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true); - return std::string(); - } - char hBuff[4096]; - if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) { - pclose(proc); - if (hBuff[strlen(hBuff) - 1] == '\n') { - hBuff[strlen(hBuff) - 1] = '\0'; - } - return std::string(hBuff); - } - return std::string(); -#else - ELPP_UNUSED(command); - return std::string(); -#endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) -} - -std::string OS::getEnvironmentVariable(const char* variableName, const char* defaultVal, - const char* alternativeBashCommand) { -#if ELPP_OS_UNIX - const char* val = getenv(variableName); -#elif ELPP_OS_WINDOWS - const char* val = getWindowsEnvironmentVariable(variableName); -#endif // ELPP_OS_UNIX - if ((val == nullptr) || ((strcmp(val, "") == 0))) { -#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - // Try harder on unix-based systems - std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand); - if (valBash.empty()) { - return std::string(defaultVal); - } else { - return valBash; - } -#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX - ELPP_UNUSED(alternativeBashCommand); - return std::string(defaultVal); -#endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - } - return std::string(val); -} - -std::string OS::currentUser(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownUser); - return std::string("android"); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID -} - -std::string OS::currentHost(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownHost); - return getDeviceName(); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID -} - -bool OS::termSupportsColor(void) { - std::string term = getEnvironmentVariable("TERM", ""); - return term == "xterm" || term == "xterm-color" || term == "xterm-256color" - || term == "screen" || term == "linux" || term == "cygwin" - || term == "screen-256color"; -} - -// DateTime - -void DateTime::gettimeofday(struct timeval* tv) { -#if ELPP_OS_WINDOWS - if (tv != nullptr) { -# if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const unsigned __int64 delta_ = 11644473600000000Ui64; -# else - const unsigned __int64 delta_ = 11644473600000000ULL; -# endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const double secOffSet = 0.000001; - const unsigned long usecOffSet = 1000000; - FILETIME fileTime; - GetSystemTimeAsFileTime(&fileTime); - unsigned __int64 present = 0; - present |= fileTime.dwHighDateTime; - present = present << 32; - present |= fileTime.dwLowDateTime; - present /= 10; // mic-sec - // Subtract the difference - present -= delta_; - tv->tv_sec = static_cast(present * secOffSet); - tv->tv_usec = static_cast(present % usecOffSet); - } -#else - ::gettimeofday(tv, nullptr); -#endif // ELPP_OS_WINDOWS -} - -std::string DateTime::getDateTime(const char* format, const base::SubsecondPrecision* ssPrec) { - struct timeval currTime; - gettimeofday(&currTime); - return timevalToString(currTime, format, ssPrec); -} - -std::string DateTime::timevalToString(struct timeval tval, const char* format, - const el::base::SubsecondPrecision* ssPrec) { - struct ::tm timeInfo; - buildTimeInfo(&tval, &timeInfo); - const int kBuffSize = 30; - char buff_[kBuffSize] = ""; - parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast(tval.tv_usec / ssPrec->m_offset), - ssPrec); - return std::string(buff_); -} - -base::type::string_t DateTime::formatTime(unsigned long long time, base::TimestampUnit timestampUnit) { - base::type::EnumType start = static_cast(timestampUnit); - const base::type::char_t* unit = base::consts::kTimeFormats[start].unit; - for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) { - if (time <= base::consts::kTimeFormats[i].value) { - break; - } - if (base::consts::kTimeFormats[i].value == 1000.0f && time / 1000.0f < 1.9f) { - break; - } - time /= static_cast(base::consts::kTimeFormats[i].value); - unit = base::consts::kTimeFormats[i + 1].unit; - } - base::type::stringstream_t ss; - ss << time << " " << unit; - return ss.str(); -} - -unsigned long long DateTime::getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, - base::TimestampUnit timestampUnit) { - if (timestampUnit == base::TimestampUnit::Microsecond) { - return static_cast(static_cast(1000000 * endTime.tv_sec + endTime.tv_usec) - - static_cast(1000000 * startTime.tv_sec + startTime.tv_usec)); - } - // milliseconds - auto conv = [](const struct timeval& tim) { - return static_cast((tim.tv_sec * 1000) + (tim.tv_usec / 1000)); - }; - return static_cast(conv(endTime) - conv(startTime)); -} - -struct ::tm* DateTime::buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) { -#if ELPP_OS_UNIX - time_t rawTime = currTime->tv_sec; - ::localtime_r(&rawTime, timeInfo); - return timeInfo; -#else -# if ELPP_COMPILER_MSVC - ELPP_UNUSED(currTime); - time_t t; - _time64(&t); - localtime_s(timeInfo, &t); - return timeInfo; -# else - // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method - time_t rawTime = currTime->tv_sec; - struct tm* tmInf = localtime(&rawTime); - *timeInfo = *tmInf; - return timeInfo; -# endif // ELPP_COMPILER_MSVC -#endif // ELPP_OS_UNIX -} - -char* DateTime::parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, - std::size_t msec, const base::SubsecondPrecision* ssPrec) { - const char* bufLim = buf + bufSz; - for (; *format; ++format) { - if (*format == base::consts::kFormatSpecifierChar) { - switch (*++format) { - case base::consts::kFormatSpecifierChar: // Escape - break; - case '\0': // End - --format; - break; - case 'd': // Day - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim); - continue; - case 'a': // Day of week (short) - buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim); - continue; - case 'A': // Day of week (long) - buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim); - continue; - case 'M': // month - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim); - continue; - case 'b': // month (short) - buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim); - continue; - case 'B': // month (long) - buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim); - continue; - case 'y': // year (two digits) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim); - continue; - case 'Y': // year (four digits) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim); - continue; - case 'h': // hour (12-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim); - continue; - case 'H': // hour (24-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim); - continue; - case 'm': // minute - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim); - continue; - case 's': // second - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim); - continue; - case 'z': // subsecond part - case 'g': - buf = base::utils::Str::convertAndAddToBuff(msec, ssPrec->m_width, buf, bufLim); - continue; - case 'F': // AM/PM - buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim); - continue; - default: - continue; - } - } - if (buf == bufLim) break; - *buf++ = *format; - } - return buf; -} - -// CommandLineArgs - -void CommandLineArgs::setArgs(int argc, char** argv) { - m_params.clear(); - m_paramsWithValue.clear(); - if (argc == 0 || argv == nullptr) { - return; - } - m_argc = argc; - m_argv = argv; - for (int i = 1; i < m_argc; ++i) { - const char* v = (strstr(m_argv[i], "=")); - if (v != nullptr && strlen(v) > 0) { - std::string key = std::string(m_argv[i]); - key = key.substr(0, key.find_first_of('=')); - if (hasParamWithValue(key.c_str())) { - ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value [" - << getParamValue(key.c_str()) << "]"); - } else { - m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1))); - } - } - if (v == nullptr) { - if (hasParam(m_argv[i])) { - ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists"); - } else { - m_params.push_back(std::string(m_argv[i])); - } - } - } -} - -bool CommandLineArgs::hasParamWithValue(const char* paramKey) const { - return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end(); -} - -const char* CommandLineArgs::getParamValue(const char* paramKey) const { - return m_paramsWithValue.find(std::string(paramKey))->second.c_str(); -} - -bool CommandLineArgs::hasParam(const char* paramKey) const { - return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end(); -} - -bool CommandLineArgs::empty(void) const { - return m_params.empty() && m_paramsWithValue.empty(); -} - -std::size_t CommandLineArgs::size(void) const { - return m_params.size() + m_paramsWithValue.size(); -} - -base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c) { - for (int i = 1; i < c.m_argc; ++i) { - os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]"); - if (i < c.m_argc - 1) { - os << ELPP_LITERAL(" "); - } - } - return os; -} - -} // namespace utils - -// el::base::threading -namespace threading { - -#if ELPP_THREADING_ENABLED -# if ELPP_USE_STD_THREADING -# if ELPP_ASYNC_LOGGING -static void msleep(int ms) { - // Only when async logging enabled - this is because async is strict on compiler -# if defined(ELPP_NO_SLEEP_FOR) - usleep(ms * 1000); -# else - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); -# endif // defined(ELPP_NO_SLEEP_FOR) -} -# endif // ELPP_ASYNC_LOGGING -# endif // !ELPP_USE_STD_THREADING -#endif // ELPP_THREADING_ENABLED - -} // namespace threading - -// el::base - -// SubsecondPrecision - -void SubsecondPrecision::init(int width) { - if (width < 1 || width > 6) { - width = base::consts::kDefaultSubsecondPrecision; - } - m_width = width; - switch (m_width) { - case 3: - m_offset = 1000; - break; - case 4: - m_offset = 100; - break; - case 5: - m_offset = 10; - break; - case 6: - m_offset = 1; - break; - default: - m_offset = 1000; - break; - } -} - -// LogFormat - -LogFormat::LogFormat(void) : - m_level(Level::Unknown), - m_userFormat(base::type::string_t()), - m_format(base::type::string_t()), - m_dateTimeFormat(std::string()), - m_flags(0x0), - m_currentUser(base::utils::OS::currentUser()), - m_currentHost(base::utils::OS::currentHost()) { -} - -LogFormat::LogFormat(Level level, const base::type::string_t& format) - : m_level(level), m_userFormat(format), m_currentUser(base::utils::OS::currentUser()), - m_currentHost(base::utils::OS::currentHost()) { - parseFromFormat(m_userFormat); -} - -LogFormat::LogFormat(const LogFormat& logFormat): - m_level(logFormat.m_level), - m_userFormat(logFormat.m_userFormat), - m_format(logFormat.m_format), - m_dateTimeFormat(logFormat.m_dateTimeFormat), - m_flags(logFormat.m_flags), - m_currentUser(logFormat.m_currentUser), - m_currentHost(logFormat.m_currentHost) { -} - -LogFormat::LogFormat(LogFormat&& logFormat) { - m_level = std::move(logFormat.m_level); - m_userFormat = std::move(logFormat.m_userFormat); - m_format = std::move(logFormat.m_format); - m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat); - m_flags = std::move(logFormat.m_flags); - m_currentUser = std::move(logFormat.m_currentUser); - m_currentHost = std::move(logFormat.m_currentHost); -} - -LogFormat& LogFormat::operator=(const LogFormat& logFormat) { - if (&logFormat != this) { - m_level = logFormat.m_level; - m_userFormat = logFormat.m_userFormat; - m_dateTimeFormat = logFormat.m_dateTimeFormat; - m_flags = logFormat.m_flags; - m_currentUser = logFormat.m_currentUser; - m_currentHost = logFormat.m_currentHost; - } - return *this; -} - -bool LogFormat::operator==(const LogFormat& other) { - return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format && - m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags; -} - -/// @brief Updates format to be used while logging. -/// @param userFormat User provided format -void LogFormat::parseFromFormat(const base::type::string_t& userFormat) { - // We make copy because we will be changing the format - // i.e, removing user provided date format from original format - // and then storing it. - base::type::string_t formatCopy = userFormat; - m_flags = 0x0; - auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos) { - if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) { - if (hasFlag(flag)) { - // If we already have flag we remove the escape chars so that '%%' is turned to '%' - // even after specifier resolution - this is because we only replaceFirst specifier - formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1); - ++foundAt; - } - } else { - if (!hasFlag(flag)) addFlag(flag); - } - } - }; - conditionalAddFlag(base::consts::kAppNameFormatSpecifier, base::FormatFlags::AppName); - conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, base::FormatFlags::Level); - conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, base::FormatFlags::LevelShort); - conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, base::FormatFlags::LoggerId); - conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, base::FormatFlags::ThreadId); - conditionalAddFlag(base::consts::kLogFileFormatSpecifier, base::FormatFlags::File); - conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, base::FormatFlags::FileBase); - conditionalAddFlag(base::consts::kLogLineFormatSpecifier, base::FormatFlags::Line); - conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, base::FormatFlags::Location); - conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, base::FormatFlags::Function); - conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, base::FormatFlags::User); - conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, base::FormatFlags::Host); - conditionalAddFlag(base::consts::kMessageFormatSpecifier, base::FormatFlags::LogMessage); - conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, base::FormatFlags::VerboseLevel); - // For date/time we need to extract user's date format first - std::size_t dateIndex = std::string::npos; - if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) { - while (dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1); - } - if (dateIndex != std::string::npos) { - addFlag(base::FormatFlags::DateTime); - updateDateFormat(dateIndex, formatCopy); - } - } - m_format = formatCopy; - updateFormatSpec(); -} - -void LogFormat::updateDateFormat(std::size_t index, base::type::string_t& currFormat) { - if (hasFlag(base::FormatFlags::DateTime)) { - index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier); - } - const base::type::char_t* ptr = currFormat.c_str() + index; - if ((currFormat.size() > index) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << static_cast(*ptr); - } - currFormat.erase(index, count); - m_dateTimeFormat = ss.str(); - } else { - // No format provided, use default - if (hasFlag(base::FormatFlags::DateTime)) { - m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat); - } - } -} - -void LogFormat::updateFormatSpec(void) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (m_level == Level::Debug) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kDebugLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kDebugLevelShortLogValue); - } else if (m_level == Level::Info) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kInfoLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kInfoLevelShortLogValue); - } else if (m_level == Level::Warning) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kWarningLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kWarningLevelShortLogValue); - } else if (m_level == Level::Error) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kErrorLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kErrorLevelShortLogValue); - } else if (m_level == Level::Fatal) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kFatalLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kFatalLevelShortLogValue); - } else if (m_level == Level::Verbose) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kVerboseLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kVerboseLevelShortLogValue); - } else if (m_level == Level::Trace) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kTraceLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kTraceLevelShortLogValue); - } - if (hasFlag(base::FormatFlags::User)) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentUserFormatSpecifier, - m_currentUser); - } - if (hasFlag(base::FormatFlags::Host)) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentHostFormatSpecifier, - m_currentHost); - } - // Ignore Level::Global and Level::Unknown -} - -// TypedConfigurations - -TypedConfigurations::TypedConfigurations(Configurations* configurations, - base::LogStreamsReferenceMap* logStreamsReference) { - m_configurations = configurations; - m_logStreamsReference = logStreamsReference; - build(m_configurations); -} - -TypedConfigurations::TypedConfigurations(const TypedConfigurations& other) { - this->m_configurations = other.m_configurations; - this->m_logStreamsReference = other.m_logStreamsReference; - build(m_configurations); -} - -bool TypedConfigurations::enabled(Level level) { - return getConfigByVal(level, &m_enabledMap, "enabled"); -} - -bool TypedConfigurations::toFile(Level level) { - return getConfigByVal(level, &m_toFileMap, "toFile"); -} - -const std::string& TypedConfigurations::filename(Level level) { - return getConfigByRef(level, &m_filenameMap, "filename"); -} - -bool TypedConfigurations::toStandardOutput(Level level) { - return getConfigByVal(level, &m_toStandardOutputMap, "toStandardOutput"); -} - -const base::LogFormat& TypedConfigurations::logFormat(Level level) { - return getConfigByRef(level, &m_logFormatMap, "logFormat"); -} - -const base::SubsecondPrecision& TypedConfigurations::subsecondPrecision(Level level) { - return getConfigByRef(level, &m_subsecondPrecisionMap, "subsecondPrecision"); -} - -const base::MillisecondsWidth& TypedConfigurations::millisecondsWidth(Level level) { - return getConfigByRef(level, &m_subsecondPrecisionMap, "millisecondsWidth"); -} - -bool TypedConfigurations::performanceTracking(Level level) { - return getConfigByVal(level, &m_performanceTrackingMap, "performanceTracking"); -} - -base::type::fstream_t* TypedConfigurations::fileStream(Level level) { - return getConfigByRef(level, &m_fileStreamMap, "fileStream").get(); -} - -std::size_t TypedConfigurations::maxLogFileSize(Level level) { - return getConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); -} - -std::size_t TypedConfigurations::logFlushThreshold(Level level) { - return getConfigByVal(level, &m_logFlushThresholdMap, "logFlushThreshold"); -} - -void TypedConfigurations::build(Configurations* configurations) { - base::threading::ScopedLock scopedLock(lock()); - auto getBool = [] (std::string boolStr) -> bool { // Pass by value for trimming - base::utils::Str::trim(boolStr); - return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1"); - }; - std::vector withFileSizeLimit; - for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { - Configuration* conf = *it; - // We cannot use switch on strong enums because Intel C++ dont support them yet - if (conf->configurationType() == ConfigurationType::Enabled) { - setValue(conf->level(), getBool(conf->value()), &m_enabledMap); - } else if (conf->configurationType() == ConfigurationType::ToFile) { - setValue(conf->level(), getBool(conf->value()), &m_toFileMap); - } else if (conf->configurationType() == ConfigurationType::ToStandardOutput) { - setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap); - } else if (conf->configurationType() == ConfigurationType::Filename) { - // We do not yet configure filename but we will configure in another - // loop. This is because if file cannot be created, we will force ToFile - // to be false. Because configuring logger is not necessarily performance - // sensative operation, we can live with another loop; (by the way this loop - // is not very heavy either) - } else if (conf->configurationType() == ConfigurationType::Format) { - setValue(conf->level(), base::LogFormat(conf->level(), - base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap); - } else if (conf->configurationType() == ConfigurationType::SubsecondPrecision) { - setValue(Level::Global, - base::SubsecondPrecision(static_cast(getULong(conf->value()))), &m_subsecondPrecisionMap); - } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) { - setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap); - } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) { - setValue(conf->level(), static_cast(getULong(conf->value())), &m_maxLogFileSizeMap); -#if !defined(ELPP_NO_DEFAULT_LOG_FILE) - withFileSizeLimit.push_back(conf); -#endif // !defined(ELPP_NO_DEFAULT_LOG_FILE) - } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) { - setValue(conf->level(), static_cast(getULong(conf->value())), &m_logFlushThresholdMap); - } - } - // As mentioned earlier, we will now set filename configuration in separate loop to deal with non-existent files - for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { - Configuration* conf = *it; - if (conf->configurationType() == ConfigurationType::Filename) { - insertFile(conf->level(), conf->value()); - } - } - for (std::vector::iterator conf = withFileSizeLimit.begin(); - conf != withFileSizeLimit.end(); ++conf) { - // This is not unsafe as mutex is locked in currect scope - unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback); - } -} - -unsigned long TypedConfigurations::getULong(std::string confVal) { - bool valid = true; - base::utils::Str::trim(confVal); - valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(), - [](char c) { - return !base::utils::Str::isDigit(c); - }) == confVal.end(); - if (!valid) { - valid = false; - ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]"); - return 0; - } - return atol(confVal.c_str()); -} - -std::string TypedConfigurations::resolveFilename(const std::string& filename) { - std::string resultingFilename = filename; - std::size_t dateIndex = std::string::npos; - std::string dateTimeFormatSpecifierStr = std::string(base::consts::kDateTimeFormatSpecifierForFilename); - if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) { - while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1); - } - if (dateIndex != std::string::npos) { - const char* ptr = resultingFilename.c_str() + dateIndex; - // Goto end of specifier - ptr += dateTimeFormatSpecifierStr.size(); - std::string fmt; - if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << *ptr; - } - resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count); - fmt = ss.str(); - } else { - fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename); - } - base::SubsecondPrecision ssPrec(3); - std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &ssPrec); - base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename - base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now); - } - } - return resultingFilename; -} - -void TypedConfigurations::insertFile(Level level, const std::string& fullFilename) { -#if defined(ELPP_NO_LOG_TO_FILE) - setValue(level, false, &m_toFileMap); - ELPP_UNUSED(fullFilename); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(nullptr))); - return; -#endif - std::string resolvedFilename = resolveFilename(fullFilename); - if (resolvedFilename.empty()) { - std::cerr << "Could not load empty file for logging, please re-check your configurations for level [" - << LevelHelper::convertToString(level) << "]"; - } - std::string filePath = base::utils::File::extractPathFromFilename(resolvedFilename, base::consts::kFilePathSeperator); - if (filePath.size() < resolvedFilename.size()) { - base::utils::File::createPath(filePath); - } - auto create = [&](Level level) { - base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename); - base::type::fstream_t* fs = nullptr; - if (filestreamIter == m_logStreamsReference->end()) { - // We need a completely new stream, nothing to share with - fs = base::utils::File::newFileStream(resolvedFilename); - m_filenameMap.insert(std::make_pair(level, resolvedFilename)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs))); - m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level)))); - } else { - // Woops! we have an existing one, share it! - m_filenameMap.insert(std::make_pair(level, filestreamIter->first)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second))); - fs = filestreamIter->second.get(); - } - if (fs == nullptr) { - // We display bad file error from newFileStream() - ELPP_INTERNAL_ERROR("Setting [TO_FILE] of [" - << LevelHelper::convertToString(level) << "] to FALSE", false); - setValue(level, false, &m_toFileMap); - } - }; - // If we dont have file conf for any level, create it for Level::Global first - // otherwise create for specified level - create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level); -} - -bool TypedConfigurations::unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) { - base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get(); - if (fs == nullptr) { - return true; - } - std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); - std::size_t currFileSize = base::utils::File::getSizeOfFile(fs); - if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) { - std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename"); - ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level [" - << LevelHelper::convertToString(level) << "]"); - fs->close(); - preRollOutCallback(fname.c_str(), currFileSize); - fs->open(fname, std::fstream::out | std::fstream::trunc); - return true; - } - return false; -} - -// RegisteredHitCounters - -bool RegisteredHitCounters::validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->validateHitCounts(n); - bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0); - return result; -} - -/// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one -/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned -bool RegisteredHitCounters::validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - // Do not use validateHitCounts here since we do not want to reset counter here - // Note the >= instead of > because we are incrementing - // after this check - if (counter->hitCounts() >= n) - return true; - counter->increment(); - return false; -} - -/// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one -/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned -bool RegisteredHitCounters::validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->increment(); - // Do not use validateHitCounts here since we do not want to reset counter here - if (counter->hitCounts() <= n) - return true; - return false; -} - -// RegisteredLoggers - -RegisteredLoggers::RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder) : - m_defaultLogBuilder(defaultLogBuilder) { - m_defaultConfigurations.setToDefault(); -} - -Logger* RegisteredLoggers::get(const std::string& id, bool forceCreation) { - base::threading::ScopedLock scopedLock(lock()); - Logger* logger_ = base::utils::Registry::get(id); - if (logger_ == nullptr && forceCreation) { - bool validId = Logger::isValidId(id); - if (!validId) { - ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger."); - return nullptr; - } - logger_ = new Logger(id, m_defaultConfigurations, &m_logStreamsReference); - logger_->m_logBuilder = m_defaultLogBuilder; - registerNew(id, logger_); - LoggerRegistrationCallback* callback = nullptr; - for (const std::pair& h - : m_loggerRegistrationCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(logger_); - } - } - } - return logger_; -} - -bool RegisteredLoggers::remove(const std::string& id) { - if (id == base::consts::kDefaultLoggerId) { - return false; - } - Logger* logger = base::utils::Registry::get(id); - if (logger != nullptr) { - unregister(logger); - } - return true; -} - -void RegisteredLoggers::unsafeFlushAll(void) { - ELPP_INTERNAL_INFO(1, "Flushing all log files"); - for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin(); - it != m_logStreamsReference.end(); ++it) { - if (it->second.get() == nullptr) continue; - it->second->flush(); - } -} - -// VRegistry - -VRegistry::VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags) { -} - -/// @brief Sets verbose level. Accepted range is 0-9 -void VRegistry::setLevel(base::type::VerboseLevel level) { - base::threading::ScopedLock scopedLock(lock()); - if (level > 9) - m_level = base::consts::kMaxVerboseLevel; - else - m_level = level; -} - -void VRegistry::setModules(const char* modules) { - base::threading::ScopedLock scopedLock(lock()); - auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) { - if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev))); - ss.str(std::string("")); - ss << chr; - } - if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx))); - ss.str(std::string("")); - ss << chr; - } - ss << sfx; - }; - auto insert = [&](std::stringstream& ss, base::type::VerboseLevel level) { - if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, *m_pFlags)) { - addSuffix(ss, ".h", nullptr); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".c", ".h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cpp", ".c"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cc", ".cpp"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cxx", ".cc"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".-inl.h", ".cxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hxx", ".-inl.h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hpp", ".hxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hh", ".hpp"); - } - m_modules.insert(std::make_pair(ss.str(), level)); - }; - bool isMod = true; - bool isLevel = false; - std::stringstream ss; - int level = -1; - for (; *modules; ++modules) { - switch (*modules) { - case '=': - isLevel = true; - isMod = false; - break; - case ',': - isLevel = false; - isMod = true; - if (!ss.str().empty() && level != -1) { - insert(ss, static_cast(level)); - ss.str(std::string("")); - level = -1; - } - break; - default: - if (isMod) { - ss << *modules; - } else if (isLevel) { - if (isdigit(*modules)) { - level = static_cast(*modules) - 48; - } - } - break; - } - } - if (!ss.str().empty() && level != -1) { - insert(ss, static_cast(level)); - } -} - -bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char* file) { - base::threading::ScopedLock scopedLock(lock()); - if (m_modules.empty() || file == nullptr) { - return vlevel <= m_level; - } else { - std::map::iterator it = m_modules.begin(); - for (; it != m_modules.end(); ++it) { - if (base::utils::Str::wildCardMatch(file, it->first.c_str())) { - return vlevel <= it->second; - } - } - if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, *m_pFlags)) { - return true; - } - return false; - } -} - -void VRegistry::setFromArgs(const base::utils::CommandLineArgs* commandLineArgs) { - if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") || - commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) { - setLevel(base::consts::kMaxVerboseLevel); - } else if (commandLineArgs->hasParamWithValue("--v")) { - setLevel(static_cast(atoi(commandLineArgs->getParamValue("--v")))); - } else if (commandLineArgs->hasParamWithValue("--V")) { - setLevel(static_cast(atoi(commandLineArgs->getParamValue("--V")))); - } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-vmodule")); - } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-VMODULE")); - } -} - -#if !defined(ELPP_DEFAULT_LOGGING_FLAGS) -# define ELPP_DEFAULT_LOGGING_FLAGS 0x0 -#endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS) -// Storage -#if ELPP_ASYNC_LOGGING -Storage::Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) : -#else -Storage::Storage(const LogBuilderPtr& defaultLogBuilder) : -#endif // ELPP_ASYNC_LOGGING - m_registeredHitCounters(new base::RegisteredHitCounters()), - m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)), - m_flags(ELPP_DEFAULT_LOGGING_FLAGS), - m_vRegistry(new base::VRegistry(0, &m_flags)), -#if ELPP_ASYNC_LOGGING - m_asyncLogQueue(new base::AsyncLogQueue()), - m_asyncDispatchWorker(asyncDispatchWorker), -#endif // ELPP_ASYNC_LOGGING - m_preRollOutCallback(base::defaultPreRollOutCallback) { - // Register default logger - m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId)); - // We register default logger anyway (worse case it's not going to register) just in case - m_registeredLoggers->get("default"); - // Register performance logger and reconfigure format - Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId)); - m_registeredLoggers->get("performance"); - performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg")); - performanceLogger->reconfigure(); -#if defined(ELPP_SYSLOG) - // Register syslog logger and reconfigure format - Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId)); - sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg")); - sysLogLogger->reconfigure(); -#endif // defined(ELPP_SYSLOG) - addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified); -#if ELPP_ASYNC_LOGGING - installLogDispatchCallback(std::string("AsyncLogDispatchCallback")); -#else - installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); -#endif // ELPP_ASYNC_LOGGING -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - installPerformanceTrackingCallback - (std::string("DefaultPerformanceTrackingCallback")); -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized"); -#if ELPP_ASYNC_LOGGING - m_asyncDispatchWorker->start(); -#endif // ELPP_ASYNC_LOGGING -} - -Storage::~Storage(void) { - ELPP_INTERNAL_INFO(4, "Destroying storage"); -#if ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous"); - uninstallLogDispatchCallback(std::string("AsyncLogDispatchCallback")); - installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); - ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker"); - base::utils::safeDelete(m_asyncDispatchWorker); - ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue"); - base::utils::safeDelete(m_asyncLogQueue); -#endif // ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters"); - base::utils::safeDelete(m_registeredHitCounters); - ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers"); - base::utils::safeDelete(m_registeredLoggers); - ELPP_INTERNAL_INFO(5, "Destroying vRegistry"); - base::utils::safeDelete(m_vRegistry); -} - -bool Storage::hasCustomFormatSpecifier(const char* formatSpecifier) { - base::threading::ScopedLock scopedLock(lock()); - return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(), - formatSpecifier) != m_customFormatSpecifiers.end(); -} - -void Storage::installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { - if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) { - return; - } - base::threading::ScopedLock scopedLock(lock()); - m_customFormatSpecifiers.push_back(customFormatSpecifier); -} - -bool Storage::uninstallCustomFormatSpecifier(const char* formatSpecifier) { - base::threading::ScopedLock scopedLock(lock()); - std::vector::iterator it = std::find(m_customFormatSpecifiers.begin(), - m_customFormatSpecifiers.end(), formatSpecifier); - if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) { - m_customFormatSpecifiers.erase(it); - return true; - } - return false; -} - -void Storage::setApplicationArguments(int argc, char** argv) { - m_commandLineArgs.setArgs(argc, argv); - m_vRegistry->setFromArgs(commandLineArgs()); - // default log file -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) { - Configurations c; - c.setGlobally(ConfigurationType::Filename, - std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam))); - registeredLoggers()->setDefaultConfigurations(c); - for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin(); - it != registeredLoggers()->end(); ++it) { - it->second->configure(c); - } - } -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) { - int userInput = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam)); - if (ELPP_DEFAULT_LOGGING_FLAGS == 0x0) { - m_flags = userInput; - } else { - base::utils::addFlag(userInput, &m_flags); - } - } -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) -} - -// DefaultLogDispatchCallback - -void DefaultLogDispatchCallback::handle(const LogDispatchData* data) { - m_data = data; - dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), - m_data->dispatchAction() == base::DispatchAction::NormalLog)); -} - -void DefaultLogDispatchCallback::dispatch(base::type::string_t&& logLine) { - if (m_data->dispatchAction() == base::DispatchAction::NormalLog) { - if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) { - base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream( - m_data->logMessage()->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR("Unable to write log to file [" - << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n" - << "Few possible reasons (could be something else):\n" << " * Permission denied\n" - << " * Disk full\n" << " * Disk is not writable", true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) - || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) { - m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] " - << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " - << m_data->logMessage()->logger()->id() << "]", false); - } - } - if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - } -#if defined(ELPP_SYSLOG) - else if (m_data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (m_data->logMessage()->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (m_data->logMessage()->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (m_data->logMessage()->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (m_data->logMessage()->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (m_data->logMessage()->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -# if defined(ELPP_UNICODE) - char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -# else - syslog(sysLogPriority, "%s", logLine.c_str()); -# endif - } -#endif // defined(ELPP_SYSLOG) -} - -#if ELPP_ASYNC_LOGGING - -// AsyncLogDispatchCallback - -void AsyncLogDispatchCallback::handle(const LogDispatchData* data) { - base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(), - data->dispatchAction() == base::DispatchAction::NormalLog); - if (data->dispatchAction() == base::DispatchAction::NormalLog - && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - // Save resources and only queue if we want to write to file otherwise just ignore handler - if (data->logMessage()->logger()->typedConfigurations()->toFile(data->logMessage()->level())) { - ELPP->asyncLogQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine)); - } -} - -// AsyncDispatchWorker -AsyncDispatchWorker::AsyncDispatchWorker() { - setContinueRunning(false); -} - -AsyncDispatchWorker::~AsyncDispatchWorker() { - setContinueRunning(false); - ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue"); - clean(); - ELPP_INTERNAL_INFO(6, "Log queue cleaned"); -} - -bool AsyncDispatchWorker::clean(void) { - std::mutex m; - std::unique_lock lk(m); - cv.wait(lk, [] { return !ELPP->asyncLogQueue()->empty(); }); - emptyQueue(); - lk.unlock(); - cv.notify_one(); - return ELPP->asyncLogQueue()->empty(); -} - -void AsyncDispatchWorker::emptyQueue(void) { - while (!ELPP->asyncLogQueue()->empty()) { - AsyncLogItem data = ELPP->asyncLogQueue()->next(); - handle(&data); - base::threading::msleep(100); - } -} - -void AsyncDispatchWorker::start(void) { - base::threading::msleep(5000); // 5s (why?) - setContinueRunning(true); - std::thread t1(&AsyncDispatchWorker::run, this); - t1.join(); -} - -void AsyncDispatchWorker::handle(AsyncLogItem* logItem) { - LogDispatchData* data = logItem->data(); - LogMessage* logMessage = logItem->logMessage(); - Logger* logger = logMessage->logger(); - base::TypedConfigurations* conf = logger->typedConfigurations(); - base::type::string_t logLine = logItem->logLine(); - if (data->dispatchAction() == base::DispatchAction::NormalLog) { - if (conf->toFile(logMessage->level())) { - base::type::fstream_t* fs = conf->fileStream(logMessage->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR("Unable to write log to file [" - << conf->filename(logMessage->level()) << "].\n" - << "Few possible reasons (could be something else):\n" << " * Permission denied\n" - << " * Disk full\n" << " * Disk is not writable", true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) { - logger->flush(logMessage->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] " - << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false); - } - } - } -# if defined(ELPP_SYSLOG) - else if (data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (logMessage->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (logMessage->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (logMessage->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (logMessage->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (logMessage->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -# if defined(ELPP_UNICODE) - char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -# else - syslog(sysLogPriority, "%s", logLine.c_str()); -# endif - } -# endif // defined(ELPP_SYSLOG) -} - -void AsyncDispatchWorker::run(void) { - while (continueRunning()) { - emptyQueue(); - base::threading::msleep(10); // 10ms - } -} -#endif // ELPP_ASYNC_LOGGING - -// DefaultLogBuilder - -base::type::string_t DefaultLogBuilder::build(const LogMessage* logMessage, bool appendNewLine) const { - base::TypedConfigurations* tc = logMessage->logger()->typedConfigurations(); - const base::LogFormat* logFormat = &tc->logFormat(logMessage->level()); - base::type::string_t logLine = logFormat->format(); - char buff[base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength] = ""; - const char* bufLim = buff + sizeof(buff); - if (logFormat->hasFlag(base::FormatFlags::AppName)) { - // App name - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kAppNameFormatSpecifier, - logMessage->logger()->parentApplicationName()); - } - if (logFormat->hasFlag(base::FormatFlags::ThreadId)) { - // Thread ID - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kThreadIdFormatSpecifier, - ELPP->getThreadName(base::threading::getCurrentThreadId())); - } - if (logFormat->hasFlag(base::FormatFlags::DateTime)) { - // DateTime - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kDateTimeFormatSpecifier, - base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), - &tc->subsecondPrecision(logMessage->level()))); - } - if (logFormat->hasFlag(base::FormatFlags::Function)) { - // Function - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func()); - } - if (logFormat->hasFlag(base::FormatFlags::File)) { - // File - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::FileBase)) { - // FileBase - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildBaseFilename(logMessage->file(), buff); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Line)) { - // Line - char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength); - buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLineFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Location)) { - // Location - char* buf = base::utils::Str::clearBuff(buff, - base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - buf = base::utils::Str::addToBuff(buff, buf, bufLim); - buf = base::utils::Str::addToBuff(":", buf, bufLim); - buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, - false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff)); - } - if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) { - // Verbose level - char* buf = base::utils::Str::clearBuff(buff, 1); - buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::LogMessage)) { - // Log message - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message()); - } -#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - for (std::vector::const_iterator it = ELPP->customFormatSpecifiers()->begin(); - it != ELPP->customFormatSpecifiers()->end(); ++it) { - std::string fs(it->formatSpecifier()); - base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end()); - base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, it->resolver()(logMessage)); - } -#endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - if (appendNewLine) logLine += ELPP_LITERAL("\n"); - return logLine; -} - -// LogDispatcher - -void LogDispatcher::dispatch(void) { - if (m_proceed && m_dispatchAction == base::DispatchAction::None) { - m_proceed = false; - } - if (!m_proceed) { - return; - } - base::threading::ScopedLock scopedLock(ELPP->lock()); - base::TypedConfigurations* tc = m_logMessage.logger()->m_typedConfigurations; - if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) { - tc->validateFileRolling(m_logMessage.level(), ELPP->preRollOutCallback()); - } - LogDispatchCallback* callback = nullptr; - LogDispatchData data; - for (const std::pair& h - : ELPP->m_logDispatchCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - data.setLogMessage(&m_logMessage); - data.setDispatchAction(m_dispatchAction); - callback->handle(&data); - } - } -} - -// MessageBuilder - -void MessageBuilder::initialize(Logger* logger) { - m_logger = logger; - m_containerLogSeperator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ? - ELPP_LITERAL("\n ") : ELPP_LITERAL(", "); -} - -MessageBuilder& MessageBuilder::operator<<(const wchar_t* msg) { - if (msg == nullptr) { - m_logger->stream() << base::consts::kNullPointer; - return *this; - } -# if defined(ELPP_UNICODE) - m_logger->stream() << msg; -# else - char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg); - m_logger->stream() << buff_; - free(buff_); -# endif - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; -} - -// Writer - -Writer& Writer::construct(Logger* logger, bool needLock) { - m_logger = logger; - initializeLogger(logger->id(), false, needLock); - m_messageBuilder.initialize(m_logger); - return *this; -} - -Writer& Writer::construct(int count, const char* loggerIds, ...) { - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - va_list loggersList; - va_start(loggersList, loggerIds); - const char* id = loggerIds; - for (int i = 0; i < count; ++i) { - m_loggerIds.push_back(std::string(id)); - id = va_arg(loggersList, const char*); - } - va_end(loggersList); - initializeLogger(m_loggerIds.at(0)); - } else { - initializeLogger(std::string(loggerIds)); - } - m_messageBuilder.initialize(m_logger); - return *this; -} - -void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) { - if (lookup) { - m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); - } - if (m_logger == nullptr) { - ELPP->acquireLock(); - if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) { - // Somehow default logger has been unregistered. Not good! Register again - ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId)); - } - ELPP->releaseLock(); // Need to unlock it for next writer - Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) - << "Logger [" << loggerId << "] is not registered yet!"; - m_proceed = false; - } else { - if (needLock) { - m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because - // m_proceed can be changed by lines below - } - if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) { - m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) : - LevelHelper::castToInt(m_level) >= LevelHelper::castToInt(ELPP->m_loggingLevel); - } else { - m_proceed = m_logger->enabled(m_level); - } - } -} - -void Writer::processDispatch() { -#if ELPP_LOGGING_ENABLED - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - bool firstDispatched = false; - base::type::string_t logMessage; - std::size_t i = 0; - do { - if (m_proceed) { - if (firstDispatched) { - m_logger->stream() << logMessage; - } else { - firstDispatched = true; - if (m_loggerIds.size() > 1) { - logMessage = m_logger->stream().str(); - } - } - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (i + 1 < m_loggerIds.size()) { - initializeLogger(m_loggerIds.at(i + 1)); - } - } while (++i < m_loggerIds.size()); - } else { - if (m_proceed) { - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - } -#else - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } -#endif // ELPP_LOGGING_ENABLED -} - -void Writer::triggerDispatch(void) { - if (m_proceed) { - base::LogDispatcher(m_proceed, LogMessage(m_level, m_file, m_line, m_func, m_verboseLevel, - m_logger), m_dispatchAction).dispatch(); - } - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (m_proceed && m_level == Level::Fatal - && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) { - base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) - << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]"; - std::stringstream reasonStream; - reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" - << " If you wish to disable 'abort on fatal log' please use " - << "el::Helpers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)"; - base::utils::abort(1, reasonStream.str()); - } - m_proceed = false; -} - -// PErrorWriter - -PErrorWriter::~PErrorWriter(void) { - if (m_proceed) { -#if ELPP_COMPILER_MSVC - char buff[256]; - strerror_s(buff, 256, errno); - m_logger->stream() << ": " << buff << " [" << errno << "]"; -#else - m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]"; -#endif - } -} - -// PerformanceTracker - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -PerformanceTracker::PerformanceTracker(const std::string& blockName, - base::TimestampUnit timestampUnit, - const std::string& loggerId, - bool scopedLog, Level level) : - m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog), - m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - // We store it locally so that if user happen to change configuration by the end of scope - // or before calling checkpoint, we still depend on state of configuraton at time of construction - el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false); - m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level); - if (m_enabled) { - base::utils::DateTime::gettimeofday(&m_startTime); - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED -} - -PerformanceTracker::~PerformanceTracker(void) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - if (m_scopedLog) { - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = getFormattedTimeTaken(); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete); - data.init(this); - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback* callback = nullptr; - for (const std::pair& h - : ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(&data); - } - } - } - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) -} - -void PerformanceTracker::checkpoint(const std::string& id, const char* file, base::type::LineNumber line, - const char* func) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL(""); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint); - data.init(this); - data.m_checkpointId = id; - data.m_file = file; - data.m_line = line; - data.m_func = func; - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback* callback = nullptr; - for (const std::pair& h - : ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(&data); - } - } - base::utils::DateTime::gettimeofday(&m_lastCheckpointTime); - m_hasChecked = true; - m_lastCheckpointId = id; - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - ELPP_UNUSED(id); - ELPP_UNUSED(file); - ELPP_UNUSED(line); - ELPP_UNUSED(func); -} - -const base::type::string_t PerformanceTracker::getFormattedTimeTaken(struct timeval startTime) const { - if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) { - base::type::stringstream_t ss; - ss << base::utils::DateTime::getTimeDifference(m_endTime, - startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast - (m_timestampUnit)].unit; - return ss.str(); - } - return base::utils::DateTime::formatTime(base::utils::DateTime::getTimeDifference(m_endTime, - startTime, m_timestampUnit), m_timestampUnit); -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -namespace debug { -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -// StackTrace - -StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, - const char* addr) { - m_index = index; - m_location = std::string(loc); - m_demangled = std::string(demang); - m_hex = std::string(hex); - m_addr = std::string(addr); -} - -std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) { - ss << "[" << si.m_index << "] " << si.m_location << (si.m_demangled.empty() ? "" : ":") << si.m_demangled - << (si.m_hex.empty() ? "" : "+") << si.m_hex << si.m_addr; - return ss; -} - -std::ostream& operator<<(std::ostream& os, const StackTrace& st) { - std::vector::const_iterator it = st.m_stack.begin(); - while (it != st.m_stack.end()) { - os << " " << *it++ << "\n"; - } - return os; -} - -void StackTrace::generateNew(void) { -#if ELPP_STACKTRACE - m_stack.clear(); - void* stack[kMaxStack]; - unsigned int size = backtrace(stack, kMaxStack); - char** strings = backtrace_symbols(stack, size); - if (size > kStackStart) { // Skip StackTrace c'tor and generateNew - for (std::size_t i = kStackStart; i < size; ++i) { - char* mangName = nullptr; - char* hex = nullptr; - char* addr = nullptr; - for (char* c = strings[i]; *c; ++c) { - switch (*c) { - case '(': - mangName = c; - break; - case '+': - hex = c; - break; - case ')': - addr = c; - break; - default: - break; - } - } - // Perform demangling if parsed properly - if (mangName != nullptr && hex != nullptr && addr != nullptr && mangName < hex) { - *mangName++ = '\0'; - *hex++ = '\0'; - *addr++ = '\0'; - int status = 0; - char* demangName = abi::__cxa_demangle(mangName, 0, 0, &status); - // if demangling is successful, output the demangled function name - if (status == 0) { - // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html) - StackTraceEntry entry(i - 1, strings[i], demangName, hex, addr); - m_stack.push_back(entry); - } else { - // Not successful - we will use mangled name - StackTraceEntry entry(i - 1, strings[i], mangName, hex, addr); - m_stack.push_back(entry); - } - free(demangName); - } else { - StackTraceEntry entry(i - 1, strings[i]); - m_stack.push_back(entry); - } - } - } - free(strings); -#else - ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler"); -#endif // ELPP_STACKTRACE -} - -// Static helper functions - -static std::string crashReason(int sig) { - std::stringstream ss; - bool foundReason = false; - for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) { - if (base::consts::kCrashSignals[i].numb == sig) { - ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal"; - if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) { - ss << std::endl << - " " << base::consts::kCrashSignals[i].brief << std::endl << - " " << base::consts::kCrashSignals[i].detail; - } - foundReason = true; - } - } - if (!foundReason) { - ss << "Application has crashed due to unknown signal [" << sig << "]"; - } - return ss.str(); -} -/// @brief Logs reason of crash from sig -static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { - std::stringstream ss; - ss << "CRASH HANDLED; "; - ss << crashReason(sig); -#if ELPP_STACKTRACE - if (stackTraceIfAvailable) { - ss << std::endl << " ======= Backtrace: =========" << std::endl << base::debug::StackTrace(); - } -#else - ELPP_UNUSED(stackTraceIfAvailable); -#endif // ELPP_STACKTRACE - ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, logger) << ss.str(); -} - -static inline void crashAbort(int sig) { - base::utils::abort(sig, std::string()); -} - -/// @brief Default application crash handler -/// -/// @detail This function writes log using 'default' logger, prints stack trace for GCC based compilers and aborts program. -static inline void defaultCrashHandler(int sig) { - base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId); - base::debug::crashAbort(sig); -} - -// CrashHandler - -CrashHandler::CrashHandler(bool useDefault) { - if (useDefault) { - setHandler(defaultCrashHandler); - } -} - -void CrashHandler::setHandler(const Handler& cHandler) { - m_handler = cHandler; -#if defined(ELPP_HANDLE_SIGABRT) - int i = 0; // SIGABRT is at base::consts::kCrashSignals[0] -#else - int i = 1; -#endif // defined(ELPP_HANDLE_SIGABRT) - for (; i < base::consts::kCrashSignalsCount; ++i) { - m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler); - } -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -} // namespace debug -} // namespace base - -// el - -// Helpers - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -void Helpers::crashAbort(int sig, const char* sourceFile, unsigned int long line) { - std::stringstream ss; - ss << base::debug::crashReason(sig).c_str(); - ss << " - [Called el::Helpers::crashAbort(" << sig << ")]"; - if (sourceFile != nullptr && strlen(sourceFile) > 0) { - ss << " - Source: " << sourceFile; - if (line > 0) - ss << ":" << line; - else - ss << " (line number not specified)"; - } - base::utils::abort(sig, ss.str()); -} - -void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { - el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger); -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -// Loggers - -Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) { - base::threading::ScopedLock scopedLock(ELPP->lock()); - return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); -} - -void Loggers::setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr) { - ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr); -} - -bool Loggers::unregisterLogger(const std::string& identity) { - base::threading::ScopedLock scopedLock(ELPP->lock()); - return ELPP->registeredLoggers()->remove(identity); -} - -bool Loggers::hasLogger(const std::string& identity) { - base::threading::ScopedLock scopedLock(ELPP->lock()); - return ELPP->registeredLoggers()->has(identity); -} - -Logger* Loggers::reconfigureLogger(Logger* logger, const Configurations& configurations) { - if (!logger) return nullptr; - logger->configure(configurations); - return logger; -} - -Logger* Loggers::reconfigureLogger(const std::string& identity, const Configurations& configurations) { - return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations); -} - -Logger* Loggers::reconfigureLogger(const std::string& identity, ConfigurationType configurationType, - const std::string& value) { - Logger* logger = Loggers::getLogger(identity); - if (logger == nullptr) { - return nullptr; - } - logger->configurations()->set(Level::Global, configurationType, value); - logger->reconfigure(); - return logger; -} - -void Loggers::reconfigureAllLoggers(const Configurations& configurations) { - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Loggers::reconfigureLogger(it->second, configurations); - } -} - -void Loggers::reconfigureAllLoggers(Level level, ConfigurationType configurationType, - const std::string& value) { - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Logger* logger = it->second; - logger->configurations()->set(level, configurationType, value); - logger->reconfigure(); - } -} - -void Loggers::setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers) { - ELPP->registeredLoggers()->setDefaultConfigurations(configurations); - if (reconfigureExistingLoggers) { - Loggers::reconfigureAllLoggers(configurations); - } -} - -const Configurations* Loggers::defaultConfigurations(void) { - return ELPP->registeredLoggers()->defaultConfigurations(); -} - -const base::LogStreamsReferenceMap* Loggers::logStreamsReference(void) { - return ELPP->registeredLoggers()->logStreamsReference(); -} - -base::TypedConfigurations Loggers::defaultTypedConfigurations(void) { - return base::TypedConfigurations( - ELPP->registeredLoggers()->defaultConfigurations(), - ELPP->registeredLoggers()->logStreamsReference()); -} - -std::vector* Loggers::populateAllLoggerIds(std::vector* targetList) { - targetList->clear(); - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin(); - it != ELPP->registeredLoggers()->list().end(); ++it) { - targetList->push_back(it->first); - } - return targetList; -} - -void Loggers::configureFromGlobal(const char* globalConfigurationFilePath) { - std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in); - ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath - << "] for parsing."); - std::string line = std::string(); - std::stringstream ss; - Logger* logger = nullptr; - auto configure = [&](void) { - ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str() - << "\n--------------"); - Configurations c; - c.parseFromText(ss.str()); - logger->configure(c); - }; - while (gcfStream.good()) { - std::getline(gcfStream, line); - ELPP_INTERNAL_INFO(1, "Parsing line: " << line); - base::utils::Str::trim(line); - if (Configurations::Parser::isComment(line)) continue; - Configurations::Parser::ignoreComments(&line); - base::utils::Str::trim(line); - if (line.size() > 2 && base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLoggerId))) { - if (!ss.str().empty() && logger != nullptr) { - configure(); - } - ss.str(std::string("")); - line = line.substr(2); - base::utils::Str::trim(line); - if (line.size() > 1) { - ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'"); - logger = getLogger(line); - } - } else { - ss << line << "\n"; - } - } - if (!ss.str().empty() && logger != nullptr) { - configure(); - } -} - -bool Loggers::configureFromArg(const char* argKey) { -#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - ELPP_UNUSED(argKey); -#else - if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) { - return false; - } - configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey)); -#endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - return true; -} - -void Loggers::flushAll(void) { - ELPP->registeredLoggers()->flushAll(); -} - -void Loggers::setVerboseLevel(base::type::VerboseLevel level) { - ELPP->vRegistry()->setLevel(level); -} - -base::type::VerboseLevel Loggers::verboseLevel(void) { - return ELPP->vRegistry()->level(); -} - -void Loggers::setVModules(const char* modules) { - if (ELPP->vRegistry()->vModulesEnabled()) { - ELPP->vRegistry()->setModules(modules); - } -} - -void Loggers::clearVModules(void) { - ELPP->vRegistry()->clearModules(); -} - -// VersionInfo - -const std::string VersionInfo::version(void) { - return std::string("9.94.1"); -} -/// @brief Release date of current version -const std::string VersionInfo::releaseDate(void) { - return std::string("25-02-2017 0813hrs"); -} - -} // namespace el diff --git a/internal/easylogging++.h b/internal/easylogging++.h deleted file mode 100644 index 1bb51ca..0000000 --- a/internal/easylogging++.h +++ /dev/null @@ -1,4579 +0,0 @@ -// -// Bismillah ar-Rahmaan ar-Raheem -// -// Easylogging++ v9.94.1 -// Single-header only, cross-platform logging library for C++ applications -// -// Copyright (c) 2017 muflihun.com -// -// This library is released under the MIT Licence. -// http://labs.muflihun.com/easyloggingpp/licence.php -// -// https://github.com/muflihun/easyloggingpp -// https://muflihun.github.io/easyloggingpp -// http://muflihun.com -// -#ifndef EASYLOGGINGPP_H -#define EASYLOGGINGPP_H -// Compilers and C++0x/C++11 Evaluation -#if __cplusplus >= 201103L -# define ELPP_CXX11 1 -#endif // __cplusplus >= 201103L -#if (defined(__GNUC__)) -# define ELPP_COMPILER_GCC 1 -#else -# define ELPP_COMPILER_GCC 0 -#endif -#if ELPP_COMPILER_GCC -# define ELPP_GCC_VERSION (__GNUC__ * 10000 \ -+ __GNUC_MINOR__ * 100 \ -+ __GNUC_PATCHLEVEL__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ELPP_CXX0X 1 -# endif -#endif -// Visual C++ -#if defined(_MSC_VER) -# define ELPP_COMPILER_MSVC 1 -#else -# define ELPP_COMPILER_MSVC 0 -#endif -#define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC -#if ELPP_COMPILER_MSVC -# if (_MSC_VER == 1600) -# define ELPP_CXX0X 1 -# elif(_MSC_VER >= 1700) -# define ELPP_CXX11 1 -# endif -#endif -// Clang++ -#if (defined(__clang__) && (__clang__ == 1)) -# define ELPP_COMPILER_CLANG 1 -#else -# define ELPP_COMPILER_CLANG 0 -#endif -#if ELPP_COMPILER_CLANG -# if __has_include() -# include // Make __GLIBCXX__ defined when using libstdc++ -# if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 -# define ELPP_CLANG_SUPPORTS_THREAD -# endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 -# endif // __has_include() -#endif -#if (defined(__MINGW32__) || defined(__MINGW64__)) -# define ELPP_MINGW 1 -#else -# define ELPP_MINGW 0 -#endif -#if (defined(__CYGWIN__) && (__CYGWIN__ == 1)) -# define ELPP_CYGWIN 1 -#else -# define ELPP_CYGWIN 0 -#endif -#if (defined(__INTEL_COMPILER)) -# define ELPP_COMPILER_INTEL 1 -#else -# define ELPP_COMPILER_INTEL 0 -#endif -// Operating System Evaluation -// Windows -#if (defined(_WIN32) || defined(_WIN64)) -# define ELPP_OS_WINDOWS 1 -#else -# define ELPP_OS_WINDOWS 0 -#endif -// Linux -#if (defined(__linux) || defined(__linux__)) -# define ELPP_OS_LINUX 1 -#else -# define ELPP_OS_LINUX 0 -#endif -#if (defined(__APPLE__)) -# define ELPP_OS_MAC 1 -#else -# define ELPP_OS_MAC 0 -#endif -#if (defined(__FreeBSD__)) -# define ELPP_OS_FREEBSD 1 -#else -# define ELPP_OS_FREEBSD 0 -#endif -#if (defined(__sun)) -# define ELPP_OS_SOLARIS 1 -#else -# define ELPP_OS_SOLARIS 0 -#endif -// Unix -#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!ELPP_OS_WINDOWS)) -# define ELPP_OS_UNIX 1 -#else -# define ELPP_OS_UNIX 0 -#endif -#if (defined(__ANDROID__)) -# define ELPP_OS_ANDROID 1 -#else -# define ELPP_OS_ANDROID 0 -#endif -// Evaluating Cygwin as *nix OS -#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN -# undef ELPP_OS_UNIX -# undef ELPP_OS_LINUX -# define ELPP_OS_UNIX 1 -# define ELPP_OS_LINUX 1 -#endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN -#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO) -# define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR) -# define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL) -# define ELPP_INTERNAL_DEBUGGING_ENDL std::endl -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_MSG) -# define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -// Internal Assertions and errors -#if !defined(ELPP_DISABLE_ASSERT) -# if (defined(ELPP_DEBUG_ASSERT_FAILURE)) -# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ -std::stringstream internalInfoStream; internalInfoStream << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ -<< "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \ -<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \ -"ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); } -# else -# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ -std::stringstream internalInfoStream; internalInfoStream << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR\ -<< "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \ -<< __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \ -<< ELPP_INTERNAL_DEBUGGING_ENDL; } -# endif // (defined(ELPP_DEBUG_ASSERT_FAILURE)) -#else -# define ELPP_ASSERT(x, y) -#endif //(!defined(ELPP_DISABLE_ASSERT) -#if ELPP_COMPILER_MSVC -# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ -{ char buff[256]; strerror_s(buff, 256, errno); \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0 -#else -# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0 -#endif // ELPP_COMPILER_MSVC -#if defined(ELPP_DEBUG_ERRORS) -# if !defined(ELPP_INTERNAL_ERROR) -# define ELPP_INTERNAL_ERROR(msg, pe) { \ -std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ -<< "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \ -<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \ -if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0 -# endif -#else -# undef ELPP_INTERNAL_INFO -# define ELPP_INTERNAL_ERROR(msg, pe) -#endif // defined(ELPP_DEBUG_ERRORS) -#if (defined(ELPP_DEBUG_INFO)) -# if !(defined(ELPP_INTERNAL_INFO_LEVEL)) -# define ELPP_INTERNAL_INFO_LEVEL 9 -# endif // !(defined(ELPP_INTERNAL_INFO_LEVEL)) -# if !defined(ELPP_INTERNAL_INFO) -# define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \ -std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \ -<< ELPP_INTERNAL_DEBUGGING_ENDL; }} -# endif -#else -# undef ELPP_INTERNAL_INFO -# define ELPP_INTERNAL_INFO(lvl, msg) -#endif // (defined(ELPP_DEBUG_INFO)) -#if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) -# if (ELPP_COMPILER_GCC && !ELPP_MINGW) -# define ELPP_STACKTRACE 1 -# else -# if ELPP_COMPILER_MSVC -# pragma message("Stack trace not available for this compiler") -# else -# warning "Stack trace not available for this compiler"; -# endif // ELPP_COMPILER_MSVC -# define ELPP_STACKTRACE 0 -# endif // ELPP_COMPILER_GCC -#else -# define ELPP_STACKTRACE 0 -#endif // (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) -// Miscellaneous macros -#define ELPP_UNUSED(x) (void)x -#if ELPP_OS_UNIX -// Log file permissions for unix-based systems -# define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH -#endif // ELPP_OS_UNIX -#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC -# if defined(ELPP_EXPORT_SYMBOLS) -# define ELPP_EXPORT __declspec(dllexport) -# else -# define ELPP_EXPORT __declspec(dllimport) -# endif // defined(ELPP_EXPORT_SYMBOLS) -#else -# define ELPP_EXPORT -#endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC -// Some special functions that are VC++ specific -#undef STRTOK -#undef STRERROR -#undef STRCAT -#undef STRCPY -#if ELPP_CRT_DBG_WARNINGS -# define STRTOK(a, b, c) strtok_s(a, b, c) -# define STRERROR(a, b, c) strerror_s(a, b, c) -# define STRCAT(a, b, len) strcat_s(a, len, b) -# define STRCPY(a, b, len) strcpy_s(a, len, b) -#else -# define STRTOK(a, b, c) strtok(a, b) -# define STRERROR(a, b, c) strerror(c) -# define STRCAT(a, b, len) strcat(a, b) -# define STRCPY(a, b, len) strcpy(a, b) -#endif -// Compiler specific support evaluations -#if (ELPP_MINGW && !defined(ELPP_FORCE_USE_STD_THREAD)) -# define ELPP_USE_STD_THREADING 0 -#else -# if ((ELPP_COMPILER_CLANG && defined(ELPP_CLANG_SUPPORTS_THREAD)) || \ - (!ELPP_COMPILER_CLANG && defined(ELPP_CXX11)) || \ - defined(ELPP_FORCE_USE_STD_THREAD)) -# define ELPP_USE_STD_THREADING 1 -# else -# define ELPP_USE_STD_THREADING 0 -# endif -#endif -#undef ELPP_FINAL -#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) -# define ELPP_FINAL -#else -# define ELPP_FINAL final -#endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) -#if defined(ELPP_EXPERIMENTAL_ASYNC) -# define ELPP_ASYNC_LOGGING 1 -#else -# define ELPP_ASYNC_LOGGING 0 -#endif // defined(ELPP_EXPERIMENTAL_ASYNC) -#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING -# define ELPP_THREADING_ENABLED 1 -#else -# define ELPP_THREADING_ENABLED 0 -#endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING -// Function macro ELPP_FUNC -#undef ELPP_FUNC -#if ELPP_COMPILER_MSVC // Visual C++ -# define ELPP_FUNC __FUNCSIG__ -#elif ELPP_COMPILER_GCC // GCC -# define ELPP_FUNC __PRETTY_FUNCTION__ -#elif ELPP_COMPILER_INTEL // Intel C++ -# define ELPP_FUNC __PRETTY_FUNCTION__ -#elif ELPP_COMPILER_CLANG // Clang++ -# define ELPP_FUNC __PRETTY_FUNCTION__ -#else -# if defined(__func__) -# define ELPP_FUNC __func__ -# else -# define ELPP_FUNC "" -# endif // defined(__func__) -#endif // defined(_MSC_VER) -#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED -// Keep following line commented until features are fixed -#define ELPP_VARIADIC_TEMPLATES_SUPPORTED \ -(ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)) -// Logging Enable/Disable macros -#define ELPP_LOGGING_ENABLED (!defined(ELPP_DISABLE_LOGS)) -#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) -# define ELPP_DEBUG_LOG 1 -#else -# define ELPP_DEBUG_LOG 0 -#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) -#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_INFO_LOG 1 -#else -# define ELPP_INFO_LOG 0 -#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_WARNING_LOG 1 -#else -# define ELPP_WARNING_LOG 0 -#endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_ERROR_LOG 1 -#else -# define ELPP_ERROR_LOG 0 -#endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_FATAL_LOG 1 -#else -# define ELPP_FATAL_LOG 0 -#endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_TRACE_LOG 1 -#else -# define ELPP_TRACE_LOG 0 -#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_VERBOSE_LOG 1 -#else -# define ELPP_VERBOSE_LOG 0 -#endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!(ELPP_CXX0X || ELPP_CXX11)) -# error "C++0x (or higher) support not detected! (Is `-std=c++11' missing?)" -#endif // (!(ELPP_CXX0X || ELPP_CXX11)) -// Headers -#if defined(ELPP_SYSLOG) -# include -#endif // defined(ELPP_SYSLOG) -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(ELPP_UNICODE) -# include -# if ELPP_OS_WINDOWS -# include -# endif // ELPP_OS_WINDOWS -#endif // defined(ELPP_UNICODE) -#if ELPP_STACKTRACE -# include -# include -#endif // ELPP_STACKTRACE -#if ELPP_OS_ANDROID -# include -#endif // ELPP_OS_ANDROID -#if ELPP_OS_UNIX -# include -# include -#elif ELPP_OS_WINDOWS -# include -# include -# if defined(WIN32_LEAN_AND_MEAN) -# if defined(ELPP_WINSOCK2) -# include -# else -# include -# endif // defined(ELPP_WINSOCK2) -# endif // defined(WIN32_LEAN_AND_MEAN) -#endif // ELPP_OS_UNIX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if ELPP_THREADING_ENABLED -# if ELPP_USE_STD_THREADING -# include -# include -# else -# if ELPP_OS_UNIX -# include -# endif // ELPP_OS_UNIX -# endif // ELPP_USE_STD_THREADING -#endif // ELPP_THREADING_ENABLED -#if ELPP_ASYNC_LOGGING -# if defined(ELPP_NO_SLEEP_FOR) -# include -# endif // defined(ELPP_NO_SLEEP_FOR) -# include -# include -# include -#endif // ELPP_ASYNC_LOGGING -#if defined(ELPP_STL_LOGGING) -// For logging STL based templates -# include -# include -# include -# include -# include -# include -# if defined(ELPP_LOG_STD_ARRAY) -# include -# endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_MAP) -# include -# endif // defined(ELPP_LOG_UNORDERED_MAP) -# if defined(ELPP_LOG_UNORDERED_SET) -# include -# endif // defined(ELPP_UNORDERED_SET) -#endif // defined(ELPP_STL_LOGGING) -#if defined(ELPP_QT_LOGGING) -// For logging Qt based classes & templates -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif // defined(ELPP_QT_LOGGING) -#if defined(ELPP_BOOST_LOGGING) -// For logging boost based classes & templates -# include -# include -# include -# include -# include -# include -# include -# include -#endif // defined(ELPP_BOOST_LOGGING) -#if defined(ELPP_WXWIDGETS_LOGGING) -// For logging wxWidgets based classes & templates -# include -#endif // defined(ELPP_WXWIDGETS_LOGGING) -// Forward declarations -namespace el { -class Logger; -class LogMessage; -class PerformanceTrackingData; -class Loggers; -class Helpers; -template class Callback; -class LogDispatchCallback; -class PerformanceTrackingCallback; -class LoggerRegistrationCallback; -class LogDispatchData; -namespace base { -class Storage; -class RegisteredLoggers; -class PerformanceTracker; -class MessageBuilder; -class Writer; -class PErrorWriter; -class LogDispatcher; -class DefaultLogBuilder; -class DefaultLogDispatchCallback; -#if ELPP_ASYNC_LOGGING -class AsyncLogDispatchCallback; -class AsyncDispatchWorker; -#endif // ELPP_ASYNC_LOGGING -class DefaultPerformanceTrackingCallback; -} // namespace base -} // namespace el -/// @brief Easylogging++ entry namespace -namespace el { -/// @brief Namespace containing base/internal functionality used by Easylogging++ -namespace base { -/// @brief Data types used by Easylogging++ -namespace type { -#undef ELPP_LITERAL -#undef ELPP_STRLEN -#undef ELPP_COUT -#if defined(ELPP_UNICODE) -# define ELPP_LITERAL(txt) L##txt -# define ELPP_STRLEN wcslen -# if defined ELPP_CUSTOM_COUT -# define ELPP_COUT ELPP_CUSTOM_COUT -# else -# define ELPP_COUT std::wcout -# endif // defined ELPP_CUSTOM_COUT -typedef wchar_t char_t; -typedef std::wstring string_t; -typedef std::wstringstream stringstream_t; -typedef std::wfstream fstream_t; -typedef std::wostream ostream_t; -#else -# define ELPP_LITERAL(txt) txt -# define ELPP_STRLEN strlen -# if defined ELPP_CUSTOM_COUT -# define ELPP_COUT ELPP_CUSTOM_COUT -# else -# define ELPP_COUT std::cout -# endif // defined ELPP_CUSTOM_COUT -typedef char char_t; -typedef std::string string_t; -typedef std::stringstream stringstream_t; -typedef std::fstream fstream_t; -typedef std::ostream ostream_t; -#endif // defined(ELPP_UNICODE) -#if defined(ELPP_CUSTOM_COUT_LINE) -# define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine) -#else -# define ELPP_COUT_LINE(logLine) logLine << std::flush -#endif // defined(ELPP_CUSTOM_COUT_LINE) -typedef unsigned int EnumType; -typedef unsigned short VerboseLevel; -typedef unsigned long int LineNumber; -typedef std::shared_ptr StoragePointer; -typedef std::shared_ptr LogDispatchCallbackPtr; -typedef std::shared_ptr PerformanceTrackingCallbackPtr; -typedef std::shared_ptr LoggerRegistrationCallbackPtr; -typedef std::unique_ptr PerformanceTrackerPtr; -} // namespace type -/// @brief Internal helper class that prevent copy constructor for class -/// -/// @detail When using this class simply inherit it privately -class NoCopy { - protected: - NoCopy(void) {} - private: - NoCopy(const NoCopy&); - NoCopy& operator=(const NoCopy&); -}; -/// @brief Internal helper class that makes all default constructors private. -/// -/// @detail This prevents initializing class making it static unless an explicit constructor is declared. -/// When using this class simply inherit it privately -class StaticClass { - private: - StaticClass(void); - StaticClass(const StaticClass&); - StaticClass& operator=(const StaticClass&); -}; -} // namespace base -/// @brief Represents enumeration for severity level used to determine level of logging -/// -/// @detail With Easylogging++, developers may disable or enable any level regardless of -/// what the severity is. Or they can choose to log using hierarchical logging flag -enum class Level : base::type::EnumType { - /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels - Global = 1, - /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs. - Trace = 2, - /// @brief Informational events most useful for developers to debug application - Debug = 4, - /// @brief Severe error information that will presumably abort application - Fatal = 8, - /// @brief Information representing errors in application but application will keep running - Error = 16, - /// @brief Useful when application has potentially harmful situtaions - Warning = 32, - /// @brief Information that can be highly useful and vary with verbose logging level. - Verbose = 64, - /// @brief Mainly useful to represent current progress of application - Info = 128, - /// @brief Represents unknown level - Unknown = 1010 -}; -/// @brief Static class that contains helper functions for el::Level -class LevelHelper : base::StaticClass { - public: - /// @brief Represents minimum valid level. Useful when iterating through enum. - static const base::type::EnumType kMinValid = static_cast(Level::Trace); - /// @brief Represents maximum valid level. This is used internally and you should not need it. - static const base::type::EnumType kMaxValid = static_cast(Level::Info); - /// @brief Casts level to int, useful for iterating through enum. - static base::type::EnumType castToInt(Level level) { - return static_cast(level); - } - /// @brief Casts int(ushort) to level, useful for iterating through enum. - static Level castFromInt(base::type::EnumType l) { - return static_cast(l); - } - /// @brief Converts level to associated const char* - /// @return Upper case string based level. - static const char* convertToString(Level level); - /// @brief Converts from levelStr to Level - /// @param levelStr Upper case string based level. - /// Lower case is also valid but providing upper case is recommended. - static Level convertFromString(const char* levelStr); - /// @brief Applies specified function to each level starting from startIndex - /// @param startIndex initial value to start the iteration from. This is passed as pointer and - /// is left-shifted so this can be used inside function (fn) to represent current level. - /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels. - static void forEachLevel(base::type::EnumType* startIndex, const std::function& fn); -}; -/// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect -/// of logging -enum class ConfigurationType : base::type::EnumType { - /// @brief Determines whether or not corresponding level and logger of logging is enabled - /// You may disable all logs by using el::Level::Global - Enabled = 1, - /// @brief Whether or not to write corresponding log to log file - ToFile = 2, - /// @brief Whether or not to write corresponding level and logger log to standard output. - /// By standard output meaning termnal, command prompt etc - ToStandardOutput = 4, - /// @brief Determines format of logging corresponding level and logger. - Format = 8, - /// @brief Determines log file (full path) to write logs to for correponding level and logger - Filename = 16, - /// @brief Specifies precision of the subsecond part. It should be within range (1-6). - SubsecondPrecision = 32, - /// @brief Alias of SubsecondPrecision (for backward compatibility) - MillisecondsWidth = SubsecondPrecision, - /// @brief Determines whether or not performance tracking is enabled. - /// - /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger - PerformanceTracking = 64, - /// @brief Specifies log file max size. - /// - /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will - /// be truncated and re-initiated. - MaxLogFileSize = 128, - /// @brief Specifies number of log entries to hold until we flush pending log data - LogFlushThreshold = 256, - /// @brief Represents unknown configuration - Unknown = 1010 -}; -/// @brief Static class that contains helper functions for el::ConfigurationType -class ConfigurationTypeHelper : base::StaticClass { - public: - /// @brief Represents minimum valid configuration type. Useful when iterating through enum. - static const base::type::EnumType kMinValid = static_cast(ConfigurationType::Enabled); - /// @brief Represents maximum valid configuration type. This is used internally and you should not need it. - static const base::type::EnumType kMaxValid = static_cast(ConfigurationType::MaxLogFileSize); - /// @brief Casts configuration type to int, useful for iterating through enum. - static base::type::EnumType castToInt(ConfigurationType configurationType) { - return static_cast(configurationType); - } - /// @brief Casts int(ushort) to configurationt type, useful for iterating through enum. - static ConfigurationType castFromInt(base::type::EnumType c) { - return static_cast(c); - } - /// @brief Converts configuration type to associated const char* - /// @returns Upper case string based configuration type. - static const char* convertToString(ConfigurationType configurationType); - /// @brief Converts from configStr to ConfigurationType - /// @param configStr Upper case string based configuration type. - /// Lower case is also valid but providing upper case is recommended. - static ConfigurationType convertFromString(const char* configStr); - /// @brief Applies specified function to each configuration type starting from startIndex - /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted - /// so this can be used inside function (fn) to represent current configuration type. - /// @param fn function to apply with each configuration type. - /// This bool represent whether or not to stop iterating through configurations. - static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function& fn); -}; -/// @brief Flags used while writing logs. This flags are set by user -enum class LoggingFlag : base::type::EnumType { - /// @brief Makes sure we have new line for each container log entry - NewLineForContainer = 1, - /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose - /// logging is allowed via that module. - AllowVerboseIfModuleNotSpecified = 2, - /// @brief When handling crashes by default, detailed crash reason will be logged as well - LogDetailedCrashReason = 4, - /// @brief Allows to disable application abortion when logged using FATAL level - DisableApplicationAbortOnFatalLog = 8, - /// @brief Flushes log with every log-entry (performance sensative) - Disabled by default - ImmediateFlush = 16, - /// @brief Enables strict file rolling - StrictLogFileSizeCheck = 32, - /// @brief Make terminal output colorful for supported terminals - ColoredTerminalOutput = 64, - /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network") - MultiLoggerSupport = 128, - /// @brief Disables comparing performance tracker's checkpoints - DisablePerformanceTrackingCheckpointComparison = 256, - /// @brief Disable VModules - DisableVModules = 512, - /// @brief Disable VModules extensions - DisableVModulesExtensions = 1024, - /// @brief Enables hierarchical logging - HierarchicalLogging = 2048, - /// @brief Creates logger automatically when not available - CreateLoggerAutomatically = 4096, - /// @brief Adds spaces b/w logs that separated by left-shift operator - AutoSpacing = 8192, - /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only) - FixedTimeFormat = 16384 -}; -namespace base { -/// @brief Namespace containing constants used internally. -namespace consts { -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif -// Level log values - These are values that are replaced in place of %level format specifier -static const base::type::char_t* kInfoLevelLogValue = ELPP_LITERAL("INFO "); -static const base::type::char_t* kDebugLevelLogValue = ELPP_LITERAL("DEBUG"); -static const base::type::char_t* kWarningLevelLogValue = ELPP_LITERAL("WARN "); -static const base::type::char_t* kErrorLevelLogValue = ELPP_LITERAL("ERROR"); -static const base::type::char_t* kFatalLevelLogValue = ELPP_LITERAL("FATAL"); -static const base::type::char_t* kVerboseLevelLogValue = ELPP_LITERAL("VER"); -static const base::type::char_t* kTraceLevelLogValue = ELPP_LITERAL("TRACE"); -static const base::type::char_t* kInfoLevelShortLogValue = ELPP_LITERAL("I"); -static const base::type::char_t* kDebugLevelShortLogValue = ELPP_LITERAL("D"); -static const base::type::char_t* kWarningLevelShortLogValue = ELPP_LITERAL("W"); -static const base::type::char_t* kErrorLevelShortLogValue = ELPP_LITERAL("E"); -static const base::type::char_t* kFatalLevelShortLogValue = ELPP_LITERAL("F"); -static const base::type::char_t* kVerboseLevelShortLogValue = ELPP_LITERAL("V"); -static const base::type::char_t* kTraceLevelShortLogValue = ELPP_LITERAL("T"); -// Format specifiers - These are used to define log format -static const base::type::char_t* kAppNameFormatSpecifier = ELPP_LITERAL("%app"); -static const base::type::char_t* kLoggerIdFormatSpecifier = ELPP_LITERAL("%logger"); -static const base::type::char_t* kThreadIdFormatSpecifier = ELPP_LITERAL("%thread"); -static const base::type::char_t* kSeverityLevelFormatSpecifier = ELPP_LITERAL("%level"); -static const base::type::char_t* kSeverityLevelShortFormatSpecifier = ELPP_LITERAL("%levshort"); -static const base::type::char_t* kDateTimeFormatSpecifier = ELPP_LITERAL("%datetime"); -static const base::type::char_t* kLogFileFormatSpecifier = ELPP_LITERAL("%file"); -static const base::type::char_t* kLogFileBaseFormatSpecifier = ELPP_LITERAL("%fbase"); -static const base::type::char_t* kLogLineFormatSpecifier = ELPP_LITERAL("%line"); -static const base::type::char_t* kLogLocationFormatSpecifier = ELPP_LITERAL("%loc"); -static const base::type::char_t* kLogFunctionFormatSpecifier = ELPP_LITERAL("%func"); -static const base::type::char_t* kCurrentUserFormatSpecifier = ELPP_LITERAL("%user"); -static const base::type::char_t* kCurrentHostFormatSpecifier = ELPP_LITERAL("%host"); -static const base::type::char_t* kMessageFormatSpecifier = ELPP_LITERAL("%msg"); -static const base::type::char_t* kVerboseLevelFormatSpecifier = ELPP_LITERAL("%vlevel"); -static const char* kDateTimeFormatSpecifierForFilename = "%datetime"; -// Date/time -static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; -static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -static const char* kMonths[12] = { "January", "February", "March", "Apri", "May", "June", "July", "August", - "September", "October", "November", "December" - }; -static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g"; -static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m"; -static const int kYearBase = 1900; -static const char* kAm = "AM"; -static const char* kPm = "PM"; -// Miscellaneous constants -#ifdef ELPP_DEFAULT_LOGGER -static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER; -#else -static const char* kDefaultLoggerId = "default"; -#endif -#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER -static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER; -#else -static const char* kPerformanceLoggerId = "performance"; -#endif -#if defined(ELPP_SYSLOG) -static const char* kSysLogLoggerId = "syslog"; -#endif // defined(ELPP_SYSLOG) -static const char* kNullPointer = "nullptr"; -static const char kFormatSpecifierChar = '%'; -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -static const char kFormatSpecifierCharValue = 'v'; -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED -static const unsigned int kMaxLogPerContainer = 100; -static const unsigned int kMaxLogPerCounter = 100000; -static const unsigned int kDefaultSubsecondPrecision = 3; -static const base::type::VerboseLevel kMaxVerboseLevel = 9; -static const char* kUnknownUser = "user"; -static const char* kUnknownHost = "unknown-host"; -#if defined(ELPP_DEFAULT_LOG_FILE) -static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE; -#else -# if ELPP_OS_UNIX -# if ELPP_OS_ANDROID -static const char* kDefaultLogFile = "logs/myeasylog.log"; -# else -static const char* kDefaultLogFile = "logs/myeasylog.log"; -# endif // ELPP_OS_ANDROID -# elif ELPP_OS_WINDOWS -static const char* kDefaultLogFile = "logs\\myeasylog.log"; -# endif // ELPP_OS_UNIX -#endif // defined(ELPP_DEFAULT_LOG_FILE) -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -static const char* kDefaultLogFileParam = "--default-log-file"; -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) -static const char* kLoggingFlagsParam = "--logging-flags"; -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) -#if ELPP_OS_WINDOWS -static const char* kFilePathSeperator = "\\"; -#else -static const char* kFilePathSeperator = "/"; -#endif // ELPP_OS_WINDOWS -static const char* kValidLoggerIdSymbols = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"; -static const char* kConfigurationComment = "##"; -static const char* kConfigurationLevel = "*"; -static const char* kConfigurationLoggerId = "--"; -static const std::size_t kSourceFilenameMaxLength = 100; -static const std::size_t kSourceLineMaxLength = 10; -static const Level kPerformanceTrackerDefaultLevel = Level::Info; -const struct { - double value; - const base::type::char_t* unit; -} kTimeFormats[] = { - { 1000.0f, ELPP_LITERAL("us") }, - { 1000.0f, ELPP_LITERAL("ms") }, - { 60.0f, ELPP_LITERAL("seconds") }, - { 60.0f, ELPP_LITERAL("minutes") }, - { 24.0f, ELPP_LITERAL("hours") }, - { 7.0f, ELPP_LITERAL("days") } -}; -static const int kTimeFormatsCount = sizeof(kTimeFormats) / sizeof(kTimeFormats[0]); -const struct { - int numb; - const char* name; - const char* brief; - const char* detail; -} kCrashSignals[] = { - // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..) - { - SIGABRT, "SIGABRT", "Abnormal termination", - "Program was abnormally terminated." - }, - { - SIGFPE, "SIGFPE", "Erroneous arithmetic operation", - "Arithemetic operation issue such as division by zero or operation resulting in overflow." - }, - { - SIGILL, "SIGILL", "Illegal instruction", - "Generally due to a corruption in the code or to an attempt to execute data." - }, - { - SIGSEGV, "SIGSEGV", "Invalid access to memory", - "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory." - }, - { - SIGINT, "SIGINT", "Interactive attention signal", - "Interruption generated (generally) by user or operating system." - }, -}; -static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]); -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif -} // namespace consts -} // namespace base -typedef std::function PreRollOutCallback; -namespace base { -static inline void defaultPreRollOutCallback(const char*, std::size_t) {} -/// @brief Enum to represent timestamp unit -enum class TimestampUnit : base::type::EnumType { - Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5 -}; -/// @brief Format flags used to determine specifiers that are active for performance improvements. -enum class FormatFlags : base::type::EnumType { - DateTime = 1 << 1, - LoggerId = 1 << 2, - File = 1 << 3, - Line = 1 << 4, - Location = 1 << 5, - Function = 1 << 6, - User = 1 << 7, - Host = 1 << 8, - LogMessage = 1 << 9, - VerboseLevel = 1 << 10, - AppName = 1 << 11, - ThreadId = 1 << 12, - Level = 1 << 13, - FileBase = 1 << 14, - LevelShort = 1 << 15 -}; -/// @brief A subsecond precision class containing actual width and offset of the subsecond part -class SubsecondPrecision { - public: - SubsecondPrecision(void) { - init(base::consts::kDefaultSubsecondPrecision); - } - explicit SubsecondPrecision(int width) { - init(width); - } - bool operator==(const SubsecondPrecision& ssPrec) { - return m_width == ssPrec.m_width && m_offset == ssPrec.m_offset; - } - int m_width; - unsigned int m_offset; - private: - void init(int width); -}; -/// @brief Type alias of SubsecondPrecision -typedef SubsecondPrecision MillisecondsWidth; -/// @brief Namespace containing utility functions/static classes used internally -namespace utils { -/// @brief Deletes memory safely and points to null -template -static -typename std::enable_if::value, void>::type -safeDelete(T*& pointer) { - if (pointer == nullptr) - return; - delete pointer; - pointer = nullptr; -} -/// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation -/// Use these function as
flag = bitwise::Or(MyEnum::val1, flag);
-namespace bitwise { -template -static inline base::type::EnumType And(Enum e, base::type::EnumType flag) { - return static_cast(flag) & static_cast(e); -} -template -static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) { - return static_cast(flag) & ~(static_cast(e)); -} -template -static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) { - return static_cast(flag) | static_cast(e); -} -} // namespace bitwise -template -static inline void addFlag(Enum e, base::type::EnumType* flag) { - *flag = base::utils::bitwise::Or(e, *flag); -} -template -static inline void removeFlag(Enum e, base::type::EnumType* flag) { - *flag = base::utils::bitwise::Not(e, *flag); -} -template -static inline bool hasFlag(Enum e, base::type::EnumType flag) { - return base::utils::bitwise::And(e, flag) > 0x0; -} -} // namespace utils -namespace threading { -#if ELPP_THREADING_ENABLED -# if !ELPP_USE_STD_THREADING -namespace internal { -/// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex -class Mutex : base::NoCopy { - public: - Mutex(void) { -# if ELPP_OS_UNIX - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_underlyingMutex, &attr); - pthread_mutexattr_destroy(&attr); -# elif ELPP_OS_WINDOWS - InitializeCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - virtual ~Mutex(void) { -# if ELPP_OS_UNIX - pthread_mutex_destroy(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - DeleteCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline void lock(void) { -# if ELPP_OS_UNIX - pthread_mutex_lock(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - EnterCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline bool try_lock(void) { -# if ELPP_OS_UNIX - return (pthread_mutex_trylock(&m_underlyingMutex) == 0); -# elif ELPP_OS_WINDOWS - return TryEnterCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline void unlock(void) { -# if ELPP_OS_UNIX - pthread_mutex_unlock(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - LeaveCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - private: -# if ELPP_OS_UNIX - pthread_mutex_t m_underlyingMutex; -# elif ELPP_OS_WINDOWS - CRITICAL_SECTION m_underlyingMutex; -# endif // ELPP_OS_UNIX -}; -/// @brief Scoped lock for compiler that dont yet support std::lock_guard -template -class ScopedLock : base::NoCopy { - public: - explicit ScopedLock(M& mutex) { - m_mutex = &mutex; - m_mutex->lock(); - } - - virtual ~ScopedLock(void) { - m_mutex->unlock(); - } - private: - M* m_mutex; - ScopedLock(void); -}; -} // namespace internal -typedef base::threading::internal::Mutex Mutex; -typedef base::threading::internal::ScopedLock ScopedLock; -# else -typedef std::recursive_mutex Mutex; -typedef std::lock_guard ScopedLock; -# endif // !ELPP_USE_STD_THREADING -#else -namespace internal { -/// @brief Mutex wrapper used when multi-threading is disabled. -class NoMutex : base::NoCopy { - public: - NoMutex(void) {} - inline void lock(void) {} - inline bool try_lock(void) { - return true; - } - inline void unlock(void) {} -}; -/// @brief Lock guard wrapper used when multi-threading is disabled. -template -class NoScopedLock : base::NoCopy { - public: - explicit NoScopedLock(Mutex&) { - } - virtual ~NoScopedLock(void) { - } - private: - NoScopedLock(void); -}; -} // namespace internal -typedef base::threading::internal::NoMutex Mutex; -typedef base::threading::internal::NoScopedLock ScopedLock; -#endif // ELPP_THREADING_ENABLED -/// @brief Base of thread safe class, this class is inheritable-only -class ThreadSafe { - public: - virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); } - virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); } - virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; } - protected: - ThreadSafe(void) {} - virtual ~ThreadSafe(void) {} - private: - base::threading::Mutex m_mutex; -}; - -#if ELPP_THREADING_ENABLED -# if !ELPP_USE_STD_THREADING -/// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned. -static std::string getCurrentThreadId(void) { - std::stringstream ss; -# if (ELPP_OS_WINDOWS) - ss << GetCurrentThreadId(); -# endif // (ELPP_OS_WINDOWS) - return ss.str(); -} -# else -/// @brief Gets ID of currently running threading using std::this_thread::get_id() -static std::string getCurrentThreadId(void) { - std::stringstream ss; - ss << std::this_thread::get_id(); - return ss.str(); -} -# endif // !ELPP_USE_STD_THREADING -#else -static inline std::string getCurrentThreadId(void) { - return std::string(); -} -#endif // ELPP_THREADING_ENABLED -} // namespace threading -namespace utils { -class File : base::StaticClass { - public: - /// @brief Creates new out file stream for specified filename. - /// @return Pointer to newly created fstream or nullptr - static base::type::fstream_t* newFileStream(const std::string& filename); - - /// @brief Gets size of file provided in stream - static std::size_t getSizeOfFile(base::type::fstream_t* fs); - - /// @brief Determines whether or not provided path exist in current file system - static bool pathExists(const char* path, bool considerFile = false); - - /// @brief Creates specified path on file system - /// @param path Path to create. - static bool createPath(const std::string& path); - /// @brief Extracts path of filename with leading slash - static std::string extractPathFromFilename(const std::string& fullPath, - const char* seperator = base::consts::kFilePathSeperator); - /// @brief builds stripped filename and puts it in buff - static void buildStrippedFilename(const char* filename, char buff[], - std::size_t limit = base::consts::kSourceFilenameMaxLength); - /// @brief builds base filename and puts it in buff - static void buildBaseFilename(const std::string& fullPath, char buff[], - std::size_t limit = base::consts::kSourceFilenameMaxLength, - const char* seperator = base::consts::kFilePathSeperator); -}; -/// @brief String utilities helper class used internally. You should not use it. -class Str : base::StaticClass { - public: - /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues. - static inline bool isDigit(char c) { - return c >= '0' && c <= '9'; - } - - /// @brief Matches wildcards, '*' and '?' only supported. - static bool wildCardMatch(const char* str, const char* pattern); - - static std::string& ltrim(std::string& str); - static std::string& rtrim(std::string& str); - static std::string& trim(std::string& str); - - /// @brief Determines whether or not str starts with specified string - /// @param str String to check - /// @param start String to check against - /// @return Returns true if starts with specified string, false otherwise - static bool startsWith(const std::string& str, const std::string& start); - - /// @brief Determines whether or not str ends with specified string - /// @param str String to check - /// @param end String to check against - /// @return Returns true if ends with specified string, false otherwise - static bool endsWith(const std::string& str, const std::string& end); - - /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance. - /// @param [in,out] str String to replace from - /// @param replaceWhat Character to replace - /// @param replaceWith Character to replace with - /// @return Modified version of str - static std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith); - - /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place - /// @param str String to replace from - /// @param replaceWhat Character to replace - /// @param replaceWith Character to replace with - /// @return Modified (original) str - static std::string& replaceAll(std::string& str, const std::string& replaceWhat, - const std::string& replaceWith); - - static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const base::type::string_t& replaceWith); -#if defined(ELPP_UNICODE) - static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const std::string& replaceWith); -#endif // defined(ELPP_UNICODE) - /// @brief Converts string to uppercase - /// @param str String to convert - /// @return Uppercase string - static std::string& toUpper(std::string& str); - - /// @brief Compares cstring equality - uses strcmp - static bool cStringEq(const char* s1, const char* s2); - - /// @brief Compares cstring equality (case-insensitive) - uses toupper(char) - /// Dont use strcasecmp because of CRT (VC++) - static bool cStringCaseEq(const char* s1, const char* s2); - - /// @brief Returns true if c exist in str - static bool contains(const char* str, char c); - - static char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true); - static char* addToBuff(const char* str, char* buf, const char* bufLim); - static char* clearBuff(char buff[], std::size_t lim); - - /// @brief Converst wchar* to char* - /// NOTE: Need to free return value after use! - static char* wcharPtrToCharPtr(const wchar_t* line); -}; -/// @brief Operating System helper static class used internally. You should not use it. -class OS : base::StaticClass { - public: -#if ELPP_OS_WINDOWS - /// @brief Gets environment variables for Windows based OS. - /// We are not using getenv(const char*) because of CRT deprecation - /// @param varname Variable name to get environment variable value for - /// @return If variable exist the value of it otherwise nullptr - static const char* getWindowsEnvironmentVariable(const char* varname); -#endif // ELPP_OS_WINDOWS -#if ELPP_OS_ANDROID - /// @brief Reads android property value - static std::string getProperty(const char* prop); - - /// @brief Reads android device name - static std::string getDeviceName(void); -#endif // ELPP_OS_ANDROID - - /// @brief Runs command on terminal and returns the output. - /// - /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned. - /// @param command Bash command - /// @return Result of bash output or empty string if no result found. - static const std::string getBashOutput(const char* command); - - /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++) - /// @param variableName Environment variable name - /// @param defaultVal If no environment variable or value found the value to return by default - /// @param alternativeBashCommand If environment variable not found what would be alternative bash command - /// in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami' - static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, - const char* alternativeBashCommand = nullptr); - /// @brief Gets current username. - static std::string currentUser(void); - - /// @brief Gets current host name or computer name. - /// - /// @detail For android systems this is device name with its manufacturer and model seperated by hyphen - static std::string currentHost(void); - /// @brief Whether or not terminal supports colors - static bool termSupportsColor(void); -}; -/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str -class DateTime : base::StaticClass { - public: - /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current microsecond. - /// - /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a seperate implementation is provided - /// @param [in,out] tv Pointer that gets updated - static void gettimeofday(struct timeval* tv); - - /// @brief Gets current date and time with a subsecond part. - /// @param format User provided date/time format - /// @param ssPrec A pointer to base::SubsecondPrecision from configuration (non-null) - /// @returns string based date time in specified format. - static std::string getDateTime(const char* format, const base::SubsecondPrecision* ssPrec); - - /// @brief Converts timeval (struct from ctime) to string using specified format and subsecond precision - static std::string timevalToString(struct timeval tval, const char* format, - const el::base::SubsecondPrecision* ssPrec); - - /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc - static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit); - - /// @brief Gets time difference in milli/micro second depending on timestampUnit - static unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, - base::TimestampUnit timestampUnit); - - - private: - static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo); - static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, - std::size_t msec, const base::SubsecondPrecision* ssPrec); -}; -/// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..) -class CommandLineArgs { - public: - CommandLineArgs(void) { - setArgs(0, static_cast(nullptr)); - } - CommandLineArgs(int argc, const char** argv) { - setArgs(argc, argv); - } - CommandLineArgs(int argc, char** argv) { - setArgs(argc, argv); - } - virtual ~CommandLineArgs(void) {} - /// @brief Sets arguments and parses them - inline void setArgs(int argc, const char** argv) { - setArgs(argc, const_cast(argv)); - } - /// @brief Sets arguments and parses them - void setArgs(int argc, char** argv); - /// @brief Returns true if arguments contain paramKey with a value (seperated by '=') - bool hasParamWithValue(const char* paramKey) const; - /// @brief Returns value of arguments - /// @see hasParamWithValue(const char*) - const char* getParamValue(const char* paramKey) const; - /// @brief Return true if arguments has a param (not having a value) i,e without '=' - bool hasParam(const char* paramKey) const; - /// @brief Returns true if no params available. This exclude argv[0] - bool empty(void) const; - /// @brief Returns total number of arguments. This exclude argv[0] - std::size_t size(void) const; - friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c); - - private: - int m_argc; - char** m_argv; - std::map m_paramsWithValue; - std::vector m_params; -}; -/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type. -/// -/// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement -/// unregisterAll() and deepCopy(const AbstractRegistry&) and write registerNew() method according to container -/// and few more methods; get() to find element, unregister() to unregister single entry. -/// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation. -template -class AbstractRegistry : public base::threading::ThreadSafe { - public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - - /// @brief Default constructor - AbstractRegistry(void) {} - - /// @brief Move constructor that is useful for base classes - AbstractRegistry(AbstractRegistry&& sr) { - if (this == &sr) { - return; - } - unregisterAll(); - m_list = std::move(sr.m_list); - } - - bool operator==(const AbstractRegistry& other) { - if (size() != other.size()) { - return false; - } - for (std::size_t i = 0; i < m_list.size(); ++i) { - if (m_list.at(i) != other.m_list.at(i)) { - return false; - } - } - return true; - } - - bool operator!=(const AbstractRegistry& other) { - if (size() != other.size()) { - return true; - } - for (std::size_t i = 0; i < m_list.size(); ++i) { - if (m_list.at(i) != other.m_list.at(i)) { - return true; - } - } - return false; - } - - /// @brief Assignment move operator - AbstractRegistry& operator=(AbstractRegistry&& sr) { - if (this == &sr) { - return *this; - } - unregisterAll(); - m_list = std::move(sr.m_list); - return *this; - } - - virtual ~AbstractRegistry(void) { - } - - /// @return Iterator pointer from start of repository - virtual inline iterator begin(void) ELPP_FINAL { - return m_list.begin(); - } - - /// @return Iterator pointer from end of repository - virtual inline iterator end(void) ELPP_FINAL { - return m_list.end(); - } - - - /// @return Constant iterator pointer from start of repository - virtual inline const_iterator cbegin(void) const ELPP_FINAL { - return m_list.cbegin(); - } - - /// @return End of repository - virtual inline const_iterator cend(void) const ELPP_FINAL { - return m_list.cend(); - } - - /// @return Whether or not repository is empty - virtual inline bool empty(void) const ELPP_FINAL { - return m_list.empty(); - } - - /// @return Size of repository - virtual inline std::size_t size(void) const ELPP_FINAL { - return m_list.size(); - } - - /// @brief Returns underlying container by reference - virtual inline Container& list(void) ELPP_FINAL { - return m_list; - } - - /// @brief Returns underlying container by constant reference. - virtual inline const Container& list(void) const ELPP_FINAL { - return m_list; - } - - /// @brief Unregisters all the pointers from current repository. - virtual void unregisterAll(void) = 0; - - protected: - virtual void deepCopy(const AbstractRegistry&) = 0; - void reinitDeepCopy(const AbstractRegistry& sr) { - unregisterAll(); - deepCopy(sr); - } - - private: - Container m_list; -}; - -/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version) -/// -/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions) -/// of AbstractRegistry. Any implementation of this class should be -/// explicitly (by using lock functions) -template -class Registry : public AbstractRegistry> { - public: - typedef typename Registry::iterator iterator; - typedef typename Registry::const_iterator const_iterator; - - Registry(void) {} - - /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. - Registry(const Registry& sr) : AbstractRegistry>() { - if (this == &sr) { - return; - } - this->reinitDeepCopy(sr); - } - - /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element - /// @see unregisterAll() - /// @see deepCopy(const AbstractRegistry&) - Registry& operator=(const Registry& sr) { - if (this == &sr) { - return *this; - } - this->reinitDeepCopy(sr); - return *this; - } - - virtual ~Registry(void) { - unregisterAll(); - } - - protected: - virtual void unregisterAll(void) ELPP_FINAL { - if (!this->empty()) { - for (auto&& curr : this->list()) { - base::utils::safeDelete(curr.second); - } - this->list().clear(); - } - } - -/// @brief Registers new registry to repository. - virtual void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL { - unregister(uniqKey); - this->list().insert(std::make_pair(uniqKey, ptr)); - } - -/// @brief Unregisters single entry mapped to specified unique key - void unregister(const T_Key& uniqKey) { - T_Ptr* existing = get(uniqKey); - if (existing != nullptr) { - base::utils::safeDelete(existing); - this->list().erase(uniqKey); - } - } - -/// @brief Gets pointer from repository. If none found, nullptr is returned. - T_Ptr* get(const T_Key& uniqKey) { - iterator it = this->list().find(uniqKey); - return it == this->list().end() - ? nullptr - : it->second; - } - - private: - virtual void deepCopy(const AbstractRegistry>& sr) ELPP_FINAL { - for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) { - registerNew(it->first, new T_Ptr(*it->second)); - } - } -}; - -/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version) -/// -/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry. Any implementation of this class -/// should be made thread-safe explicitly -template -class RegistryWithPred : public AbstractRegistry> { - public: - typedef typename RegistryWithPred::iterator iterator; - typedef typename RegistryWithPred::const_iterator const_iterator; - - RegistryWithPred(void) { - } - - virtual ~RegistryWithPred(void) { - unregisterAll(); - } - - /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. - RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry>() { - if (this == &sr) { - return; - } - this->reinitDeepCopy(sr); - } - - /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element - /// @see unregisterAll() - /// @see deepCopy(const AbstractRegistry&) - RegistryWithPred& operator=(const RegistryWithPred& sr) { - if (this == &sr) { - return *this; - } - this->reinitDeepCopy(sr); - return *this; - } - - friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) { - for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { - os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n"); - } - return os; - } - - protected: - virtual void unregisterAll(void) ELPP_FINAL { - if (!this->empty()) { - for (auto&& curr : this->list()) { - base::utils::safeDelete(curr); - } - this->list().clear(); - } - } - - virtual void unregister(T_Ptr*& ptr) ELPP_FINAL { - if (ptr) { - iterator iter = this->begin(); - for (; iter != this->end(); ++iter) { - if (ptr == *iter) { - break; - } - } - if (iter != this->end() && *iter != nullptr) { - this->list().erase(iter); - base::utils::safeDelete(*iter); - } - } - } - - virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL { - this->list().push_back(ptr); - } - -/// @brief Gets pointer from repository with speicifed arguments. Arguments are passed to predicate -/// in order to validate pointer. - template - T_Ptr* get(const T& arg1, const T2 arg2) { - iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2)); - if (iter != this->list().end() && *iter != nullptr) { - return *iter; - } - return nullptr; - } - - private: - virtual void deepCopy(const AbstractRegistry>& sr) { - for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { - registerNew(new T_Ptr(**it)); - } - } -}; -class Utils { - public: - template - static bool installCallback(const std::string& id, std::map* mapT) { - if (mapT->find(id) == mapT->end()) { - mapT->insert(std::make_pair(id, TPtr(new T()))); - return true; - } - return false; - } - - template - static void uninstallCallback(const std::string& id, std::map* mapT) { - if (mapT->find(id) != mapT->end()) { - mapT->erase(id); - } - } - - template - static T* callback(const std::string& id, std::map* mapT) { - typename std::map::iterator iter = mapT->find(id); - if (iter != mapT->end()) { - return static_cast(iter->second.get()); - } - return nullptr; - } -}; -} // namespace utils -} // namespace base -/// @brief Base of Easylogging++ friendly class -/// -/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const` -class Loggable { - public: - virtual ~Loggable(void) {} - virtual void log(el::base::type::ostream_t&) const = 0; - private: - friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) { - loggable.log(os); - return os; - } -}; -namespace base { -/// @brief Represents log format containing flags and date format. This is used internally to start initial log -class LogFormat : public Loggable { - public: - LogFormat(void); - LogFormat(Level level, const base::type::string_t& format); - LogFormat(const LogFormat& logFormat); - LogFormat(LogFormat&& logFormat); - LogFormat& operator=(const LogFormat& logFormat); - virtual ~LogFormat(void) {} - bool operator==(const LogFormat& other); - - /// @brief Updates format to be used while logging. - /// @param userFormat User provided format - void parseFromFormat(const base::type::string_t& userFormat); - - inline Level level(void) const { - return m_level; - } - - inline const base::type::string_t& userFormat(void) const { - return m_userFormat; - } - - inline const base::type::string_t& format(void) const { - return m_format; - } - - inline const std::string& dateTimeFormat(void) const { - return m_dateTimeFormat; - } - - inline base::type::EnumType flags(void) const { - return m_flags; - } - - inline bool hasFlag(base::FormatFlags flag) const { - return base::utils::hasFlag(flag, m_flags); - } - - virtual void log(el::base::type::ostream_t& os) const { - os << m_format; - } - - protected: - /// @brief Updates date time format if available in currFormat. - /// @param index Index where %datetime, %date or %time was found - /// @param [in,out] currFormat current format that is being used to format - virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL; - - /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level - virtual void updateFormatSpec(void) ELPP_FINAL; - - inline void addFlag(base::FormatFlags flag) { - base::utils::addFlag(flag, &m_flags); - } - - private: - Level m_level; - base::type::string_t m_userFormat; - base::type::string_t m_format; - std::string m_dateTimeFormat; - base::type::EnumType m_flags; - std::string m_currentUser; - std::string m_currentHost; - friend class el::Logger; // To resolve loggerId format specifier easily -}; -} // namespace base -/// @brief Resolving function for format specifier -typedef std::function FormatSpecifierValueResolver; -/// @brief User-provided custom format specifier -/// @see el::Helpers::installCustomFormatSpecifier -/// @see FormatSpecifierValueResolver -class CustomFormatSpecifier { - public: - CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) : - m_formatSpecifier(formatSpecifier), m_resolver(resolver) {} - inline const char* formatSpecifier(void) const { - return m_formatSpecifier; - } - inline const FormatSpecifierValueResolver& resolver(void) const { - return m_resolver; - } - inline bool operator==(const char* formatSpecifier) { - return strcmp(m_formatSpecifier, formatSpecifier) == 0; - } - - private: - const char* m_formatSpecifier; - FormatSpecifierValueResolver m_resolver; -}; -/// @brief Represents single configuration that has representing level, configuration type and a string based value. -/// -/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes -/// and will be parsed later. -/// -/// Consider some examples below: -/// * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true"); -/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048"); -/// * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log"); -class Configuration : public Loggable { - public: - Configuration(const Configuration& c); - Configuration& operator=(const Configuration& c); - - virtual ~Configuration(void) { - } - - /// @brief Full constructor used to sets value of configuration - Configuration(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Gets level of current configuration - inline Level level(void) const { - return m_level; - } - - /// @brief Gets configuration type of current configuration - inline ConfigurationType configurationType(void) const { - return m_configurationType; - } - - /// @brief Gets string based configuration value - inline const std::string& value(void) const { - return m_value; - } - - /// @brief Set string based configuration value - /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values - /// use them in quotes. They will be parsed when configuring - inline void setValue(const std::string& value) { - m_value = value; - } - - virtual void log(el::base::type::ostream_t& os) const; - - /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. - class Predicate { - public: - Predicate(Level level, ConfigurationType configurationType); - - bool operator()(const Configuration* conf) const; - - private: - Level m_level; - ConfigurationType m_configurationType; - }; - - private: - Level m_level; - ConfigurationType m_configurationType; - std::string m_value; -}; - -/// @brief Thread-safe Configuration repository -/// -/// @detail This repository represents configurations for all the levels and configuration type mapped to a value. -class Configurations : public base::utils::RegistryWithPred { - public: - /// @brief Default constructor with empty repository - Configurations(void); - - /// @brief Constructor used to set configurations using configuration file. - /// @param configurationFile Full path to configuration file - /// @param useDefaultsForRemaining Lets you set the remaining configurations to default. - /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to. - /// @see parseFromFile(const std::string&, Configurations* base) - /// @see setRemainingToDefault() - Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true, - Configurations* base = nullptr); - - virtual ~Configurations(void) { - } - - /// @brief Parses configuration from file. - /// @param configurationFile Full path to configuration file - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration file. - /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you - /// do not proceed without successful parse. - bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr); - - /// @brief Parse configurations from configuration string. - /// - /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary - /// new line characters are provided. - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration text. - /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you - /// do not proceed without successful parse. - bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr); - - /// @brief Sets configuration based-off an existing configurations. - /// @param base Pointer to existing configurations. - void setFromBase(Configurations* base); - - /// @brief Determines whether or not specified configuration type exists in the repository. - /// - /// @detail Returns as soon as first level is found. - /// @param configurationType Type of configuration to check existence for. - bool hasConfiguration(ConfigurationType configurationType); - - /// @brief Determines whether or not specified configuration type exists for specified level - /// @param level Level to check - /// @param configurationType Type of configuration to check existence for. - bool hasConfiguration(Level level, ConfigurationType configurationType); - - /// @brief Sets value of configuration for specified level. - /// - /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types - /// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for - /// Level::Global because these configurations are not dependant on level. - /// @param level Level to set configuration for (el::Level). - /// @param configurationType Type of configuration (el::ConfigurationType) - /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string - /// from users' point of view. This is then parsed later to be used internally. - /// @see Configuration::setValue(const std::string& value) - /// @see el::Level - /// @see el::ConfigurationType - void set(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Sets single configuration based on other single configuration. - /// @see set(Level level, ConfigurationType configurationType, const std::string& value) - void set(Configuration* conf); - - inline Configuration* get(Level level, ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); - return RegistryWithPred::get(level, configurationType); - } - - /// @brief Sets configuration for all levels. - /// @param configurationType Type of configuration - /// @param value String based value - /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) - inline void setGlobally(ConfigurationType configurationType, const std::string& value) { - setGlobally(configurationType, value, false); - } - - /// @brief Clears repository so that all the configurations are unset - inline void clear(void) { - base::threading::ScopedLock scopedLock(lock()); - unregisterAll(); - } - - /// @brief Gets configuration file used in parsing this configurations. - /// - /// @detail If this repository was set manually or by text this returns empty string. - inline const std::string& configurationFile(void) const { - return m_configurationFile; - } - - /// @brief Sets configurations to "factory based" configurations. - void setToDefault(void); - - /// @brief Lets you set the remaining configurations to default. - /// - /// @detail By remaining, it means that the level/type a configuration does not exist for. - /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets - /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e, - /// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor - /// and try to access a value, an error is thrown - void setRemainingToDefault(void); - - /// @brief Parser used internally to parse configurations from file or text. - /// - /// @detail This class makes use of base::utils::Str. - /// You should not need this unless you are working on some tool for Easylogging++ - class Parser : base::StaticClass { - public: - /// @brief Parses configuration from file. - /// @param configurationFile Full path to configuration file - /// @param sender Sender configurations pointer. Usually 'this' is used from calling class - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration file. - /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you - /// do not proceed without successful parse. - static bool parseFromFile(const std::string& configurationFile, Configurations* sender, - Configurations* base = nullptr); - - /// @brief Parse configurations from configuration string. - /// - /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary - /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you - /// do not proceed without successful parse (This is recommended) - /// @param configurationsString the configuration in plain text format - /// @param sender Sender configurations pointer. Usually 'this' is used from calling class - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration text. - /// @return True if successfully parsed, false otherwise. - static bool parseFromText(const std::string& configurationsString, Configurations* sender, - Configurations* base = nullptr); - - private: - friend class el::Loggers; - static void ignoreComments(std::string* line); - static bool isLevel(const std::string& line); - static bool isComment(const std::string& line); - static inline bool isConfig(const std::string& line); - static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel, - Configurations* conf); - }; - - private: - std::string m_configurationFile; - bool m_isFromFile; - friend class el::Loggers; - - /// @brief Unsafely sets configuration if does not already exist - void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Thread unsafe set - void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true - /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) - void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel); - - /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true - /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) - void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel); -}; - -namespace base { -typedef std::shared_ptr FileStreamPtr; -typedef std::map LogStreamsReferenceMap; -/// @brief Configurations with data types. -/// -/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations. -/// This is to perform faster while writing logs using correct configurations. -/// -/// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class) -class TypedConfigurations : public base::threading::ThreadSafe { - public: - /// @brief Constructor to initialize (construct) the object off el::Configurations - /// @param configurations Configurations pointer/reference to base this typed configurations off. - /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference() - TypedConfigurations(Configurations* configurations, base::LogStreamsReferenceMap* logStreamsReference); - - TypedConfigurations(const TypedConfigurations& other); - - virtual ~TypedConfigurations(void) { - } - - const Configurations* configurations(void) const { - return m_configurations; - } - - bool enabled(Level level); - bool toFile(Level level); - const std::string& filename(Level level); - bool toStandardOutput(Level level); - const base::LogFormat& logFormat(Level level); - const base::SubsecondPrecision& subsecondPrecision(Level level = Level::Global); - const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global); - bool performanceTracking(Level level = Level::Global); - base::type::fstream_t* fileStream(Level level); - std::size_t maxLogFileSize(Level level); - std::size_t logFlushThreshold(Level level); - - private: - Configurations* m_configurations; - std::map m_enabledMap; - std::map m_toFileMap; - std::map m_filenameMap; - std::map m_toStandardOutputMap; - std::map m_logFormatMap; - std::map m_subsecondPrecisionMap; - std::map m_performanceTrackingMap; - std::map m_fileStreamMap; - std::map m_maxLogFileSizeMap; - std::map m_logFlushThresholdMap; - base::LogStreamsReferenceMap* m_logStreamsReference; - - friend class el::Helpers; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::DefaultLogDispatchCallback; - friend class el::base::LogDispatcher; - - template - inline Conf_T getConfigByVal(Level level, const std::map* confMap, const char* confName) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope - } - - template - inline Conf_T& getConfigByRef(Level level, std::map* confMap, const char* confName) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope - } - - template - Conf_T unsafeGetConfigByVal(Level level, const std::map* confMap, const char* confName) { - ELPP_UNUSED(confName); - typename std::map::const_iterator it = confMap->find(level); - if (it == confMap->end()) { - try { - return confMap->at(Level::Global); - } catch (...) { - ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" - << LevelHelper::convertToString(level) << "]" - << std::endl << "Please ensure you have properly configured logger.", false); - return Conf_T(); - } - } - return it->second; - } - - template - Conf_T& unsafeGetConfigByRef(Level level, std::map* confMap, const char* confName) { - ELPP_UNUSED(confName); - typename std::map::iterator it = confMap->find(level); - if (it == confMap->end()) { - try { - return confMap->at(Level::Global); - } catch (...) { - ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" - << LevelHelper::convertToString(level) << "]" - << std::endl << "Please ensure you have properly configured logger.", false); - } - } - return it->second; - } - - template - void setValue(Level level, const Conf_T& value, std::map* confMap, bool includeGlobalLevel = true) { - // If map is empty and we are allowed to add into generic level (Level::Global), do it! - if (confMap->empty() && includeGlobalLevel) { - confMap->insert(std::make_pair(Level::Global, value)); - return; - } - // If same value exist in generic level already, dont add it to explicit level - typename std::map::iterator it = confMap->find(Level::Global); - if (it != confMap->end() && it->second == value) { - return; - } - // Now make sure we dont double up values if we really need to add it to explicit level - it = confMap->find(level); - if (it == confMap->end()) { - // Value not found for level, add new - confMap->insert(std::make_pair(level, value)); - } else { - // Value found, just update value - confMap->at(level) = value; - } - } - - void build(Configurations* configurations); - unsigned long getULong(std::string confVal); - std::string resolveFilename(const std::string& filename); - void insertFile(Level level, const std::string& fullFilename); - bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback); - - inline bool validateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeValidateFileRolling(level, preRollOutCallback); - } -}; -/// @brief Class that keeps record of current line hit for occasional logging -class HitCounter { - public: - HitCounter(void) : - m_filename(""), - m_lineNumber(0), - m_hitCounts(0) { - } - - HitCounter(const char* filename, base::type::LineNumber lineNumber) : - m_filename(filename), - m_lineNumber(lineNumber), - m_hitCounts(0) { - } - - HitCounter(const HitCounter& hitCounter) : - m_filename(hitCounter.m_filename), - m_lineNumber(hitCounter.m_lineNumber), - m_hitCounts(hitCounter.m_hitCounts) { - } - - HitCounter& operator=(const HitCounter& hitCounter) { - if (&hitCounter != this) { - m_filename = hitCounter.m_filename; - m_lineNumber = hitCounter.m_lineNumber; - m_hitCounts = hitCounter.m_hitCounts; - } - return *this; - } - - virtual ~HitCounter(void) { - } - - /// @brief Resets location of current hit counter - inline void resetLocation(const char* filename, base::type::LineNumber lineNumber) { - m_filename = filename; - m_lineNumber = lineNumber; - } - - /// @brief Validates hit counts and resets it if necessary - inline void validateHitCounts(std::size_t n) { - if (m_hitCounts >= base::consts::kMaxLogPerCounter) { - m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0); - } - ++m_hitCounts; - } - - inline const char* filename(void) const { - return m_filename; - } - - inline base::type::LineNumber lineNumber(void) const { - return m_lineNumber; - } - - inline std::size_t hitCounts(void) const { - return m_hitCounts; - } - - inline void increment(void) { - ++m_hitCounts; - } - - class Predicate { - public: - Predicate(const char* filename, base::type::LineNumber lineNumber) - : m_filename(filename), - m_lineNumber(lineNumber) { - } - inline bool operator()(const HitCounter* counter) { - return ((counter != nullptr) && - (strcmp(counter->m_filename, m_filename) == 0) && - (counter->m_lineNumber == m_lineNumber)); - } - - private: - const char* m_filename; - base::type::LineNumber m_lineNumber; - }; - - private: - const char* m_filename; - base::type::LineNumber m_lineNumber; - std::size_t m_hitCounts; -}; -/// @brief Repository for hit counters used across the application -class RegisteredHitCounters : public base::utils::RegistryWithPred { - public: - /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n); - - /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n); - - /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n); - - /// @brief Gets hit counter registered at specified position - inline const base::HitCounter* getCounter(const char* filename, base::type::LineNumber lineNumber) { - base::threading::ScopedLock scopedLock(lock()); - return get(filename, lineNumber); - } -}; -/// @brief Action to be taken for dispatching -enum class DispatchAction : base::type::EnumType { - None = 1, NormalLog = 2, SysLog = 4 -}; -} // namespace base -template -class Callback : protected base::threading::ThreadSafe { - public: - Callback(void) : m_enabled(true) {} - inline bool enabled(void) const { - return m_enabled; - } - inline void setEnabled(bool enabled) { - base::threading::ScopedLock scopedLock(lock()); - m_enabled = enabled; - } - protected: - virtual void handle(const T* handlePtr) = 0; - private: - bool m_enabled; -}; -class LogDispatchData { - public: - LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {} - inline const LogMessage* logMessage(void) const { - return m_logMessage; - } - inline base::DispatchAction dispatchAction(void) const { - return m_dispatchAction; - } - private: - LogMessage* m_logMessage; - base::DispatchAction m_dispatchAction; - friend class base::LogDispatcher; - - inline void setLogMessage(LogMessage* logMessage) { - m_logMessage = logMessage; - } - inline void setDispatchAction(base::DispatchAction dispatchAction) { - m_dispatchAction = dispatchAction; - } -}; -class LogDispatchCallback : public Callback { - private: - friend class base::LogDispatcher; -}; -class PerformanceTrackingCallback : public Callback { - private: - friend class base::PerformanceTracker; -}; -class LoggerRegistrationCallback : public Callback { - private: - friend class base::RegisteredLoggers; -}; -class LogBuilder : base::NoCopy { - public: - LogBuilder() : m_termSupportsColor(base::utils::OS::termSupportsColor()) {} - virtual ~LogBuilder(void) { - ELPP_INTERNAL_INFO(3, "Destroying log builder...") - } - virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0; - void convertToColoredOutput(base::type::string_t* logLine, Level level); - private: - bool m_termSupportsColor; - friend class el::base::DefaultLogDispatchCallback; -}; -typedef std::shared_ptr LogBuilderPtr; -/// @brief Represents a logger holding ID and configurations we need to write logs -/// -/// @detail This class does not write logs itself instead its used by writer to read configuations from. -class Logger : public base::threading::ThreadSafe, public Loggable { - public: - Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference); - Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* logStreamsReference); - Logger(const Logger& logger); - Logger& operator=(const Logger& logger); - - virtual ~Logger(void) { - base::utils::safeDelete(m_typedConfigurations); - } - - virtual inline void log(el::base::type::ostream_t& os) const { - os << m_id.c_str(); - } - - /// @brief Configures the logger using specified configurations. - void configure(const Configurations& configurations); - - /// @brief Reconfigures logger using existing configurations - void reconfigure(void); - - inline const std::string& id(void) const { - return m_id; - } - - inline const std::string& parentApplicationName(void) const { - return m_parentApplicationName; - } - - inline void setParentApplicationName(const std::string& parentApplicationName) { - m_parentApplicationName = parentApplicationName; - } - - inline Configurations* configurations(void) { - return &m_configurations; - } - - inline base::TypedConfigurations* typedConfigurations(void) { - return m_typedConfigurations; - } - - static bool isValidId(const std::string& id); - - /// @brief Flushes logger to sync all log files for all levels - void flush(void); - - void flush(Level level, base::type::fstream_t* fs); - - inline bool isFlushNeeded(Level level) { - return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level); - } - - inline LogBuilder* logBuilder(void) const { - return m_logBuilder.get(); - } - - inline void setLogBuilder(const LogBuilderPtr& logBuilder) { - m_logBuilder = logBuilder; - } - - inline bool enabled(Level level) const { - return m_typedConfigurations->enabled(level); - } - -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -# define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\ -template \ -inline void FUNCTION_NAME(const char*, const T&, const Args&...);\ -template \ -inline void FUNCTION_NAME(const T&); - - template - inline void verbose(int, const char*, const T&, const Args&...); - - template - inline void verbose(int, const T&); - - LOGGER_LEVEL_WRITERS_SIGNATURES(info) - LOGGER_LEVEL_WRITERS_SIGNATURES(debug) - LOGGER_LEVEL_WRITERS_SIGNATURES(warn) - LOGGER_LEVEL_WRITERS_SIGNATURES(error) - LOGGER_LEVEL_WRITERS_SIGNATURES(fatal) - LOGGER_LEVEL_WRITERS_SIGNATURES(trace) -# undef LOGGER_LEVEL_WRITERS_SIGNATURES -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - private: - std::string m_id; - base::TypedConfigurations* m_typedConfigurations; - base::type::stringstream_t m_stream; - std::string m_parentApplicationName; - bool m_isConfigured; - Configurations m_configurations; - std::map m_unflushedCount; - base::LogStreamsReferenceMap* m_logStreamsReference; - LogBuilderPtr m_logBuilder; - - friend class el::LogMessage; - friend class el::Loggers; - friend class el::Helpers; - friend class el::base::RegisteredLoggers; - friend class el::base::DefaultLogDispatchCallback; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::PErrorWriter; - friend class el::base::Storage; - friend class el::base::PerformanceTracker; - friend class el::base::LogDispatcher; - - Logger(void); - -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED - template - void log_(Level, int, const char*, const T&, const Args&...); - - template - inline void log_(Level, int, const T&); - - template - void log(Level, const char*, const T&, const Args&...); - - template - inline void log(Level, const T&); -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - - void initUnflushedCount(void); - - inline base::type::stringstream_t& stream(void) { - return m_stream; - } - - void resolveLoggerFormatSpec(void) const; -}; -namespace base { -/// @brief Loggers repository -class RegisteredLoggers : public base::utils::Registry { - public: - explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder); - - virtual ~RegisteredLoggers(void) { - unsafeFlushAll(); - } - - inline void setDefaultConfigurations(const Configurations& configurations) { - base::threading::ScopedLock scopedLock(lock()); - m_defaultConfigurations.setFromBase(const_cast(&configurations)); - } - - inline Configurations* defaultConfigurations(void) { - return &m_defaultConfigurations; - } - - Logger* get(const std::string& id, bool forceCreation = true); - - template - inline bool installLoggerRegistrationCallback(const std::string& id) { - return base::utils::Utils::installCallback(id, - &m_loggerRegistrationCallbacks); - } - - template - inline void uninstallLoggerRegistrationCallback(const std::string& id) { - base::utils::Utils::uninstallCallback(id, &m_loggerRegistrationCallbacks); - } - - template - inline T* loggerRegistrationCallback(const std::string& id) { - return base::utils::Utils::callback(id, &m_loggerRegistrationCallbacks); - } - - bool remove(const std::string& id); - - inline bool has(const std::string& id) { - return get(id, false) != nullptr; - } - - inline void unregister(Logger*& logger) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::Registry::unregister(logger->id()); - } - - inline base::LogStreamsReferenceMap* logStreamsReference(void) { - return &m_logStreamsReference; - } - - inline void flushAll(void) { - base::threading::ScopedLock scopedLock(lock()); - unsafeFlushAll(); - } - - inline void setDefaultLogBuilder(LogBuilderPtr& logBuilderPtr) { - base::threading::ScopedLock scopedLock(lock()); - m_defaultLogBuilder = logBuilderPtr; - } - - private: - LogBuilderPtr m_defaultLogBuilder; - Configurations m_defaultConfigurations; - base::LogStreamsReferenceMap m_logStreamsReference; - std::map m_loggerRegistrationCallbacks; - friend class el::base::Storage; - - void unsafeFlushAll(void); -}; -/// @brief Represents registries for verbose logging -class VRegistry : base::NoCopy, public base::threading::ThreadSafe { - public: - explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags); - - /// @brief Sets verbose level. Accepted range is 0-9 - void setLevel(base::type::VerboseLevel level); - - inline base::type::VerboseLevel level(void) const { - return m_level; - } - - inline void clearModules(void) { - base::threading::ScopedLock scopedLock(lock()); - m_modules.clear(); - } - - void setModules(const char* modules); - - bool allowed(base::type::VerboseLevel vlevel, const char* file); - - inline const std::map& modules(void) const { - return m_modules; - } - - void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs); - - /// @brief Whether or not vModules enabled - inline bool vModulesEnabled(void) { - return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags); - } - - private: - base::type::VerboseLevel m_level; - base::type::EnumType* m_pFlags; - std::map m_modules; -}; -} // namespace base -class LogMessage { - public: - LogMessage(Level level, const std::string& file, base::type::LineNumber line, const std::string& func, - base::type::VerboseLevel verboseLevel, Logger* logger) : - m_level(level), m_file(file), m_line(line), m_func(func), - m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) { - } - inline Level level(void) const { - return m_level; - } - inline const std::string& file(void) const { - return m_file; - } - inline base::type::LineNumber line(void) const { - return m_line; - } - inline const std::string& func(void) const { - return m_func; - } - inline base::type::VerboseLevel verboseLevel(void) const { - return m_verboseLevel; - } - inline Logger* logger(void) const { - return m_logger; - } - inline const base::type::string_t& message(void) const { - return m_message; - } - private: - Level m_level; - std::string m_file; - base::type::LineNumber m_line; - std::string m_func; - base::type::VerboseLevel m_verboseLevel; - Logger* m_logger; - base::type::string_t m_message; -}; -namespace base { -#if ELPP_ASYNC_LOGGING -class AsyncLogItem { - public: - explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine) - : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {} - virtual ~AsyncLogItem() {} - inline LogMessage* logMessage(void) { - return &m_logMessage; - } - inline LogDispatchData* data(void) { - return &m_dispatchData; - } - inline base::type::string_t logLine(void) { - return m_logLine; - } - private: - LogMessage m_logMessage; - LogDispatchData m_dispatchData; - base::type::string_t m_logLine; -}; -class AsyncLogQueue : public base::threading::ThreadSafe { - public: - virtual ~AsyncLogQueue() { - ELPP_INTERNAL_INFO(6, "~AsyncLogQueue"); - } - - inline AsyncLogItem next(void) { - base::threading::ScopedLock scopedLock(lock()); - AsyncLogItem result = m_queue.front(); - m_queue.pop(); - return result; - } - - inline void push(const AsyncLogItem& item) { - base::threading::ScopedLock scopedLock(lock()); - m_queue.push(item); - } - inline void pop(void) { - base::threading::ScopedLock scopedLock(lock()); - m_queue.pop(); - } - inline AsyncLogItem front(void) { - base::threading::ScopedLock scopedLock(lock()); - return m_queue.front(); - } - inline bool empty(void) { - base::threading::ScopedLock scopedLock(lock()); - return m_queue.empty(); - } - private: - std::queue m_queue; -}; -class IWorker { - public: - virtual ~IWorker() {} - virtual void start() = 0; -}; -#endif // ELPP_ASYNC_LOGGING -/// @brief Easylogging++ management storage -class Storage : base::NoCopy, public base::threading::ThreadSafe { - public: -#if ELPP_ASYNC_LOGGING - Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker); -#else - explicit Storage(const LogBuilderPtr& defaultLogBuilder); -#endif // ELPP_ASYNC_LOGGING - - virtual ~Storage(void); - - inline bool validateEveryNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t occasion) { - return hitCounters()->validateEveryN(filename, lineNumber, occasion); - } - - inline bool validateAfterNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - return hitCounters()->validateAfterN(filename, lineNumber, n); - } - - inline bool validateNTimesCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - return hitCounters()->validateNTimes(filename, lineNumber, n); - } - - inline base::RegisteredHitCounters* hitCounters(void) const { - return m_registeredHitCounters; - } - - inline base::RegisteredLoggers* registeredLoggers(void) const { - return m_registeredLoggers; - } - - inline base::VRegistry* vRegistry(void) const { - return m_vRegistry; - } - -#if ELPP_ASYNC_LOGGING - inline base::AsyncLogQueue* asyncLogQueue(void) const { - return m_asyncLogQueue; - } -#endif // ELPP_ASYNC_LOGGING - - inline const base::utils::CommandLineArgs* commandLineArgs(void) const { - return &m_commandLineArgs; - } - - inline void addFlag(LoggingFlag flag) { - base::utils::addFlag(flag, &m_flags); - } - - inline void removeFlag(LoggingFlag flag) { - base::utils::removeFlag(flag, &m_flags); - } - - inline bool hasFlag(LoggingFlag flag) const { - return base::utils::hasFlag(flag, m_flags); - } - - inline base::type::EnumType flags(void) const { - return m_flags; - } - - inline void setFlags(base::type::EnumType flags) { - m_flags = flags; - } - - inline void setPreRollOutCallback(const PreRollOutCallback& callback) { - m_preRollOutCallback = callback; - } - - inline void unsetPreRollOutCallback(void) { - m_preRollOutCallback = base::defaultPreRollOutCallback; - } - - inline PreRollOutCallback& preRollOutCallback(void) { - return m_preRollOutCallback; - } - - bool hasCustomFormatSpecifier(const char* formatSpecifier); - void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier); - bool uninstallCustomFormatSpecifier(const char* formatSpecifier); - - const std::vector* customFormatSpecifiers(void) const { - return &m_customFormatSpecifiers; - } - - inline void setLoggingLevel(Level level) { - m_loggingLevel = level; - } - - template - inline bool installLogDispatchCallback(const std::string& id) { - return base::utils::Utils::installCallback(id, &m_logDispatchCallbacks); - } - - template - inline void uninstallLogDispatchCallback(const std::string& id) { - base::utils::Utils::uninstallCallback(id, &m_logDispatchCallbacks); - } - template - inline T* logDispatchCallback(const std::string& id) { - return base::utils::Utils::callback(id, &m_logDispatchCallbacks); - } - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - template - inline bool installPerformanceTrackingCallback(const std::string& id) { - return base::utils::Utils::installCallback(id, - &m_performanceTrackingCallbacks); - } - - template - inline void uninstallPerformanceTrackingCallback(const std::string& id) { - base::utils::Utils::uninstallCallback(id, - &m_performanceTrackingCallbacks); - } - - template - inline T* performanceTrackingCallback(const std::string& id) { - return base::utils::Utils::callback(id, &m_performanceTrackingCallbacks); - } -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - - /// @brief Sets thread name for current thread. Requires std::thread - inline void setThreadName(const std::string& name) { - if (name.empty()) return; - base::threading::ScopedLock scopedLock(lock()); - m_threadNames[base::threading::getCurrentThreadId()] = name; - } - - inline std::string getThreadName(const std::string& threadId) { - std::map::const_iterator it = m_threadNames.find(threadId); - if (it == m_threadNames.end()) { - return threadId; - } - return it->second; - } - private: - base::RegisteredHitCounters* m_registeredHitCounters; - base::RegisteredLoggers* m_registeredLoggers; - base::type::EnumType m_flags; - base::VRegistry* m_vRegistry; -#if ELPP_ASYNC_LOGGING - base::AsyncLogQueue* m_asyncLogQueue; - base::IWorker* m_asyncDispatchWorker; -#endif // ELPP_ASYNC_LOGGING - base::utils::CommandLineArgs m_commandLineArgs; - PreRollOutCallback m_preRollOutCallback; - std::map m_logDispatchCallbacks; - std::map m_performanceTrackingCallbacks; - std::map m_threadNames; - std::vector m_customFormatSpecifiers; - Level m_loggingLevel; - - friend class el::Helpers; - friend class el::base::DefaultLogDispatchCallback; - friend class el::LogBuilder; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::PerformanceTracker; - friend class el::base::LogDispatcher; - - void setApplicationArguments(int argc, char** argv); - - inline void setApplicationArguments(int argc, const char** argv) { - setApplicationArguments(argc, const_cast(argv)); - } -}; -extern ELPP_EXPORT base::type::StoragePointer elStorage; -#define ELPP el::base::elStorage -class DefaultLogDispatchCallback : public LogDispatchCallback { - protected: - void handle(const LogDispatchData* data); - private: - const LogDispatchData* m_data; - void dispatch(base::type::string_t&& logLine); -}; -#if ELPP_ASYNC_LOGGING -class AsyncLogDispatchCallback : public LogDispatchCallback { - protected: - void handle(const LogDispatchData* data); -}; -class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe { - public: - AsyncDispatchWorker(); - virtual ~AsyncDispatchWorker(); - - bool clean(void); - void emptyQueue(void); - virtual void start(void); - void handle(AsyncLogItem* logItem); - void run(void); - - void setContinueRunning(bool value) { - base::threading::ScopedLock scopedLock(m_continueRunningMutex); - m_continueRunning = value; - } - - bool continueRunning(void) const { - return m_continueRunning; - } - private: - std::condition_variable cv; - bool m_continueRunning; - base::threading::Mutex m_continueRunningMutex; -}; -#endif // ELPP_ASYNC_LOGGING -} // namespace base -namespace base { -class DefaultLogBuilder : public LogBuilder { - public: - base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const; -}; -/// @brief Dispatches log messages -class LogDispatcher : base::NoCopy { - public: - LogDispatcher(bool proceed, LogMessage&& logMessage, base::DispatchAction dispatchAction) : - m_proceed(proceed), - m_logMessage(std::move(logMessage)), - m_dispatchAction(std::move(dispatchAction)) { - } - - void dispatch(void); - - private: - bool m_proceed; - LogMessage m_logMessage; - base::DispatchAction m_dispatchAction; -}; -#if defined(ELPP_STL_LOGGING) -/// @brief Workarounds to write some STL logs -/// -/// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers -/// of same type and provide iterator interface and pass it on to writeIterator(). -/// Remember, this is passed by value in constructor so that we dont change original containers. -/// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer)) -namespace workarounds { -/// @brief Abstract IterableContainer template that provides interface for iterable classes of type T -template -class IterableContainer { - public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - IterableContainer(void) {} - virtual ~IterableContainer(void) {} - iterator begin(void) { - return getContainer().begin(); - } - iterator end(void) { - return getContainer().end(); - } - private: - virtual Container& getContainer(void) = 0; -}; -/// @brief Implements IterableContainer and provides iterable std::priority_queue class -template, typename Comparator = std::less> -class IterablePriorityQueue : public IterableContainer, - public std::priority_queue { - public: - IterablePriorityQueue(std::priority_queue queue_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { - this->push(queue_.top()); - queue_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } -}; -/// @brief Implements IterableContainer and provides iterable std::queue class -template> -class IterableQueue : public IterableContainer, public std::queue { - public: - IterableQueue(std::queue queue_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { - this->push(queue_.front()); - queue_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } -}; -/// @brief Implements IterableContainer and provides iterable std::stack class -template> -class IterableStack : public IterableContainer, public std::stack { - public: - IterableStack(std::stack stack_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) { - this->push(stack_.top()); - stack_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } -}; -} // namespace workarounds -#endif // defined(ELPP_STL_LOGGING) -// Log message builder -class MessageBuilder { - public: - MessageBuilder(void) : m_logger(nullptr), m_containerLogSeperator(ELPP_LITERAL("")) {} - void initialize(Logger* logger); - -# define ELPP_SIMPLE_LOG(LOG_TYPE)\ -MessageBuilder& operator<<(LOG_TYPE msg) {\ -m_logger->stream() << msg;\ -if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\ -m_logger->stream() << " ";\ -}\ -return *this;\ -} - - inline MessageBuilder& operator<<(const std::string& msg) { - return operator<<(msg.c_str()); - } - ELPP_SIMPLE_LOG(char) - ELPP_SIMPLE_LOG(bool) - ELPP_SIMPLE_LOG(signed short) - ELPP_SIMPLE_LOG(unsigned short) - ELPP_SIMPLE_LOG(signed int) - ELPP_SIMPLE_LOG(unsigned int) - ELPP_SIMPLE_LOG(signed long) - ELPP_SIMPLE_LOG(unsigned long) - ELPP_SIMPLE_LOG(float) - ELPP_SIMPLE_LOG(double) - ELPP_SIMPLE_LOG(char*) - ELPP_SIMPLE_LOG(const char*) - ELPP_SIMPLE_LOG(const void*) - ELPP_SIMPLE_LOG(long double) - inline MessageBuilder& operator<<(const std::wstring& msg) { - return operator<<(msg.c_str()); - } - MessageBuilder& operator<<(const wchar_t* msg); - // ostream manipulators - inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) { - m_logger->stream() << OStreamMani; - return *this; - } -#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} - -#if defined(ELPP_STL_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap) - template - inline MessageBuilder& operator<<(const std::queue& queue_) { - base::workarounds::IterableQueue iterableQueue_ = - static_cast >(queue_); - return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); - } - template - inline MessageBuilder& operator<<(const std::stack& stack_) { - base::workarounds::IterableStack iterableStack_ = - static_cast >(stack_); - return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); - } - template - inline MessageBuilder& operator<<(const std::priority_queue& priorityQueue_) { - base::workarounds::IterablePriorityQueue iterablePriorityQueue_ = - static_cast >(priorityQueue_); - return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); - } - template - MessageBuilder& operator<<(const std::pair& pair_) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(pair_.first)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(pair_.second)); - m_logger->stream() << ELPP_LITERAL(")"); - return *this; - } - template - MessageBuilder& operator<<(const std::bitset& bitset_) { - m_logger->stream() << ELPP_LITERAL("["); - operator << (bitset_.to_string()); - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } -# if defined(ELPP_LOG_STD_ARRAY) - template - inline MessageBuilder& operator<<(const std::array& array) { - return writeIterator(array.begin(), array.end(), array.size()); - } -# endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_MAP) - ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map) - ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap) -# endif // defined(ELPP_LOG_UNORDERED_MAP) -# if defined(ELPP_LOG_UNORDERED_SET) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset) -# endif // defined(ELPP_LOG_UNORDERED_SET) -#endif // defined(ELPP_STL_LOGGING) -#if defined(ELPP_QT_LOGGING) - inline MessageBuilder& operator<<(const QString& msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << msg.toStdWString(); -# else - m_logger->stream() << msg.toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(const QByteArray& msg) { - return operator << (QString(msg)); - } - inline MessageBuilder& operator<<(const QStringRef& msg) { - return operator<<(msg.toString()); - } - inline MessageBuilder& operator<<(qint64 msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << QString::number(msg).toStdWString(); -# else - m_logger->stream() << QString::number(msg).toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(quint64 msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << QString::number(msg).toStdWString(); -# else - m_logger->stream() << QString::number(msg).toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(QChar msg) { - m_logger->stream() << msg.toLatin1(); - return *this; - } - inline MessageBuilder& operator<<(const QLatin1String& msg) { - m_logger->stream() << msg.latin1(); - return *this; - } - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack) - template - MessageBuilder& operator<<(const QPair& pair_) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(pair_.first)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(pair_.second)); - m_logger->stream() << ELPP_LITERAL(")"); - return *this; - } - template - MessageBuilder& operator<<(const QMap& map_) { - m_logger->stream() << ELPP_LITERAL("["); - QList keys = map_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(base::consts::kMaxLogPerContainer); // to prevent warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(*begin)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(map_.value(*begin))); - m_logger->stream() << ELPP_LITERAL(")"); - m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); - } - if (begin != end) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMultiMap& map_) { - operator << (static_cast>(map_)); - return *this; - } - template - MessageBuilder& operator<<(const QHash& hash_) { - m_logger->stream() << ELPP_LITERAL("["); - QList keys = hash_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(base::consts::kMaxLogPerContainer); // prevent type warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(*begin)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(hash_.value(*begin))); - m_logger->stream() << ELPP_LITERAL(")"); - m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); - } - if (begin != end) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMultiHash& multiHash_) { - operator << (static_cast>(multiHash_)); - return *this; - } -#endif // defined(ELPP_QT_LOGGING) -#if defined(ELPP_BOOST_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set) -#endif // defined(ELPP_BOOST_LOGGING) - - /// @brief Macro used internally that can be used externally to make containers easylogging++ friendly - /// - /// @detail This macro expands to write an ostream& operator<< for container. This container is expected to - /// have begin() and end() methods that return respective iterators - /// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets - /// @param SizeMethod Method used to get size of container. - /// @param ElementInstance Instance of element to be fed out. Insance name is "elem". See WXELPP_ENABLED macro - /// for an example usage -#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \ -el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\ -const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \ -ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");\ -ContainerType::const_iterator elem = container.begin();\ -ContainerType::const_iterator endElem = container.end();\ -std::size_t size_ = container.SizeMethod; \ -ss << ELPP_LITERAL("[");\ -for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \ -ss << ElementInstance;\ -ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\ -}\ -if (elem != endElem) {\ -ss << ELPP_LITERAL("...");\ -}\ -ss << ELPP_LITERAL("]");\ -return ss;\ -} -#if defined(ELPP_WXWIDGETS_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector) -# define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem)) -# define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem)) -# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \ -ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")") -#else -# define ELPP_WX_PTR_ENABLED(ContainerType) -# define ELPP_WX_ENABLED(ContainerType) -# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) -#endif // defined(ELPP_WXWIDGETS_LOGGING) - // Other classes - template - ELPP_SIMPLE_LOG(const Class&) -#undef ELPP_SIMPLE_LOG -#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG - private: - Logger* m_logger; - const base::type::char_t* m_containerLogSeperator; - - template - MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) { - m_logger->stream() << ELPP_LITERAL("["); - for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) { - operator << (*begin_); - m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeperator : ELPP_LITERAL("")); - } - if (begin_ != end_) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; - } -}; -/// @brief Writes nothing - Used when certain log is disabled -class NullWriter : base::NoCopy { - public: - NullWriter(void) {} - - // Null manipulator - inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) { - return *this; - } - - template - inline NullWriter& operator<<(const T&) { - return *this; - } - - inline operator bool() { - return true; - } -}; -/// @brief Main entry point of each logging -class Writer : base::NoCopy { - public: - Writer(Level level, const char* file, base::type::LineNumber line, - const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, - base::type::VerboseLevel verboseLevel = 0) : - m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), - m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { - } - - virtual ~Writer(void) { - processDispatch(); - } - - template - inline Writer& operator<<(const T& log) { -#if ELPP_LOGGING_ENABLED - if (m_proceed) { - m_messageBuilder << log; - } -#endif // ELPP_LOGGING_ENABLED - return *this; - } - - inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) { -#if ELPP_LOGGING_ENABLED - if (m_proceed) { - m_messageBuilder << log; - } -#endif // ELPP_LOGGING_ENABLED - return *this; - } - - inline operator bool() { - return true; - } - - Writer& construct(Logger* logger, bool needLock = true); - Writer& construct(int count, const char* loggerIds, ...); - protected: - Level m_level; - const char* m_file; - const base::type::LineNumber m_line; - const char* m_func; - base::type::VerboseLevel m_verboseLevel; - Logger* m_logger; - bool m_proceed; - base::MessageBuilder m_messageBuilder; - base::DispatchAction m_dispatchAction; - std::vector m_loggerIds; - friend class el::Helpers; - - void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true); - void processDispatch(); - void triggerDispatch(void); -}; -class PErrorWriter : public base::Writer { - public: - PErrorWriter(Level level, const char* file, base::type::LineNumber line, - const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, - base::type::VerboseLevel verboseLevel = 0) : - base::Writer(level, file, line, func, dispatchAction, verboseLevel) { - } - - virtual ~PErrorWriter(void); -}; -} // namespace base -// Logging from Logger class. Why this is here? Because we have Storage and Writer class available -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -template -void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) { - base::MessageBuilder b; - b.initialize(this); - while (*s) { - if (*s == base::consts::kFormatSpecifierChar) { - if (*(s + 1) == base::consts::kFormatSpecifierChar) { - ++s; - } else { - if (*(s + 1) == base::consts::kFormatSpecifierCharValue) { - ++s; - b << value; - log_(level, vlevel, ++s, args...); - return; - } - } - } - b << *s++; - } - ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false); -} -template -void Logger::log_(Level level, int vlevel, const T& log) { - if (level == Level::Verbose) { - if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) { - base::Writer(Level::Verbose, "FILE", 0, "FUNCTION", - base::DispatchAction::NormalLog, vlevel).construct(this, false) << log; - } else { - stream().str(ELPP_LITERAL("")); - } - } else { - base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; - } -} -template -inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) { - base::threading::ScopedLock scopedLock(lock()); - log_(level, 0, s, value, args...); -} -template -inline void Logger::log(Level level, const T& log) { - base::threading::ScopedLock scopedLock(lock()); - log_(level, 0, log); -} -# if ELPP_VERBOSE_LOG -template -inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) { - base::threading::ScopedLock scopedLock(lock()); - log_(el::Level::Verbose, vlevel, s, value, args...); -} -template -inline void Logger::verbose(int vlevel, const T& log) { - base::threading::ScopedLock scopedLock(lock()); - log_(el::Level::Verbose, vlevel, log); -} -# else -template -inline void Logger::verbose(int, const char*, const T&, const Args&...) { - return; -} -template -inline void Logger::verbose(int, const T&) { - return; -} -# endif // ELPP_VERBOSE_LOG -# define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\ -template \ -inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\ -log(LOG_LEVEL, s, value, args...);\ -}\ -template \ -inline void Logger::FUNCTION_NAME(const T& value) {\ -log(LOG_LEVEL, value);\ -} -# define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\ -template \ -inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\ -return;\ -}\ -template \ -inline void Logger::FUNCTION_NAME(const T&) {\ -return;\ -} - -# if ELPP_INFO_LOG -LOGGER_LEVEL_WRITERS(info, Level::Info) -# else -LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info) -# endif // ELPP_INFO_LOG -# if ELPP_DEBUG_LOG -LOGGER_LEVEL_WRITERS(debug, Level::Debug) -# else -LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug) -# endif // ELPP_DEBUG_LOG -# if ELPP_WARNING_LOG -LOGGER_LEVEL_WRITERS(warn, Level::Warning) -# else -LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning) -# endif // ELPP_WARNING_LOG -# if ELPP_ERROR_LOG -LOGGER_LEVEL_WRITERS(error, Level::Error) -# else -LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error) -# endif // ELPP_ERROR_LOG -# if ELPP_FATAL_LOG -LOGGER_LEVEL_WRITERS(fatal, Level::Fatal) -# else -LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal) -# endif // ELPP_FATAL_LOG -# if ELPP_TRACE_LOG -LOGGER_LEVEL_WRITERS(trace, Level::Trace) -# else -LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace) -# endif // ELPP_TRACE_LOG -# undef LOGGER_LEVEL_WRITERS -# undef LOGGER_LEVEL_WRITERS_DISABLED -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED -#if ELPP_COMPILER_MSVC -# define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs -# define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__)) -# define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\ -10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#else -# if ELPP_COMPILER_CLANG -# define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -# else -# define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -# endif // ELPP_COMPILER_CLANG -#endif // ELPP_COMPILER_MSVC -#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \ -ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \ -ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \ -ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) -class PerformanceTrackingData { - public: - enum class DataType : base::type::EnumType { - Checkpoint = 1, Complete = 2 - }; - // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*) - explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr), - m_dataType(dataType), m_firstCheckpoint(false), m_file(""), m_line(0), m_func("") {} - inline const std::string* blockName(void) const; - inline const struct timeval* startTime(void) const; - inline const struct timeval* endTime(void) const; - inline const struct timeval* lastCheckpointTime(void) const; - inline const base::PerformanceTracker* performanceTracker(void) const { - return m_performanceTracker; - } - inline PerformanceTrackingData::DataType dataType(void) const { - return m_dataType; - } - inline bool firstCheckpoint(void) const { - return m_firstCheckpoint; - } - inline std::string checkpointId(void) const { - return m_checkpointId; - } - inline const char* file(void) const { - return m_file; - } - inline base::type::LineNumber line(void) const { - return m_line; - } - inline const char* func(void) const { - return m_func; - } - inline const base::type::string_t* formattedTimeTaken() const { - return &m_formattedTimeTaken; - } - inline const std::string& loggerId(void) const; - private: - base::PerformanceTracker* m_performanceTracker; - base::type::string_t m_formattedTimeTaken; - PerformanceTrackingData::DataType m_dataType; - bool m_firstCheckpoint; - std::string m_checkpointId; - const char* m_file; - base::type::LineNumber m_line; - const char* m_func; - inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) { - m_performanceTracker = performanceTracker; - m_firstCheckpoint = firstCheckpoint; - } - - friend class el::base::PerformanceTracker; -}; -namespace base { -/// @brief Represents performanceTracker block of code that conditionally adds performance status to log -/// either when goes outside the scope of when checkpoint() is called -class PerformanceTracker : public base::threading::ThreadSafe, public Loggable { - public: - PerformanceTracker(const std::string& blockName, - base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond, - const std::string& loggerId = std::string(el::base::consts::kPerformanceLoggerId), - bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel); - /// @brief Copy constructor - PerformanceTracker(const PerformanceTracker& t) : - m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog), - m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled), - m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) { - } - virtual ~PerformanceTracker(void); - /// @brief A checkpoint for current performanceTracker block. - void checkpoint(const std::string& id = std::string(), const char* file = __FILE__, - base::type::LineNumber line = __LINE__, - const char* func = ""); - inline Level level(void) const { - return m_level; - } - private: - std::string m_blockName; - base::TimestampUnit m_timestampUnit; - std::string m_loggerId; - bool m_scopedLog; - Level m_level; - bool m_hasChecked; - std::string m_lastCheckpointId; - bool m_enabled; - struct timeval m_startTime, m_endTime, m_lastCheckpointTime; - - PerformanceTracker(void); - - friend class el::PerformanceTrackingData; - friend class base::DefaultPerformanceTrackingCallback; - - const inline base::type::string_t getFormattedTimeTaken() const { - return getFormattedTimeTaken(m_startTime); - } - - const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const; - - virtual inline void log(el::base::type::ostream_t& os) const { - os << getFormattedTimeTaken(); - } -}; -class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback { - protected: - void handle(const PerformanceTrackingData* data) { - m_data = data; - base::type::stringstream_t ss; - if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) { - ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") << - *m_data->formattedTimeTaken() << ELPP_LITERAL("]"); - } else { - ss << ELPP_LITERAL("Performance checkpoint"); - if (!m_data->checkpointId().empty()) { - ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]"); - } - ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") << - *m_data->performanceTracker(); - if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison) - && m_data->performanceTracker()->m_hasChecked) { - ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from "); - if (m_data->performanceTracker()->m_lastCheckpointId.empty()) { - ss << ELPP_LITERAL("last checkpoint"); - } else { - ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'"); - } - ss << ELPP_LITERAL(")]"); - } else { - ss << ELPP_LITERAL("]"); - } - } - el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1, - m_data->loggerId().c_str()) << ss.str(); - } - private: - const PerformanceTrackingData* m_data; -}; -} // namespace base -inline const std::string* PerformanceTrackingData::blockName() const { - return const_cast(&m_performanceTracker->m_blockName); -} -inline const struct timeval* PerformanceTrackingData::startTime() const { - return const_cast(&m_performanceTracker->m_startTime); -} -inline const struct timeval* PerformanceTrackingData::endTime() const { - return const_cast(&m_performanceTracker->m_endTime); -} -inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const { - return const_cast(&m_performanceTracker->m_lastCheckpointTime); -} -inline const std::string& PerformanceTrackingData::loggerId(void) const { - return m_performanceTracker->m_loggerId; -} -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) -namespace base { -/// @brief Contains some internal debugging tools like crash handler and stack tracer -namespace debug { -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -class StackTrace : base::NoCopy { - public: - static const unsigned int kMaxStack = 64; - static const unsigned int kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew() - class StackTraceEntry { - public: - StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, const char* addr); - StackTraceEntry(std::size_t index, char* loc) : - m_index(index), - m_location(loc) { - } - std::size_t m_index; - std::string m_location; - std::string m_demangled; - std::string m_hex; - std::string m_addr; - friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si); - - private: - StackTraceEntry(void); - }; - - StackTrace(void) { - generateNew(); - } - - virtual ~StackTrace(void) { - } - - inline std::vector& getLatestStack(void) { - return m_stack; - } - - friend std::ostream& operator<<(std::ostream& os, const StackTrace& st); - - private: - std::vector m_stack; - - void generateNew(void); -}; -/// @brief Handles unexpected crashes -class CrashHandler : base::NoCopy { - public: - typedef void (*Handler)(int); - - explicit CrashHandler(bool useDefault); - explicit CrashHandler(const Handler& cHandler) { - setHandler(cHandler); - } - void setHandler(const Handler& cHandler); - - private: - Handler m_handler; -}; -#else -class CrashHandler { - public: - explicit CrashHandler(bool) {} -}; -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -} // namespace debug -} // namespace base -extern base::debug::CrashHandler elCrashHandler; -#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \ -el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance) -/// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor -class SysLogInitializer { - public: - SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) { -#if defined(ELPP_SYSLOG) - openlog(processIdent, options, facility); -#else - ELPP_UNUSED(processIdent); - ELPP_UNUSED(options); - ELPP_UNUSED(facility); -#endif // defined(ELPP_SYSLOG) - } - virtual ~SysLogInitializer(void) { -#if defined(ELPP_SYSLOG) - closelog(); -#endif // defined(ELPP_SYSLOG) - } -}; -#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac) -/// @brief Static helpers for developers -class Helpers : base::StaticClass { - public: - /// @brief Shares logging repository (base::Storage) - static inline void setStorage(base::type::StoragePointer storage) { - ELPP = storage; - } - /// @return Main storage repository - static inline base::type::StoragePointer storage() { - return ELPP; - } - /// @brief Sets application arguments and figures out whats active for logging and whats not. - static inline void setArgs(int argc, char** argv) { - ELPP->setApplicationArguments(argc, argv); - } - /// @copydoc setArgs(int argc, char** argv) - static inline void setArgs(int argc, const char** argv) { - ELPP->setApplicationArguments(argc, const_cast(argv)); - } - /// @brief Sets thread name for current thread. Requires std::thread - static inline void setThreadName(const std::string& name) { - ELPP->setThreadName(name); - } - static inline std::string getThreadName() { - return ELPP->getThreadName(base::threading::getCurrentThreadId()); - } -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - /// @brief Overrides default crash handler and installs custom handler. - /// @param crashHandler A functor with no return type that takes single int argument. - /// Handler is a typedef with specification: void (*Handler)(int) - static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) { - el::elCrashHandler.setHandler(crashHandler); - } - /// @brief Abort due to crash with signal in parameter - /// @param sig Crash signal - static void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0); - /// @brief Logs reason of crash as per sig - /// @param sig Crash signal - /// @param stackTraceIfAvailable Includes stack trace if available - /// @param level Logging level - /// @param logger Logger to use for logging - static void logCrashReason(int sig, bool stackTraceIfAvailable = false, - Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId); -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out - /// (can be useful for backing up) - static inline void installPreRollOutCallback(const PreRollOutCallback& callback) { - ELPP->setPreRollOutCallback(callback); - } - /// @brief Uninstalls pre rollout callback - static inline void uninstallPreRollOutCallback(void) { - ELPP->unsetPreRollOutCallback(); - } - /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched - template - static inline bool installLogDispatchCallback(const std::string& id) { - return ELPP->installLogDispatchCallback(id); - } - /// @brief Uninstalls log dispatch callback - template - static inline void uninstallLogDispatchCallback(const std::string& id) { - ELPP->uninstallLogDispatchCallback(id); - } - template - static inline T* logDispatchCallback(const std::string& id) { - return ELPP->logDispatchCallback(id); - } -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished - template - static inline bool installPerformanceTrackingCallback(const std::string& id) { - return ELPP->installPerformanceTrackingCallback(id); - } - /// @brief Uninstalls post performance tracking handler - template - static inline void uninstallPerformanceTrackingCallback(const std::string& id) { - ELPP->uninstallPerformanceTrackingCallback(id); - } - template - static inline T* performanceTrackingCallback(const std::string& id) { - return ELPP->performanceTrackingCallback(id); - } -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const - template - static std::string convertTemplateToStdString(const T& templ) { - el::Logger* logger = - ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId); - if (logger == nullptr) { - return std::string(); - } - base::MessageBuilder b; - b.initialize(logger); - logger->acquireLock(); - b << templ; -#if defined(ELPP_UNICODE) - std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end()); -#else - std::string s = logger->stream().str(); -#endif // defined(ELPP_UNICODE) - logger->stream().str(ELPP_LITERAL("")); - logger->releaseLock(); - return s; - } - /// @brief Returns command line arguments (pointer) provided to easylogging++ - static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) { - return ELPP->commandLineArgs(); - } - /// @brief Installs user defined format specifier and handler - static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { - ELPP->installCustomFormatSpecifier(customFormatSpecifier); - } - /// @brief Uninstalls user defined format specifier and handler - static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) { - return ELPP->uninstallCustomFormatSpecifier(formatSpecifier); - } - /// @brief Returns true if custom format specifier is installed - static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) { - return ELPP->hasCustomFormatSpecifier(formatSpecifier); - } - static inline void validateFileRolling(Logger* logger, Level level) { - if (logger == nullptr) return; - logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback()); - } -}; -/// @brief Static helpers to deal with loggers and their configurations -class Loggers : base::StaticClass { - public: - /// @brief Gets existing or registers new logger - static Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true); - /// @brief Changes default log builder for future loggers - static void setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr); - /// @brief Installs logger registration callback, this callback is triggered when new logger is registered - template - static inline bool installLoggerRegistrationCallback(const std::string& id) { - return ELPP->registeredLoggers()->installLoggerRegistrationCallback(id); - } - /// @brief Uninstalls log dispatch callback - template - static inline void uninstallLoggerRegistrationCallback(const std::string& id) { - ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback(id); - } - template - static inline T* loggerRegistrationCallback(const std::string& id) { - return ELPP->registeredLoggers()->loggerRegistrationCallback(id); - } - /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister - /// loggers initialized / used by third-party libs. - static bool unregisterLogger(const std::string& identity); - /// @brief Whether or not logger with id is registered - static bool hasLogger(const std::string& identity); - /// @brief Reconfigures specified logger with new configurations - static Logger* reconfigureLogger(Logger* logger, const Configurations& configurations); - /// @brief Reconfigures logger with new configurations after looking it up using identity - static Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations); - /// @brief Reconfigures logger's single configuration - static Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType, - const std::string& value); - /// @brief Reconfigures all the existing loggers with new configurations - static void reconfigureAllLoggers(const Configurations& configurations); - /// @brief Reconfigures single configuration for all the loggers - static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) { - reconfigureAllLoggers(Level::Global, configurationType, value); - } - /// @brief Reconfigures single configuration for all the loggers for specified level - static void reconfigureAllLoggers(Level level, ConfigurationType configurationType, - const std::string& value); - /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers - static void setDefaultConfigurations(const Configurations& configurations, - bool reconfigureExistingLoggers = false); - /// @brief Returns current default - static const Configurations* defaultConfigurations(void); - /// @brief Returns log stream reference pointer if needed by user - static const base::LogStreamsReferenceMap* logStreamsReference(void); - /// @brief Default typed configuration based on existing defaultConf - static base::TypedConfigurations defaultTypedConfigurations(void); - /// @brief Populates all logger IDs in current repository. - /// @param [out] targetList List of fill up. - static std::vector* populateAllLoggerIds(std::vector* targetList); - /// @brief Sets configurations from global configuration file. - static void configureFromGlobal(const char* globalConfigurationFilePath); - /// @brief Configures loggers using command line arg. Ensure you have already set command line args, - /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger. - /// If true is returned that does not mean it has been configured successfully, it only means that it - /// has attempeted to configure logger using configuration file provided in argument - static bool configureFromArg(const char* argKey); - /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered - static void flushAll(void); - /// @brief Adds logging flag used internally. - static inline void addFlag(LoggingFlag flag) { - ELPP->addFlag(flag); - } - /// @brief Removes logging flag used internally. - static inline void removeFlag(LoggingFlag flag) { - ELPP->removeFlag(flag); - } - /// @brief Determines whether or not certain flag is active - static inline bool hasFlag(LoggingFlag flag) { - return ELPP->hasFlag(flag); - } - /// @brief Adds flag and removes it when scope goes out - class ScopedAddFlag { - public: - ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { - Loggers::addFlag(m_flag); - } - ~ScopedAddFlag(void) { - Loggers::removeFlag(m_flag); - } - private: - LoggingFlag m_flag; - }; - /// @brief Removes flag and add it when scope goes out - class ScopedRemoveFlag { - public: - ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { - Loggers::removeFlag(m_flag); - } - ~ScopedRemoveFlag(void) { - Loggers::addFlag(m_flag); - } - private: - LoggingFlag m_flag; - }; - /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging) - static void setLoggingLevel(Level level) { - ELPP->setLoggingLevel(level); - } - /// @brief Sets verbose level on the fly - static void setVerboseLevel(base::type::VerboseLevel level); - /// @brief Gets current verbose level - static base::type::VerboseLevel verboseLevel(void); - /// @brief Sets vmodules as specified (on the fly) - static void setVModules(const char* modules); - /// @brief Clears vmodules - static void clearVModules(void); -}; -class VersionInfo : base::StaticClass { - public: - /// @brief Current version number - static const std::string version(void); - - /// @brief Release date of current version - static const std::string releaseDate(void); -}; -} // namespace el -#undef VLOG_IS_ON -/// @brief Determines whether verbose logging is on for specified level current file. -#define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__)) -#undef TIMED_BLOCK -#undef TIMED_SCOPE -#undef TIMED_SCOPE_IF -#undef TIMED_FUNC -#undef TIMED_FUNC_IF -#undef ELPP_MIN_UNIT -#if defined(ELPP_PERFORMANCE_MICROSECONDS) -# define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond -#else -# define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond -#endif // (defined(ELPP_PERFORMANCE_MICROSECONDS)) -/// @brief Performance tracked scope. Performance gets written when goes out of scope using -/// 'performance' logger. -/// -/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint(); -/// @see el::base::PerformanceTracker -/// @see el::base::PerformanceTracker::checkpoint -// Note: Do not surround this definition with null macro because of obj instance -#define TIMED_SCOPE_IF(obj, blockname, condition) el::base::type::PerformanceTrackerPtr obj( condition ? \ - new el::base::PerformanceTracker(blockname, ELPP_MIN_UNIT) : nullptr ) -#define TIMED_SCOPE(obj, blockname) TIMED_SCOPE_IF(obj, blockname, true) -#define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::type::PerformanceTrackerPtr timer; } obj = { 0, \ - el::base::type::PerformanceTrackerPtr(new el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT)) }; obj.i < 1; ++obj.i) -/// @brief Performance tracked function. Performance gets written when goes out of scope using -/// 'performance' logger. -/// -/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint(); -/// @see el::base::PerformanceTracker -/// @see el::base::PerformanceTracker::checkpoint -#define TIMED_FUNC_IF(obj,condition) TIMED_SCOPE_IF(obj, ELPP_FUNC, condition) -#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC) -#undef PERFORMANCE_CHECKPOINT -#undef PERFORMANCE_CHECKPOINT_WITH_ID -#define PERFORMANCE_CHECKPOINT(obj) obj->checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC) -#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj->checkpoint(id, __FILE__, __LINE__, ELPP_FUNC) -#undef ELPP_COUNTER -#undef ELPP_COUNTER_POS -/// @brief Gets hit counter for file/line -#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__)) -/// @brief Gets hit counter position for file/line, -1 if not registered yet -#define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts()) -// Undef levels to support LOG(LEVEL) -#undef INFO -#undef WARNING -#undef DEBUG -#undef ERROR -#undef FATAL -#undef TRACE -#undef VERBOSE -// Undef existing -#undef CINFO -#undef CWARNING -#undef CDEBUG -#undef CFATAL -#undef CERROR -#undef CTRACE -#undef CVERBOSE -#undef CINFO_IF -#undef CWARNING_IF -#undef CDEBUG_IF -#undef CERROR_IF -#undef CFATAL_IF -#undef CTRACE_IF -#undef CVERBOSE_IF -#undef CINFO_EVERY_N -#undef CWARNING_EVERY_N -#undef CDEBUG_EVERY_N -#undef CERROR_EVERY_N -#undef CFATAL_EVERY_N -#undef CTRACE_EVERY_N -#undef CVERBOSE_EVERY_N -#undef CINFO_AFTER_N -#undef CWARNING_AFTER_N -#undef CDEBUG_AFTER_N -#undef CERROR_AFTER_N -#undef CFATAL_AFTER_N -#undef CTRACE_AFTER_N -#undef CVERBOSE_AFTER_N -#undef CINFO_N_TIMES -#undef CWARNING_N_TIMES -#undef CDEBUG_N_TIMES -#undef CERROR_N_TIMES -#undef CFATAL_N_TIMES -#undef CTRACE_N_TIMES -#undef CVERBOSE_N_TIMES -// Normal logs -#if ELPP_INFO_LOG -# define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\ -el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#else -# define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// Conditional logs -#if ELPP_INFO_LOG -# define CINFO_IF(writer, condition_, dispatchAction, ...) \ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \ -el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#else -# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// Occasional logs -#if ELPP_INFO_LOG -# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// After N logs -#if ELPP_INFO_LOG -# define CINFO_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// N Times logs -#if ELPP_INFO_LOG -# define CINFO_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// -// Custom Loggers - Requires (level, dispatchAction, loggerId/s) -// -// undef existing -#undef CLOG -#undef CLOG_VERBOSE -#undef CVLOG -#undef CLOG_IF -#undef CLOG_VERBOSE_IF -#undef CVLOG_IF -#undef CLOG_EVERY_N -#undef CVLOG_EVERY_N -#undef CLOG_AFTER_N -#undef CVLOG_AFTER_N -#undef CLOG_N_TIMES -#undef CVLOG_N_TIMES -// Normal logs -#define CLOG(LEVEL, ...)\ -C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// Conditional logs -#define CLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_IF(condition, vlevel, ...)\ -CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// Hit counts based logs -#define CLOG_EVERY_N(n, LEVEL, ...)\ -C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_EVERY_N(n, vlevel, ...)\ -CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CLOG_AFTER_N(n, LEVEL, ...)\ -C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_AFTER_N(n, vlevel, ...)\ -CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CLOG_N_TIMES(n, LEVEL, ...)\ -C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_N_TIMES(n, vlevel, ...)\ -CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// -// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros -// -// undef existing -#undef LOG -#undef VLOG -#undef LOG_IF -#undef VLOG_IF -#undef LOG_EVERY_N -#undef VLOG_EVERY_N -#undef LOG_AFTER_N -#undef VLOG_AFTER_N -#undef LOG_N_TIMES -#undef VLOG_N_TIMES -#undef ELPP_CURR_FILE_LOGGER_ID -#if defined(ELPP_DEFAULT_LOGGER) -# define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER -#else -# define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId -#endif -#undef ELPP_TRACE -#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID) -// Normal logs -#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Conditional logs -#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Hit counts based logs -#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Generic PLOG() -#undef CPLOG -#undef CPLOG_IF -#undef PLOG -#undef PLOG_IF -#undef DCPLOG -#undef DCPLOG_IF -#undef DPLOG -#undef DPLOG_IF -#define CPLOG(LEVEL, ...)\ -C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CPLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define DCPLOG(LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define DCPLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -// Generic SYSLOG() -#undef CSYSLOG -#undef CSYSLOG_IF -#undef CSYSLOG_EVERY_N -#undef CSYSLOG_AFTER_N -#undef CSYSLOG_N_TIMES -#undef SYSLOG -#undef SYSLOG_IF -#undef SYSLOG_EVERY_N -#undef SYSLOG_AFTER_N -#undef SYSLOG_N_TIMES -#undef DCSYSLOG -#undef DCSYSLOG_IF -#undef DCSYSLOG_EVERY_N -#undef DCSYSLOG_AFTER_N -#undef DCSYSLOG_N_TIMES -#undef DSYSLOG -#undef DSYSLOG_IF -#undef DSYSLOG_EVERY_N -#undef DSYSLOG_AFTER_N -#undef DSYSLOG_N_TIMES -#if defined(ELPP_SYSLOG) -# define CSYSLOG(LEVEL, ...)\ -C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_EVERY_N(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_AFTER_N(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_N_TIMES(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) -#else -# define CSYSLOG(LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() -# define SYSLOG(LEVEL) el::base::NullWriter() -# define SYSLOG_IF(condition, LEVEL) el::base::NullWriter() -# define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() -# define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() -# define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() -# define DCSYSLOG(LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() -# define DSYSLOG(LEVEL) el::base::NullWriter() -# define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter() -# define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() -# define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() -# define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() -#endif // defined(ELPP_SYSLOG) -// -// Custom Debug Only Loggers - Requires (level, loggerId/s) -// -// undef existing -#undef DCLOG -#undef DCVLOG -#undef DCLOG_IF -#undef DCVLOG_IF -#undef DCLOG_EVERY_N -#undef DCVLOG_EVERY_N -#undef DCLOG_AFTER_N -#undef DCVLOG_AFTER_N -#undef DCLOG_N_TIMES -#undef DCVLOG_N_TIMES -// Normal logs -#define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__) -#define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__) -#define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__) -// Conditional logs -#define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__) -#define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__) -// Hit counts based logs -#define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__) -#define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__) -#define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__) -#define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__) -#define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__) -#define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__) -// -// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros -// -#if !defined(ELPP_NO_DEBUG_MACROS) -// undef existing -#undef DLOG -#undef DVLOG -#undef DLOG_IF -#undef DVLOG_IF -#undef DLOG_EVERY_N -#undef DVLOG_EVERY_N -#undef DLOG_AFTER_N -#undef DVLOG_AFTER_N -#undef DLOG_N_TIMES -#undef DVLOG_N_TIMES -// Normal logs -#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Conditional logs -#define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Hit counts based logs -#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#endif // defined(ELPP_NO_DEBUG_MACROS) -#if !defined(ELPP_NO_CHECK_MACROS) -// Check macros -#undef CCHECK -#undef CPCHECK -#undef CCHECK_EQ -#undef CCHECK_NE -#undef CCHECK_LT -#undef CCHECK_GT -#undef CCHECK_LE -#undef CCHECK_GE -#undef CCHECK_BOUNDS -#undef CCHECK_NOTNULL -#undef CCHECK_STRCASEEQ -#undef CCHECK_STRCASENE -#undef CHECK -#undef PCHECK -#undef CHECK_EQ -#undef CHECK_NE -#undef CHECK_LT -#undef CHECK_GT -#undef CHECK_LE -#undef CHECK_GE -#undef CHECK_BOUNDS -#undef CHECK_NOTNULL -#undef CHECK_STRCASEEQ -#undef CHECK_STRCASENE -#define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " -#define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " -#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__) -#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__) -#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__) -#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__) -#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__) -#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__) -#define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__) -#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) -#define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__) -#define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " == " << #str2 << "] " -#define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " != " << #str2 << "] " -#define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " == " << #str2 << "] " -#define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " != " << #str2 << "] " -#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#undef DCCHECK -#undef DCCHECK_EQ -#undef DCCHECK_NE -#undef DCCHECK_LT -#undef DCCHECK_GT -#undef DCCHECK_LE -#undef DCCHECK_GE -#undef DCCHECK_BOUNDS -#undef DCCHECK_NOTNULL -#undef DCCHECK_STRCASEEQ -#undef DCCHECK_STRCASENE -#undef DCPCHECK -#undef DCHECK -#undef DCHECK_EQ -#undef DCHECK_NE -#undef DCHECK_LT -#undef DCHECK_GT -#undef DCHECK_LE -#undef DCHECK_GE -#undef DCHECK_BOUNDS_ -#undef DCHECK_NOTNULL -#undef DCHECK_STRCASEEQ -#undef DCHECK_STRCASENE -#undef DPCHECK -#define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__) -#define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__) -#define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__) -#define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__) -#define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__) -#define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__) -#define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__) -#define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__) -#define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL((ptr), __VA_ARGS__) -#define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__) -#define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__) -#define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__) -#define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__) -#define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__) -#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#endif // defined(ELPP_NO_CHECK_MACROS) -#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) -# define ELPP_USE_DEF_CRASH_HANDLER false -#else -# define ELPP_USE_DEF_CRASH_HANDLER true -#endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) -#define ELPP_CRASH_HANDLER_INIT -#define ELPP_INIT_EASYLOGGINGPP(val) \ -namespace el { \ -namespace base { \ -el::base::type::StoragePointer elStorage(val); \ -} \ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \ -} - -#if ELPP_ASYNC_LOGGING -# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\ -new el::base::AsyncDispatchWorker())) -#else -# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()))) -#endif // ELPP_ASYNC_LOGGING -#define INITIALIZE_NULL_EASYLOGGINGPP \ -namespace el {\ -namespace base {\ -el::base::type::StoragePointer elStorage;\ -}\ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ -} -#define SHARE_EASYLOGGINGPP(initializedStorage)\ -namespace el {\ -namespace base {\ -el::base::type::StoragePointer elStorage(initializedStorage);\ -}\ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ -} - -#if defined(ELPP_UNICODE) -# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale("")) -#else -# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv) -#endif // defined(ELPP_UNICODE) -#endif // EASYLOGGINGPP_H diff --git a/vendor/README.md b/vendor/README.md new file mode 100644 index 0000000..72a8776 --- /dev/null +++ b/vendor/README.md @@ -0,0 +1,24 @@ +# Vendored Packages + +Some external dependencies are vendored here. Use +[git-vendor](https://github.com/brettlangdon/git-vendor) to view, +add, or update vendored packages. + +For example: + +```sh +$ git-vendor list +easylogging@master: + name: easylogging + dir: vendor/github.com/muflihun/easyloggingpp + repo: https://github.com/muflihun/easyloggingpp + ref: master + commit: e2b86551a5ba1d63b21b57a2bae1ddb0b0e5135e + +tinyxml2@master: + name: tinyxml2 + dir: vendor/github.com/leethomason/tinyxml2 + repo: https://github.com/leethomason/tinyxml2.git + ref: master + commit: 1979f3c87e68f489c7f6d88532aae4d76d9d3a78 +``` \ No newline at end of file From 57ff0e2fe8c01a551e5425474ab9cccf385f261d Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 5 Aug 2017 23:23:33 -0700 Subject: [PATCH 08/25] Squashed 'vendor/github.com/leethomason/tinyxml2/' content from commit 02d2764f git-subtree-dir: vendor/github.com/leethomason/tinyxml2 git-subtree-split: 02d2764fd794422c6d3c86cebe1c892e5a592d23 --- .gitignore | 18 + .travis.yml | 15 + CMakeLists.txt | 176 + Makefile | 19 + TinyXML2_small.png | Bin 0 -> 214977 bytes appveyor.yml | 7 + biicode.conf | 7 + cmake_uninstall.cmake.in | 21 + contrib/html5-printer.cpp | 108 + docs/_example-1.html | 75 + docs/_example-2.html | 75 + docs/_example-3.html | 104 + docs/_example-4.html | 81 + docs/annotated.html | 91 + docs/bc_s.png | Bin 0 -> 676 bytes docs/bdwn.png | Bin 0 -> 147 bytes docs/classes.html | 83 + ...stinyxml2_1_1_x_m_l_attribute-members.html | 103 + docs/classtinyxml2_1_1_x_m_l_attribute.html | 223 + ...asstinyxml2_1_1_x_m_l_comment-members.html | 113 + docs/classtinyxml2_1_1_x_m_l_comment.html | 300 ++ docs/classtinyxml2_1_1_x_m_l_comment.png | Bin 0 -> 650 bytes ...nyxml2_1_1_x_m_l_const_handle-members.html | 81 + .../classtinyxml2_1_1_x_m_l_const_handle.html | 87 + ...inyxml2_1_1_x_m_l_declaration-members.html | 113 + docs/classtinyxml2_1_1_x_m_l_declaration.html | 302 ++ docs/classtinyxml2_1_1_x_m_l_declaration.png | Bin 0 -> 688 bytes ...sstinyxml2_1_1_x_m_l_document-members.html | 137 + docs/classtinyxml2_1_1_x_m_l_document.html | 730 +++ docs/classtinyxml2_1_1_x_m_l_document.png | Bin 0 -> 657 bytes ...asstinyxml2_1_1_x_m_l_element-members.html | 158 + docs/classtinyxml2_1_1_x_m_l_element.html | 708 +++ docs/classtinyxml2_1_1_x_m_l_element.png | Bin 0 -> 618 bytes ...lasstinyxml2_1_1_x_m_l_handle-members.html | 98 + docs/classtinyxml2_1_1_x_m_l_handle.html | 189 + .../classtinyxml2_1_1_x_m_l_node-members.html | 113 + docs/classtinyxml2_1_1_x_m_l_node.html | 581 +++ docs/classtinyxml2_1_1_x_m_l_node.png | Bin 0 -> 1845 bytes ...asstinyxml2_1_1_x_m_l_printer-members.html | 106 + docs/classtinyxml2_1_1_x_m_l_printer.html | 410 ++ docs/classtinyxml2_1_1_x_m_l_printer.png | Bin 0 -> 586 bytes .../classtinyxml2_1_1_x_m_l_text-members.html | 115 + docs/classtinyxml2_1_1_x_m_l_text.html | 310 ++ docs/classtinyxml2_1_1_x_m_l_text.png | Bin 0 -> 591 bytes ...asstinyxml2_1_1_x_m_l_unknown-members.html | 113 + docs/classtinyxml2_1_1_x_m_l_unknown.html | 301 ++ docs/classtinyxml2_1_1_x_m_l_unknown.png | Bin 0 -> 647 bytes ...asstinyxml2_1_1_x_m_l_visitor-members.html | 89 + docs/classtinyxml2_1_1_x_m_l_visitor.html | 138 + docs/classtinyxml2_1_1_x_m_l_visitor.png | Bin 0 -> 592 bytes docs/closed.png | Bin 0 -> 132 bytes docs/doc.png | Bin 0 -> 746 bytes docs/doxygen.css | 1596 ++++++ docs/doxygen.png | Bin 0 -> 3779 bytes docs/dynsections.js | 97 + docs/files.html | 79 + docs/folderclosed.png | Bin 0 -> 616 bytes docs/folderopen.png | Bin 0 -> 597 bytes docs/functions.html | 544 ++ docs/functions_func.html | 544 ++ docs/hierarchy.html | 90 + docs/index.html | 230 + docs/jquery.js | 87 + docs/menu.js | 26 + docs/menudata.js | 52 + docs/nav_f.png | Bin 0 -> 153 bytes docs/nav_g.png | Bin 0 -> 95 bytes docs/nav_h.png | Bin 0 -> 98 bytes docs/open.png | Bin 0 -> 123 bytes docs/pages.html | 82 + docs/search/all_0.html | 26 + docs/search/all_0.js | 5 + docs/search/all_1.html | 26 + docs/search/all_1.js | 6 + docs/search/all_10.html | 26 + docs/search/all_10.js | 11 + docs/search/all_11.html | 26 + docs/search/all_11.js | 6 + docs/search/all_12.html | 26 + docs/search/all_12.js | 7 + docs/search/all_13.html | 26 + docs/search/all_13.js | 15 + docs/search/all_2.html | 26 + docs/search/all_2.js | 9 + docs/search/all_3.html | 26 + docs/search/all_3.js | 12 + docs/search/all_4.html | 26 + docs/search/all_4.js | 5 + docs/search/all_5.html | 26 + docs/search/all_5.js | 10 + docs/search/all_6.html | 26 + docs/search/all_6.js | 11 + docs/search/all_7.html | 26 + docs/search/all_7.js | 4 + docs/search/all_8.html | 26 + docs/search/all_8.js | 10 + docs/search/all_9.html | 26 + docs/search/all_9.js | 7 + docs/search/all_a.html | 26 + docs/search/all_a.js | 13 + docs/search/all_b.html | 26 + docs/search/all_b.js | 5 + docs/search/all_c.html | 26 + docs/search/all_c.js | 15 + docs/search/all_d.html | 26 + docs/search/all_d.js | 22 + docs/search/all_e.html | 26 + docs/search/all_e.js | 5 + docs/search/all_f.html | 26 + docs/search/all_f.js | 13 + docs/search/classes_0.html | 26 + docs/search/classes_0.js | 15 + docs/search/close.png | Bin 0 -> 273 bytes docs/search/functions_0.html | 26 + docs/search/functions_0.js | 5 + docs/search/functions_1.html | 26 + docs/search/functions_1.js | 6 + docs/search/functions_10.html | 26 + docs/search/functions_10.js | 10 + docs/search/functions_11.html | 26 + docs/search/functions_11.js | 6 + docs/search/functions_12.html | 26 + docs/search/functions_12.js | 7 + docs/search/functions_13.html | 26 + docs/search/functions_13.js | 6 + docs/search/functions_2.html | 26 + docs/search/functions_2.js | 9 + docs/search/functions_3.html | 26 + docs/search/functions_3.js | 12 + docs/search/functions_4.html | 26 + docs/search/functions_4.js | 5 + docs/search/functions_5.html | 26 + docs/search/functions_5.js | 10 + docs/search/functions_6.html | 26 + docs/search/functions_6.js | 10 + docs/search/functions_7.html | 26 + docs/search/functions_7.js | 4 + docs/search/functions_8.html | 26 + docs/search/functions_8.js | 10 + docs/search/functions_9.html | 26 + docs/search/functions_9.js | 6 + docs/search/functions_a.html | 26 + docs/search/functions_a.js | 13 + docs/search/functions_b.html | 26 + docs/search/functions_b.js | 5 + docs/search/functions_c.html | 26 + docs/search/functions_c.js | 14 + docs/search/functions_d.html | 26 + docs/search/functions_d.js | 22 + docs/search/functions_e.html | 26 + docs/search/functions_e.js | 4 + docs/search/functions_f.html | 26 + docs/search/functions_f.js | 13 + docs/search/mag_sel.png | Bin 0 -> 563 bytes docs/search/nomatches.html | 12 + docs/search/pages_0.html | 26 + docs/search/pages_0.js | 4 + docs/search/pages_1.html | 26 + docs/search/pages_1.js | 4 + docs/search/pages_2.html | 26 + docs/search/pages_2.js | 4 + docs/search/pages_3.html | 26 + docs/search/pages_3.js | 4 + docs/search/pages_4.html | 26 + docs/search/pages_4.js | 4 + docs/search/search.css | 271 + docs/search/search.js | 791 +++ docs/search/search_l.png | Bin 0 -> 604 bytes docs/search/search_m.png | Bin 0 -> 158 bytes docs/search/search_r.png | Bin 0 -> 612 bytes docs/search/searchdata.js | 24 + docs/splitbar.png | Bin 0 -> 314 bytes docs/sync_off.png | Bin 0 -> 853 bytes docs/sync_on.png | Bin 0 -> 845 bytes docs/tab_a.png | Bin 0 -> 142 bytes docs/tab_b.png | Bin 0 -> 169 bytes docs/tab_h.png | Bin 0 -> 177 bytes docs/tab_s.png | Bin 0 -> 184 bytes docs/tabs.css | 1 + docs/tinyxml2_8h_source.html | 180 + dox | 2441 +++++++++ readme.md | 335 ++ resources/dream.xml | 4546 +++++++++++++++++ resources/empty.xml | 0 resources/out/readme.txt | 1 + resources/utf8test.xml | 11 + resources/utf8testverify.xml | 11 + setversion.py | 123 + tinyxml2.cpp | 2741 ++++++++++ tinyxml2.h | 2264 ++++++++ tinyxml2.pc.in | 10 + tinyxml2/test.vcxproj | 352 ++ tinyxml2/test.vcxproj.filters | 6 + tinyxml2/tinyxml2-cbp/README | 3 + tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp | 49 + tinyxml2/tinyxml2.sln | 56 + tinyxml2/tinyxml2.vcxproj | 393 ++ tinyxml2/tinyxml2.vcxproj.filters | 9 + tinyxml2/tinyxml2.xcodeproj/project.pbxproj | 211 + xmltest.cpp | 2158 ++++++++ 200 files changed, 28523 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 TinyXML2_small.png create mode 100644 appveyor.yml create mode 100644 biicode.conf create mode 100644 cmake_uninstall.cmake.in create mode 100644 contrib/html5-printer.cpp create mode 100644 docs/_example-1.html create mode 100644 docs/_example-2.html create mode 100644 docs/_example-3.html create mode 100644 docs/_example-4.html create mode 100644 docs/annotated.html create mode 100644 docs/bc_s.png create mode 100644 docs/bdwn.png create mode 100644 docs/classes.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_attribute-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_attribute.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_comment-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_comment.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_comment.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_const_handle-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_const_handle.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_declaration-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_declaration.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_declaration.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_document-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_document.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_document.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_element-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_element.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_element.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_handle-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_handle.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_node-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_node.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_node.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_printer-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_printer.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_printer.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_text-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_text.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_text.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_unknown-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_unknown.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_unknown.png create mode 100644 docs/classtinyxml2_1_1_x_m_l_visitor-members.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_visitor.html create mode 100644 docs/classtinyxml2_1_1_x_m_l_visitor.png create mode 100644 docs/closed.png create mode 100644 docs/doc.png create mode 100644 docs/doxygen.css create mode 100644 docs/doxygen.png create mode 100644 docs/dynsections.js create mode 100644 docs/files.html create mode 100644 docs/folderclosed.png create mode 100644 docs/folderopen.png create mode 100644 docs/functions.html create mode 100644 docs/functions_func.html create mode 100644 docs/hierarchy.html create mode 100644 docs/index.html create mode 100644 docs/jquery.js create mode 100644 docs/menu.js create mode 100644 docs/menudata.js create mode 100644 docs/nav_f.png create mode 100644 docs/nav_g.png create mode 100644 docs/nav_h.png create mode 100644 docs/open.png create mode 100644 docs/pages.html create mode 100644 docs/search/all_0.html create mode 100644 docs/search/all_0.js create mode 100644 docs/search/all_1.html create mode 100644 docs/search/all_1.js create mode 100644 docs/search/all_10.html create mode 100644 docs/search/all_10.js create mode 100644 docs/search/all_11.html create mode 100644 docs/search/all_11.js create mode 100644 docs/search/all_12.html create mode 100644 docs/search/all_12.js create mode 100644 docs/search/all_13.html create mode 100644 docs/search/all_13.js create mode 100644 docs/search/all_2.html create mode 100644 docs/search/all_2.js create mode 100644 docs/search/all_3.html create mode 100644 docs/search/all_3.js create mode 100644 docs/search/all_4.html create mode 100644 docs/search/all_4.js create mode 100644 docs/search/all_5.html create mode 100644 docs/search/all_5.js create mode 100644 docs/search/all_6.html create mode 100644 docs/search/all_6.js create mode 100644 docs/search/all_7.html create mode 100644 docs/search/all_7.js create mode 100644 docs/search/all_8.html create mode 100644 docs/search/all_8.js create mode 100644 docs/search/all_9.html create mode 100644 docs/search/all_9.js create mode 100644 docs/search/all_a.html create mode 100644 docs/search/all_a.js create mode 100644 docs/search/all_b.html create mode 100644 docs/search/all_b.js create mode 100644 docs/search/all_c.html create mode 100644 docs/search/all_c.js create mode 100644 docs/search/all_d.html create mode 100644 docs/search/all_d.js create mode 100644 docs/search/all_e.html create mode 100644 docs/search/all_e.js create mode 100644 docs/search/all_f.html create mode 100644 docs/search/all_f.js create mode 100644 docs/search/classes_0.html create mode 100644 docs/search/classes_0.js create mode 100644 docs/search/close.png create mode 100644 docs/search/functions_0.html create mode 100644 docs/search/functions_0.js create mode 100644 docs/search/functions_1.html create mode 100644 docs/search/functions_1.js create mode 100644 docs/search/functions_10.html create mode 100644 docs/search/functions_10.js create mode 100644 docs/search/functions_11.html create mode 100644 docs/search/functions_11.js create mode 100644 docs/search/functions_12.html create mode 100644 docs/search/functions_12.js create mode 100644 docs/search/functions_13.html create mode 100644 docs/search/functions_13.js create mode 100644 docs/search/functions_2.html create mode 100644 docs/search/functions_2.js create mode 100644 docs/search/functions_3.html create mode 100644 docs/search/functions_3.js create mode 100644 docs/search/functions_4.html create mode 100644 docs/search/functions_4.js create mode 100644 docs/search/functions_5.html create mode 100644 docs/search/functions_5.js create mode 100644 docs/search/functions_6.html create mode 100644 docs/search/functions_6.js create mode 100644 docs/search/functions_7.html create mode 100644 docs/search/functions_7.js create mode 100644 docs/search/functions_8.html create mode 100644 docs/search/functions_8.js create mode 100644 docs/search/functions_9.html create mode 100644 docs/search/functions_9.js create mode 100644 docs/search/functions_a.html create mode 100644 docs/search/functions_a.js create mode 100644 docs/search/functions_b.html create mode 100644 docs/search/functions_b.js create mode 100644 docs/search/functions_c.html create mode 100644 docs/search/functions_c.js create mode 100644 docs/search/functions_d.html create mode 100644 docs/search/functions_d.js create mode 100644 docs/search/functions_e.html create mode 100644 docs/search/functions_e.js create mode 100644 docs/search/functions_f.html create mode 100644 docs/search/functions_f.js create mode 100644 docs/search/mag_sel.png create mode 100644 docs/search/nomatches.html create mode 100644 docs/search/pages_0.html create mode 100644 docs/search/pages_0.js create mode 100644 docs/search/pages_1.html create mode 100644 docs/search/pages_1.js create mode 100644 docs/search/pages_2.html create mode 100644 docs/search/pages_2.js create mode 100644 docs/search/pages_3.html create mode 100644 docs/search/pages_3.js create mode 100644 docs/search/pages_4.html create mode 100644 docs/search/pages_4.js create mode 100644 docs/search/search.css create mode 100644 docs/search/search.js create mode 100644 docs/search/search_l.png create mode 100644 docs/search/search_m.png create mode 100644 docs/search/search_r.png create mode 100644 docs/search/searchdata.js create mode 100644 docs/splitbar.png create mode 100644 docs/sync_off.png create mode 100644 docs/sync_on.png create mode 100644 docs/tab_a.png create mode 100644 docs/tab_b.png create mode 100644 docs/tab_h.png create mode 100644 docs/tab_s.png create mode 100644 docs/tabs.css create mode 100644 docs/tinyxml2_8h_source.html create mode 100644 dox create mode 100644 readme.md create mode 100755 resources/dream.xml create mode 100644 resources/empty.xml create mode 100644 resources/out/readme.txt create mode 100755 resources/utf8test.xml create mode 100755 resources/utf8testverify.xml create mode 100755 setversion.py create mode 100755 tinyxml2.cpp create mode 100755 tinyxml2.h create mode 100644 tinyxml2.pc.in create mode 100644 tinyxml2/test.vcxproj create mode 100644 tinyxml2/test.vcxproj.filters create mode 100644 tinyxml2/tinyxml2-cbp/README create mode 100644 tinyxml2/tinyxml2-cbp/tinyxml2-cbp.cbp create mode 100755 tinyxml2/tinyxml2.sln create mode 100755 tinyxml2/tinyxml2.vcxproj create mode 100755 tinyxml2/tinyxml2.vcxproj.filters create mode 100644 tinyxml2/tinyxml2.xcodeproj/project.pbxproj create mode 100644 xmltest.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca32242 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# intermediate files +Win32/ +x64/ +ipch/ +resources/out/ +tinyxml2/tinyxml2-cbp/bin/ +tinyxml2/tinyxml2-cbp/obj/ +tinyxml2/bin/ +tinyxml2/temp/ +*.sdf +*.suo +*.opensdf +*.user +*.depend +*.layout +*.o +*.vc.db +*.vc.opendb \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0634ccb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: cpp + +os: + - linux + - osx + +compiler: + - g++ + - clang + +before_script: cmake . + +script: + - make -j3 + - make test diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cec4470 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,176 @@ +IF(BIICODE) + ADD_BIICODE_TARGETS() + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/resources) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/resources DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + ENDIF() + RETURN() +ENDIF(BIICODE) +cmake_minimum_required(VERSION 2.6 FATAL_ERROR) +cmake_policy(VERSION 2.6) +if(POLICY CMP0063) + cmake_policy(SET CMP0063 OLD) +endif() + +project(tinyxml2) +include(GNUInstallDirs) +include(CTest) +#enable_testing() + +#CMAKE_BUILD_TOOL + +################################ +# set lib version here + +set(GENERIC_LIB_VERSION "5.0.1") +set(GENERIC_LIB_SOVERSION "5") + +################################ +# Add definitions + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") + +################################ +# Add targets +# By Default shared libray is being built +# To build static libs also - Do cmake . -DBUILD_STATIC_LIBS:BOOL=ON +# User can choose not to build shared library by using cmake -DBUILD_SHARED_LIBS:BOOL=OFF +# To build only static libs use cmake . -DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_STATIC_LIBS:BOOL=ON +# To build the tests, use cmake . -DBUILD_TESTS:BOOL=ON +# To disable the building of the tests, use cmake . -DBUILD_TESTS:BOOL=OFF + +option(BUILD_SHARED_LIBS "build as shared library" ON) +option(BUILD_STATIC_LIBS "build as static library" OFF) +option(BUILD_TESTS "build xmltest (deprecated: Use BUILD_TESTING)" ON) + +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +# to distinguish between debug and release lib +set(CMAKE_DEBUG_POSTFIX "d") + +if(BUILD_SHARED_LIBS) +add_library(tinyxml2 SHARED tinyxml2.cpp tinyxml2.h) + +set_target_properties(tinyxml2 PROPERTIES + COMPILE_DEFINITIONS "TINYXML2_EXPORT" + VERSION "${GENERIC_LIB_VERSION}" + SOVERSION "${GENERIC_LIB_SOVERSION}") + + +if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_include_directories(tinyxml2 PUBLIC + $ + $) + + if(MSVC) + target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +else() + include_directories(${PROJECT_SOURCE_DIR}) + + if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +endif() + +# export targets for find_package config mode +export(TARGETS tinyxml2 + FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake) + +install(TARGETS tinyxml2 + EXPORT ${CMAKE_PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +if(BUILD_STATIC_LIBS) +add_library(tinyxml2_static STATIC tinyxml2.cpp tinyxml2.h) +set_target_properties(tinyxml2_static PROPERTIES + COMPILE_DEFINITONS "TINYXML2_EXPORT" + VERSION "${GENERIC_LIB_VERSION}" + SOVERSION "${GENERIC_LIB_SOVERSION}") +set_target_properties( tinyxml2_static PROPERTIES OUTPUT_NAME tinyxml2 ) + +target_compile_definitions(tinyxml2_static PUBLIC -D_CRT_SECURE_NO_WARNINGS) + +if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_include_directories(tinyxml2_static PUBLIC + $ + $) + + if(MSVC) + target_compile_definitions(tinyxml2_static PUBLIC -D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +else() + include_directories(${PROJECT_SOURCE_DIR}) + + if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + endif(MSVC) +endif() + +# export targets for find_package config mode +export(TARGETS tinyxml2_static + FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake) + +install(TARGETS tinyxml2_static + EXPORT ${CMAKE_PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +if(BUILD_TESTING AND BUILD_TESTS) + add_executable(xmltest xmltest.cpp) + if(BUILD_SHARED_LIBS) + add_dependencies(xmltest tinyxml2) + target_link_libraries(xmltest tinyxml2) + else(BUILD_STATIC_LIBS) + add_dependencies(xmltest tinyxml2_static) + target_link_libraries(xmltest tinyxml2_static) + endif() + + # Copy test resources and create test output directory + add_custom_command(TARGET xmltest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources $/resources + COMMAND ${CMAKE_COMMAND} -E make_directory $/resources/out + COMMENT "Configuring xmltest resources directory: ${CMAKE_BINARY_DIR}/resources" + ) + + add_test(NAME xmltest COMMAND xmltest) +endif() + +install(FILES tinyxml2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +foreach(p LIB INCLUDE) + set(var CMAKE_INSTALL_${p}DIR) + if(NOT IS_ABSOLUTE "${${var}}") + set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + endif() +endforeach() + +configure_file(tinyxml2.pc.in tinyxml2.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +# uninstall target +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + +file(WRITE + ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n") + +install(FILES + ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) + +install(EXPORT ${CMAKE_PROJECT_NAME}Targets + DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..eba6fef --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +all: xmltest staticlib + +rebuild: clean all + +xmltest: xmltest.cpp libtinyxml2.a + +clean: + $(RM) *.o xmltest libtinyxml2.a + +test: clean xmltest + ./xmltest + +staticlib: libtinyxml2.a + +libtinyxml2.a: tinyxml2.o + $(AR) $(ARFLAGS)s $@ $^ + +tinyxml2.o: tinyxml2.cpp tinyxml2.h + diff --git a/TinyXML2_small.png b/TinyXML2_small.png new file mode 100644 index 0000000000000000000000000000000000000000..6e84b3535dc814954bd28b7d5af43e669e9d60ca GIT binary patch literal 214977 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%0Db!0#!36BY(O6t_T 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

-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

h=>#bC{jbnQ#R(8T6DhXGd0cJ>d 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" (line break) +// All other elements are called "non-void" and MUST never self-close. +// Examples: "
". + +// tinyxml2::XMLPrinter will emit _ALL_ XML elements with no inner content as +// self-closing. This behavior produces space-effeceint XML, but incorrect HTML5. + +// Author: Dennis Jenkins, dennis (dot) jenkins (dot) 75 (at) gmail (dot) com. +// License: Same as tinyxml2 (zlib, see below) +// This example is a small contribution to the world! Enjoy it! + +/* +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#include +#include + +#if defined (_MSC_VER) +#define strcasecmp stricmp +#endif + +using namespace tinyxml2; + +// Contrived input containing a mix of void and non-void HTML5 elements. +// When printed via XMLPrinter, some non-void elements will self-close (not valid HTML5). +static const char input[] = +"


©
"; + +// XMLPrinterHTML5 is small enough, just put the entire implementation inline. +class XMLPrinterHTML5 : public XMLPrinter +{ +public: + XMLPrinterHTML5 (FILE* file=0, bool compact = false, int depth = 0) : + XMLPrinter (file, compact, depth) + {} + +protected: + virtual void CloseElement () { + if (_elementJustOpened && !isVoidElement (_stack.PeekTop())) { + SealElementIfJustOpened(); + } + XMLPrinter::CloseElement(); + } + + virtual bool isVoidElement (const char *name) { +// Complete list of all HTML5 "void elements", +// http://dev.w3.org/html5/markup/syntax.html + static const char *list[] = { + "area", "base", "br", "col", "command", "embed", "hr", "img", + "input", "keygen", "link", "meta", "param", "source", "track", "wbr", + NULL + }; + +// I could use 'bsearch', but I don't have MSVC to test on (it would work with gcc/libc). + for (const char **p = list; *p; ++p) { + if (!strcasecmp (name, *p)) { + return true; + } + } + + return false; + } +}; + +int main (void) { + XMLDocument doc (false); + doc.Parse (input); + + std::cout << "INPUT:\n" << input << "\n\n"; + + XMLPrinter prn (NULL, true); + doc.Print (&prn); + std::cout << "XMLPrinter (not valid HTML5):\n" << prn.CStr() << "\n\n"; + + XMLPrinterHTML5 html5 (NULL, true); + doc.Print (&html5); + std::cout << "XMLPrinterHTML5:\n" << html5.CStr() << "\n"; + + return 0; +} diff --git a/docs/_example-1.html b/docs/_example-1.html new file mode 100644 index 0000000..7eb126b --- /dev/null +++ b/docs/_example-1.html @@ -0,0 +1,75 @@ + + + + + + + +TinyXML-2: Load an XML File + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
Load an XML File
+
+
+
Basic XML file loading. The basic syntax to load an XML file from disk and check for an error. (ErrorID() will return 0 for no error.)
int example_1()
{
XMLDocument doc;
doc.LoadFile( "resources/dream.xml" );
return doc.ErrorID();
}

+
+ +
+ + diff --git a/docs/_example-2.html b/docs/_example-2.html new file mode 100644 index 0000000..e44cf86 --- /dev/null +++ b/docs/_example-2.html @@ -0,0 +1,75 @@ + + + + + + + +TinyXML-2: Parse an XML from char buffer + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
Parse an XML from char buffer
+
+
+
Basic XML string parsing. The basic syntax to parse an XML for a char* and check for an error. (ErrorID() will return 0 for no error.)
int example_2()
{
static const char* xml = "<element/>";
XMLDocument doc;
doc.Parse( xml );
return doc.ErrorID();
}

+
+ + + + diff --git a/docs/_example-3.html b/docs/_example-3.html new file mode 100644 index 0000000..9a7787e --- /dev/null +++ b/docs/_example-3.html @@ -0,0 +1,104 @@ + + + + + + + +TinyXML-2: Get information out of XML + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
Get information out of XML
+
+
+
In this example, we navigate a simple XML file, and read some interesting text. Note that this example doesn't use error checking; working code should check for null pointers when walking an XML tree, or use XMLHandle.

+

(The XML is an excerpt from "dream.xml").

+

int example_3()
{
static const char* xml =
"<?xml version=\"1.0\"?>"
"<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
"<PLAY>"
"<TITLE>A Midsummer Night's Dream</TITLE>"
"</PLAY>";

+

The structure of the XML file is:

+
    +
  • +(declaration)
  • +
  • +(dtd stuff)
  • +
  • +Element "PLAY"
      +
    • +Element "TITLE"
        +
      • +Text "A Midsummer Night's Dream"
      • +
      +
    • +
    +
  • +
+

For this example, we want to print out the title of the play. The text of the title (what we want) is child of the "TITLE" element which is a child of the "PLAY" element.

+

We want to skip the declaration and dtd, so the method FirstChildElement() is a good choice. The FirstChildElement() of the Document is the "PLAY" Element, the FirstChildElement() of the "PLAY" Element is the "TITLE" Element.

+

XMLDocument doc;
doc.Parse( xml );
XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );

+

We can then use the convenience function GetText() to get the title of the play.

+

const char* title = titleElement->GetText();
printf( "Name of play (1): %s\n", title );

+

Text is just another Node in the XML DOM. And in fact you should be a little cautious with it, as text nodes can contain elements.

+
Consider: A Midsummer Night's <b>Dream</b>
+

It is more correct to actually query the Text Node if in doubt:

+

XMLText* textNode = titleElement->FirstChild()->ToText();
title = textNode->Value();
printf( "Name of play (2): %s\n", title );

+

Noting that here we use FirstChild() since we are looking for XMLText, not an element, and ToText() is a cast from a Node to a XMLText.

+
+ + + + diff --git a/docs/_example-4.html b/docs/_example-4.html new file mode 100644 index 0000000..67795e6 --- /dev/null +++ b/docs/_example-4.html @@ -0,0 +1,81 @@ + + + + + + + +TinyXML-2: Read attributes and text information. + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
Read attributes and text information.
+
+
+

There are fundamentally 2 ways of writing a key-value pair into an XML file. (Something that's always annoyed me about XML.) Either by using attributes, or by writing the key name into an element and the value into the text node wrapped by the element. Both approaches are illustrated in this example, which shows two ways to encode the value "2" into the key "v":

+

bool example_4()
{
static const char* xml =
"<information>"
" <attributeApproach v='2' />"
" <textApproach>"
" <v>2</v>"
" </textApproach>"
"</information>";

+

TinyXML-2 has accessors for both approaches.

+

When using an attribute, you navigate to the XMLElement with that attribute and use the QueryIntAttribute() group of methods. (Also QueryFloatAttribute(), etc.)

+

XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
attributeApproachElement->QueryIntAttribute( "v", &v0 );

+

When using the text approach, you need to navigate down one more step to the XMLElement that contains the text. Note the extra FirstChildElement( "v" ) in the code below. The value of the text can then be safely queried with the QueryIntText() group of methods. (Also QueryFloatText(), etc.)

+

XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );

+
+ + + + diff --git a/docs/annotated.html b/docs/annotated.html new file mode 100644 index 0000000..14c03a1 --- /dev/null +++ b/docs/annotated.html @@ -0,0 +1,91 @@ + + + + + + + +TinyXML-2: Class List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class List
+
+
+
Here are the classes, structs, unions and interfaces with brief descriptions:
+
[detail level 12]
+ + + + + + + + + + + + + +
 Ntinyxml2
 CXMLAttribute
 CXMLComment
 CXMLConstHandle
 CXMLDeclaration
 CXMLDocument
 CXMLElement
 CXMLHandle
 CXMLNode
 CXMLPrinter
 CXMLText
 CXMLUnknown
 CXMLVisitor
+
+
+ + + + diff --git a/docs/bc_s.png b/docs/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..224b29aa9847d5a4b3902efd602b7ddf7d33e6c2 GIT binary patch literal 676 zcmV;V0$crwP)y__>=_9%My z{n931IS})GlGUF8K#6VIbs%684A^L3@%PlP2>_sk`UWPq@f;rU*V%rPy_ekbhXT&s z(GN{DxFv}*vZp`F>S!r||M`I*nOwwKX+BC~3P5N3-)Y{65c;ywYiAh-1*hZcToLHK ztpl1xomJ+Yb}K(cfbJr2=GNOnT!UFA7Vy~fBz8?J>XHsbZoDad^8PxfSa0GDgENZS zuLCEqzb*xWX2CG*b&5IiO#NzrW*;`VC9455M`o1NBh+(k8~`XCEEoC1Ybwf;vr4K3 zg|EB<07?SOqHp9DhLpS&bzgo70I+ghB_#)K7H%AMU3v}xuyQq9&Bm~++VYhF09a+U zl7>n7Jjm$K#b*FONz~fj;I->Bf;ule1prFN9FovcDGBkpg>)O*-}eLnC{6oZHZ$o% zXKW$;0_{8hxHQ>l;_*HATI(`7t#^{$(zLe}h*mqwOc*nRY9=?Sx4OOeVIfI|0V(V2 zBrW#G7Ss9wvzr@>H*`r>zE z+e8bOBgqIgldUJlG(YUDviMB`9+DH8n-s9SXRLyJHO1!=wY^79WYZMTa(wiZ!zP66 zA~!21vmF3H2{ngD;+`6j#~6j;$*f*G_2ZD1E;9(yaw7d-QnSCpK(cR1zU3qU0000< KMNUMnLSTYoA~SLT literal 0 HcmV?d00001 diff --git a/docs/bdwn.png b/docs/bdwn.png new file mode 100644 index 0000000000000000000000000000000000000000..940a0b950443a0bb1b216ac03c45b8a16c955452 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PKZC{Gv1kP61Pb5HX&C2wk~_T + + + + + + +TinyXML-2: Class Index + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class Index
+
+
+ + + + + + +
  x  
+
XMLComment (tinyxml2)   XMLDocument (tinyxml2)   XMLNode (tinyxml2)   XMLUnknown (tinyxml2)   
XMLConstHandle (tinyxml2)   XMLElement (tinyxml2)   XMLPrinter (tinyxml2)   XMLVisitor (tinyxml2)   
XMLAttribute (tinyxml2)   XMLDeclaration (tinyxml2)   XMLHandle (tinyxml2)   XMLText (tinyxml2)   
+ +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_attribute-members.html b/docs/classtinyxml2_1_1_x_m_l_attribute-members.html new file mode 100644 index 0000000..4eb1504 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_attribute-members.html @@ -0,0 +1,103 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLAttribute Member List
+
+ + + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_attribute.html b/docs/classtinyxml2_1_1_x_m_l_attribute.html new file mode 100644 index 0000000..d147670 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_attribute.html @@ -0,0 +1,223 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLAttribute Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLAttribute Class Reference
+
+
+ +

#include <tinyxml2.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+const char * Name () const
 The name of the attribute.
 
+const char * Value () const
 The value of the attribute.
 
+int GetLineNum () const
 Gets the line number the attribute is in, if the document was parsed from a file.
 
+const XMLAttributeNext () const
 The next attribute in the list.
 
int IntValue () const
 
+unsigned UnsignedValue () const
 Query as an unsigned integer. See IntValue()
 
+bool BoolValue () const
 Query as a boolean. See IntValue()
 
+double DoubleValue () const
 Query as a double. See IntValue()
 
+float FloatValue () const
 Query as a float. See IntValue()
 
XMLError QueryIntValue (int *value) const
 
+XMLError QueryUnsignedValue (unsigned int *value) const
 See QueryIntValue.
 
+XMLError QueryInt64Value (int64_t *value) const
 See QueryIntValue.
 
+XMLError QueryBoolValue (bool *value) const
 See QueryIntValue.
 
+XMLError QueryDoubleValue (double *value) const
 See QueryIntValue.
 
+XMLError QueryFloatValue (float *value) const
 See QueryIntValue.
 
+void SetAttribute (const char *value)
 Set the attribute to a string value.
 
+void SetAttribute (int value)
 Set the attribute to value.
 
+void SetAttribute (unsigned value)
 Set the attribute to value.
 
+void SetAttribute (int64_t value)
 Set the attribute to value.
 
+void SetAttribute (bool value)
 Set the attribute to value.
 
+void SetAttribute (double value)
 Set the attribute to value.
 
+void SetAttribute (float value)
 Set the attribute to value.
 
+

Detailed Description

+

An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name.

+
Note
The attributes are not XMLNodes. You may only query the Next() attribute in a list.
+

Member Function Documentation

+ +

◆ IntValue()

+ +
+
+ + + + + +
+ + + + + + + +
int tinyxml2::XMLAttribute::IntValue () const
+
+inline
+
+

IntValue interprets the attribute as an integer, and returns the value. If the value isn't an integer, 0 will be returned. There is no error checking; use QueryIntValue() if you need error checking.

+ +
+
+ +

◆ QueryIntValue()

+ +
+
+ + + + + + + + +
XMLError tinyxml2::XMLAttribute::QueryIntValue (int * value) const
+
+

QueryIntValue interprets the attribute as an integer, and returns the value in the provided parameter. The function will return XML_SUCCESS on success, and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_comment-members.html b/docs/classtinyxml2_1_1_x_m_l_comment-members.html new file mode 100644 index 0000000..7465cb1 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_comment-members.html @@ -0,0 +1,113 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLComment Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLComment, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) consttinyxml2::XMLCommentvirtual
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetLineNum() consttinyxml2::XMLNodeinline
GetUserData() consttinyxml2::XMLNodeinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *document) consttinyxml2::XMLCommentvirtual
ShallowEqual(const XMLNode *compare) consttinyxml2::XMLCommentvirtual
ToComment()tinyxml2::XMLCommentinlinevirtual
ToDeclaration()tinyxml2::XMLNodeinlinevirtual
ToDocument()tinyxml2::XMLNodeinlinevirtual
ToElement()tinyxml2::XMLNodeinlinevirtual
ToText()tinyxml2::XMLNodeinlinevirtual
ToUnknown()tinyxml2::XMLNodeinlinevirtual
Value() consttinyxml2::XMLNode
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_comment.html b/docs/classtinyxml2_1_1_x_m_l_comment.html new file mode 100644 index 0000000..66df8c1 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_comment.html @@ -0,0 +1,300 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLComment Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLComment Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLComment:
+
+
+ + +tinyxml2::XMLNode + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
virtual bool Accept (XMLVisitor *visitor) const
 
virtual XMLNodeShallowClone (XMLDocument *document) const
 
virtual bool ShallowEqual (const XMLNode *compare) const
 
- Public Member Functions inherited from tinyxml2::XMLNode
+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
XMLNodeDeepClone (XMLDocument *target) const
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

An XML Comment.

+

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLComment::Accept (XMLVisitorvisitor) const
+
+virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLComment::ShallowClone (XMLDocumentdocument) const
+
+virtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLComment::ShallowEqual (const XMLNodecompare) const
+
+virtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_comment.png b/docs/classtinyxml2_1_1_x_m_l_comment.png new file mode 100644 index 0000000000000000000000000000000000000000..3a076f05c0f83dc3e8e2d11062ee57c9d8c2a377 GIT binary patch literal 650 zcmeAS@N?(olHy`uVBq!ia0vp^y+9nm!3-pY71+{%lth3}i0l9V|AEXGZ@!lHADRGU zf$@O@2Ut7r$OE|?B|(0{3_wL7aP?G(5d#C0q^FBxNCo5Dxexo6Ce`0>f z0k-Im&&;f!T$0WzWSO;z@$czPI;TxGcwACx=~ej&!WL$k+LKC7-kNvmV)lL`=Kj;S zuJBG@BD}9xr~(H=9)QXy)0C>c`CP)|hUd|8DlT7c;t5WK;dOhGx$@Sn^}JvFgcb z?Ca${e+jmk?bkHk@-uYik2dd1tcl8=c9(DJoZfVX=>Y!+rWtK3bK=&|ELpax^0dzq z_!i{ad;5g=07T zI1VVUI+Dm-;6887)tjQ59hARmEX$vK{@3sLxrF>3m;jn6shG>G-nP36nI8mz>>KyChoLWBH}fax=@>dwunTdAd&( z&#s+qzj39%_agnjiodTc%a^|?Q=OD^xz*INxg_vi*eYAAXG#YHv+CZi+h+FEHaRQ& zMTW-gpU-0d%r*bgdUm><_`b8-_r-qXW&gk_%`pFEPLNlo*guA)_HxFp)r-1;35UVc L)z4*}Q$iB}2?{U4 literal 0 HcmV?d00001 diff --git a/docs/classtinyxml2_1_1_x_m_l_const_handle-members.html b/docs/classtinyxml2_1_1_x_m_l_const_handle-members.html new file mode 100644 index 0000000..6b25d49 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_const_handle-members.html @@ -0,0 +1,81 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLConstHandle Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLConstHandle, including all inherited members.

+ +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_const_handle.html b/docs/classtinyxml2_1_1_x_m_l_const_handle.html new file mode 100644 index 0000000..0b2c8b6 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_const_handle.html @@ -0,0 +1,87 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLConstHandle Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLConstHandle Class Reference
+
+
+ +

#include <tinyxml2.h>

+

Detailed Description

+

A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the same in all regards, except for the 'const' qualifiers. See XMLHandle for API.

+

The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_declaration-members.html b/docs/classtinyxml2_1_1_x_m_l_declaration-members.html new file mode 100644 index 0000000..4e1bee2 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_declaration-members.html @@ -0,0 +1,113 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLDeclaration Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLDeclaration, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) consttinyxml2::XMLDeclarationvirtual
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetLineNum() consttinyxml2::XMLNodeinline
GetUserData() consttinyxml2::XMLNodeinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *document) consttinyxml2::XMLDeclarationvirtual
ShallowEqual(const XMLNode *compare) consttinyxml2::XMLDeclarationvirtual
ToComment()tinyxml2::XMLNodeinlinevirtual
ToDeclaration()tinyxml2::XMLDeclarationinlinevirtual
ToDocument()tinyxml2::XMLNodeinlinevirtual
ToElement()tinyxml2::XMLNodeinlinevirtual
ToText()tinyxml2::XMLNodeinlinevirtual
ToUnknown()tinyxml2::XMLNodeinlinevirtual
Value() consttinyxml2::XMLNode
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_declaration.html b/docs/classtinyxml2_1_1_x_m_l_declaration.html new file mode 100644 index 0000000..1aa2eab --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_declaration.html @@ -0,0 +1,302 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLDeclaration Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLDeclaration Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLDeclaration:
+
+
+ + +tinyxml2::XMLNode + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
virtual bool Accept (XMLVisitor *visitor) const
 
virtual XMLNodeShallowClone (XMLDocument *document) const
 
virtual bool ShallowEqual (const XMLNode *compare) const
 
- Public Member Functions inherited from tinyxml2::XMLNode
+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
XMLNodeDeepClone (XMLDocument *target) const
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

In correct XML the declaration is the first entry in the file.

    <?xml version="1.0" standalone="yes"?>
+

TinyXML-2 will happily read or write files without a declaration, however.

+

The text of the declaration isn't interpreted. It is parsed and written as a string.

+

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLDeclaration::Accept (XMLVisitorvisitor) const
+
+virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLDeclaration::ShallowClone (XMLDocumentdocument) const
+
+virtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLDeclaration::ShallowEqual (const XMLNodecompare) const
+
+virtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_declaration.png b/docs/classtinyxml2_1_1_x_m_l_declaration.png new file mode 100644 index 0000000000000000000000000000000000000000..c7aa6319fcb939dc39dc72310971fd68db7611eb GIT binary patch literal 688 zcmV;h0#E&kP)vTJkN^MxkN^Mxkifve1&Q1r00008bW%=J0RR90|NsC0)yh;d0006%Nklb)L9y(^B)#yTuZ-F8Vj(?>Q*`lJ-Pg^R%Pr(xT#53#-TvAf>AMkW7g zq07kyn^}u)(u_&Fq{gmln%pPHWiEpopaO1425iRDA?=c^U9z>M%So(@!#a)Fh7KQM z%axFVu>)G>&0wbP_AKPf`%jWay2;kmBuLi!#&xkt(wSUr^(PyM(B_HE4G;FIBx^Tbcarp^?y`LW?JnCl(EjMRUXs46#U@F9P0qG$+cu{Fp3@J& zq?(xR=VxBHiP>Ig)56Wnw)zy{H(G1}el0ctzZM&SUyBXEuf+!7*J1`>vBc;UVnFw{oQP=!`Nm3jm8nq zLR&U~Pf9*oxCoqpD%;rQDI35+nJv9dUjItK93U;UaqqC%M8}Jr*uCys(u*wLQWD

!f9COP3$EE_MaT40qVt%(rLs82S@is>ERT z@kGSKaD<2j>q?!vBv;zaRx&}Lx4v;N*!qM8pwn;I%$dDp8x^mc?jtzZ+IBR90M+^` z^zrfy<^4A7(|Tt1*Ff8+M>fFP3}1^AwkbYjW41ZIv47%Q4=|Y)8-QPvvxN}Cocaes W_8~7%yCIwa0000 + + + + + + +TinyXML-2: Member List + + + + + + + + + +

+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLDocument Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLDocument, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) consttinyxml2::XMLDocumentvirtual
Clear()tinyxml2::XMLDocument
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeepCopy(XMLDocument *target)tinyxml2::XMLDocument
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
DeleteNode(XMLNode *node)tinyxml2::XMLDocument
Error() consttinyxml2::XMLDocumentinline
ErrorID() consttinyxml2::XMLDocumentinline
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetErrorLineNum() consttinyxml2::XMLDocumentinline
GetErrorStr1() consttinyxml2::XMLDocument
GetErrorStr2() consttinyxml2::XMLDocument
GetLineNum() consttinyxml2::XMLNodeinline
GetUserData() consttinyxml2::XMLNodeinline
HasBOM() consttinyxml2::XMLDocumentinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
LoadFile(const char *filename)tinyxml2::XMLDocument
LoadFile(FILE *)tinyxml2::XMLDocument
NewComment(const char *comment)tinyxml2::XMLDocument
NewDeclaration(const char *text=0)tinyxml2::XMLDocument
NewElement(const char *name)tinyxml2::XMLDocument
NewText(const char *text)tinyxml2::XMLDocument
NewUnknown(const char *text)tinyxml2::XMLDocument
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
Parse(const char *xml, size_t nBytes=(size_t)(-1))tinyxml2::XMLDocument
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
Print(XMLPrinter *streamer=0) consttinyxml2::XMLDocument
PrintError() consttinyxml2::XMLDocument
RootElement()tinyxml2::XMLDocumentinline
SaveFile(const char *filename, bool compact=false)tinyxml2::XMLDocument
SaveFile(FILE *fp, bool compact=false)tinyxml2::XMLDocument
SetBOM(bool useBOM)tinyxml2::XMLDocumentinline
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *) consttinyxml2::XMLDocumentinlinevirtual
ShallowEqual(const XMLNode *) consttinyxml2::XMLDocumentinlinevirtual
ToComment()tinyxml2::XMLNodeinlinevirtual
ToDeclaration()tinyxml2::XMLNodeinlinevirtual
ToDocument()tinyxml2::XMLDocumentinlinevirtual
ToElement()tinyxml2::XMLNodeinlinevirtual
ToText()tinyxml2::XMLNodeinlinevirtual
ToUnknown()tinyxml2::XMLNodeinlinevirtual
Value() consttinyxml2::XMLNode
XMLDocument(bool processEntities=true, Whitespace whitespaceMode=PRESERVE_WHITESPACE)tinyxml2::XMLDocument
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_document.html b/docs/classtinyxml2_1_1_x_m_l_document.html new file mode 100644 index 0000000..0e1c409 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_document.html @@ -0,0 +1,730 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLDocument Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLDocument Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLDocument:
+
+
+ + +tinyxml2::XMLNode + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

XMLDocument (bool processEntities=true, Whitespace whitespaceMode=PRESERVE_WHITESPACE)
 constructor
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
XMLError Parse (const char *xml, size_t nBytes=(size_t)(-1))
 
XMLError LoadFile (const char *filename)
 
XMLError LoadFile (FILE *)
 
XMLError SaveFile (const char *filename, bool compact=false)
 
XMLError SaveFile (FILE *fp, bool compact=false)
 
bool HasBOM () const
 
void SetBOM (bool useBOM)
 
XMLElementRootElement ()
 
void Print (XMLPrinter *streamer=0) const
 
virtual bool Accept (XMLVisitor *visitor) const
 
XMLElementNewElement (const char *name)
 
XMLCommentNewComment (const char *comment)
 
XMLTextNewText (const char *text)
 
XMLDeclarationNewDeclaration (const char *text=0)
 
XMLUnknownNewUnknown (const char *text)
 
void DeleteNode (XMLNode *node)
 
+bool Error () const
 Return true if there was an error parsing the document.
 
+XMLError ErrorID () const
 Return the errorID.
 
+const char * GetErrorStr1 () const
 Return a possibly helpful diagnostic location or string.
 
+const char * GetErrorStr2 () const
 Return a possibly helpful secondary diagnostic location or string.
 
+int GetErrorLineNum () const
 Return the line where the error occured, or zero if unknown.
 
+void PrintError () const
 If there is an error, print it to stdout.
 
+void Clear ()
 Clear the document, resetting it to the initial state.
 
void DeepCopy (XMLDocument *target)
 
virtual XMLNodeShallowClone (XMLDocument *) const
 
virtual bool ShallowEqual (const XMLNode *) const
 
- Public Member Functions inherited from tinyxml2::XMLNode
+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
XMLNodeDeepClone (XMLDocument *target) const
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

A Document binds together all the functionality. It can be saved, loaded, and printed to the screen. All Nodes are connected and allocated to a Document. If the Document is deleted, all its Nodes are also deleted.

+

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLDocument::Accept (XMLVisitorvisitor) const
+
+virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ DeepCopy()

+ +
+
+ + + + + + + + +
void tinyxml2::XMLDocument::DeepCopy (XMLDocumenttarget)
+
+

Copies this document to a target document. The target will be completely cleared before the copy. If you want to copy a sub-tree, see XMLNode::DeepClone().

+

NOTE: that the 'target' must be non-null.

+ +
+
+ +

◆ DeleteNode()

+ +
+
+ + + + + + + + +
void tinyxml2::XMLDocument::DeleteNode (XMLNodenode)
+
+

Delete a node associated with this document. It will be unlinked from the DOM.

+ +
+
+ +

◆ HasBOM()

+ +
+
+ + + + + +
+ + + + + + + +
bool tinyxml2::XMLDocument::HasBOM () const
+
+inline
+
+

Returns true if this document has a leading Byte Order Mark of UTF8.

+ +
+
+ +

◆ LoadFile() [1/2]

+ +
+
+ + + + + + + + +
XMLError tinyxml2::XMLDocument::LoadFile (const char * filename)
+
+

Load an XML file from disk. Returns XML_SUCCESS (0) on success, or an errorID.

+ +
+
+ +

◆ LoadFile() [2/2]

+ +
+
+ + + + + + + + +
XMLError tinyxml2::XMLDocument::LoadFile (FILE * )
+
+

Load an XML file from disk. You are responsible for providing and closing the FILE*.

+

NOTE: The file should be opened as binary ("rb") not text in order for TinyXML-2 to correctly do newline normalization.

+

Returns XML_SUCCESS (0) on success, or an errorID.

+ +
+
+ +

◆ NewComment()

+ +
+
+ + + + + + + + +
XMLComment* tinyxml2::XMLDocument::NewComment (const char * comment)
+
+

Create a new Comment associated with this Document. The memory for the Comment is managed by the Document.

+ +
+
+ +

◆ NewDeclaration()

+ +
+
+ + + + + + + + +
XMLDeclaration* tinyxml2::XMLDocument::NewDeclaration (const char * text = 0)
+
+

Create a new Declaration associated with this Document. The memory for the object is managed by the Document.

+

If the 'text' param is null, the standard declaration is used.:

    <?xml version="1.0" encoding="UTF-8"?>
+
+
+
+ +

◆ NewElement()

+ +
+
+ + + + + + + + +
XMLElement* tinyxml2::XMLDocument::NewElement (const char * name)
+
+

Create a new Element associated with this Document. The memory for the Element is managed by the Document.

+ +
+
+ +

◆ NewText()

+ +
+
+ + + + + + + + +
XMLText* tinyxml2::XMLDocument::NewText (const char * text)
+
+

Create a new Text associated with this Document. The memory for the Text is managed by the Document.

+ +
+
+ +

◆ NewUnknown()

+ +
+
+ + + + + + + + +
XMLUnknown* tinyxml2::XMLDocument::NewUnknown (const char * text)
+
+

Create a new Unknown associated with this Document. The memory for the object is managed by the Document.

+ +
+
+ +

◆ Parse()

+ +
+
+ + + + + + + + + + + + + + + + + + +
XMLError tinyxml2::XMLDocument::Parse (const char * xml,
size_t nBytes = (size_t)(-1) 
)
+
+

Parse an XML file from a character string. Returns XML_SUCCESS (0) on success, or an errorID.

+

You may optionally pass in the 'nBytes', which is the number of bytes which will be parsed. If not specified, TinyXML-2 will assume 'xml' points to a null terminated string.

+ +
+
+ +

◆ Print()

+ +
+
+ + + + + + + + +
void tinyxml2::XMLDocument::Print (XMLPrinterstreamer = 0) const
+
+

Print the Document. If the Printer is not provided, it will print to stdout. If you provide Printer, this can print to a file:

XMLPrinter printer( fp );
+doc.Print( &printer );
+

Or you can use a printer to print to memory:

XMLPrinter printer;
+doc.Print( &printer );
+// printer.CStr() has a const char* to the XML
+
+
+
+ +

◆ RootElement()

+ +
+
+ + + + + +
+ + + + + + + +
XMLElement* tinyxml2::XMLDocument::RootElement ()
+
+inline
+
+

Return the root element of DOM. Equivalent to FirstChildElement(). To get the first node, use FirstChild().

+ +
+
+ +

◆ SaveFile() [1/2]

+ +
+
+ + + + + + + + + + + + + + + + + + +
XMLError tinyxml2::XMLDocument::SaveFile (const char * filename,
bool compact = false 
)
+
+

Save the XML file to disk. Returns XML_SUCCESS (0) on success, or an errorID.

+ +
+
+ +

◆ SaveFile() [2/2]

+ +
+
+ + + + + + + + + + + + + + + + + + +
XMLError tinyxml2::XMLDocument::SaveFile (FILE * fp,
bool compact = false 
)
+
+

Save the XML file to disk. You are responsible for providing and closing the FILE*.

+

Returns XML_SUCCESS (0) on success, or an errorID.

+ +
+
+ +

◆ SetBOM()

+ +
+
+ + + + + +
+ + + + + + + + +
void tinyxml2::XMLDocument::SetBOM (bool useBOM)
+
+inline
+
+

Sets whether to write the BOM when writing the file.

+ +
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLDocument::ShallowClone (XMLDocumentdocument) const
+
+inlinevirtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLDocument::ShallowEqual (const XMLNodecompare) const
+
+inlinevirtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_document.png b/docs/classtinyxml2_1_1_x_m_l_document.png new file mode 100644 index 0000000000000000000000000000000000000000..4fcf9f466dbe8299ecf452e000e909c62318e62f GIT binary patch literal 657 zcmeAS@N?(olHy`uVBq!ia0vp^lYlsYgBeI3ZM_4cBm#UwT>t<74`jZ0^R=}9&;%e0 zj1L?*z}k679?0b=3GxeO04f53tEWPY7#NroJY5_^Dj46+ecSh1frqtSc;);5C$@9O zw_P#~U9DSwv}?F>}esYbgapp0WN~6M) zS)0P28LfY)v4<_8Aw|cQrBZ0+S%1FBSQ)kC788>nazT9CMSQ9iPR*EkT;;l&P5JZr zDy6d=vY6ymZvPUh;q;uuHp^|*_apAF=1h~=UpoEPA){u6t76LeKW8=1V86HC!gHJN zo@FX8oo6}zid`hRBwp=Tz1{9fUrcjVJU?wwyHqH1Jc#K>PaZ>drtOm3xt7bmPI%|C z+EBM+i#FeZ>uyXRwoGKO$yH(Sm*zZh88^3HO0z}anh;}xDpYN-=q?bo;)` z%un}T35oeSsob>nMyO1}ZSngr{U_}EIaN}*_UrELpVGw>ctJkNR%#VE6!eQdTuk2O UU-YshVESS3boFyt=akR{09U0V`2YX_ literal 0 HcmV?d00001 diff --git a/docs/classtinyxml2_1_1_x_m_l_element-members.html b/docs/classtinyxml2_1_1_x_m_l_element-members.html new file mode 100644 index 0000000..276d6f9 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_element-members.html @@ -0,0 +1,158 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLElement Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLElement, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) consttinyxml2::XMLElementvirtual
Attribute(const char *name, const char *value=0) consttinyxml2::XMLElement
BoolAttribute(const char *name, bool defaultValue=false) consttinyxml2::XMLElement
BoolText(bool defaultValue=false) consttinyxml2::XMLElement
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeleteAttribute(const char *name)tinyxml2::XMLElement
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
DoubleAttribute(const char *name, double defaultValue=0) consttinyxml2::XMLElement
DoubleText(double defaultValue=0) consttinyxml2::XMLElement
FindAttribute(const char *name) consttinyxml2::XMLElement
FirstAttribute() consttinyxml2::XMLElementinline
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
FloatAttribute(const char *name, float defaultValue=0) consttinyxml2::XMLElement
FloatText(float defaultValue=0) consttinyxml2::XMLElement
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetLineNum() consttinyxml2::XMLNodeinline
GetText() consttinyxml2::XMLElement
GetUserData() consttinyxml2::XMLNodeinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
Int64Attribute(const char *name, int64_t defaultValue=0) consttinyxml2::XMLElement
Int64Text(int64_t defaultValue=0) consttinyxml2::XMLElement
IntAttribute(const char *name, int defaultValue=0) consttinyxml2::XMLElement
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
Name() consttinyxml2::XMLElementinline
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
QueryAttribute(const char *name, int *value) consttinyxml2::XMLElementinline
QueryBoolAttribute(const char *name, bool *value) consttinyxml2::XMLElementinline
QueryBoolText(bool *bval) consttinyxml2::XMLElement
QueryDoubleAttribute(const char *name, double *value) consttinyxml2::XMLElementinline
QueryDoubleText(double *dval) consttinyxml2::XMLElement
QueryFloatAttribute(const char *name, float *value) consttinyxml2::XMLElementinline
QueryFloatText(float *fval) consttinyxml2::XMLElement
QueryInt64Attribute(const char *name, int64_t *value) consttinyxml2::XMLElementinline
QueryInt64Text(int64_t *uval) consttinyxml2::XMLElement
QueryIntAttribute(const char *name, int *value) consttinyxml2::XMLElementinline
QueryIntText(int *ival) consttinyxml2::XMLElement
QueryUnsignedAttribute(const char *name, unsigned int *value) consttinyxml2::XMLElementinline
QueryUnsignedText(unsigned *uval) consttinyxml2::XMLElement
SetAttribute(const char *name, const char *value)tinyxml2::XMLElementinline
SetAttribute(const char *name, int value)tinyxml2::XMLElementinline
SetAttribute(const char *name, unsigned value)tinyxml2::XMLElementinline
SetAttribute(const char *name, int64_t value)tinyxml2::XMLElementinline
SetAttribute(const char *name, bool value)tinyxml2::XMLElementinline
SetAttribute(const char *name, double value)tinyxml2::XMLElementinline
SetAttribute(const char *name, float value)tinyxml2::XMLElementinline
SetName(const char *str, bool staticMem=false)tinyxml2::XMLElementinline
SetText(const char *inText)tinyxml2::XMLElement
SetText(int value)tinyxml2::XMLElement
SetText(unsigned value)tinyxml2::XMLElement
SetText(int64_t value)tinyxml2::XMLElement
SetText(bool value)tinyxml2::XMLElement
SetText(double value)tinyxml2::XMLElement
SetText(float value)tinyxml2::XMLElement
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *document) consttinyxml2::XMLElementvirtual
ShallowEqual(const XMLNode *compare) consttinyxml2::XMLElementvirtual
ToComment()tinyxml2::XMLNodeinlinevirtual
ToDeclaration()tinyxml2::XMLNodeinlinevirtual
ToDocument()tinyxml2::XMLNodeinlinevirtual
ToElement()tinyxml2::XMLElementinlinevirtual
ToText()tinyxml2::XMLNodeinlinevirtual
ToUnknown()tinyxml2::XMLNodeinlinevirtual
UnsignedAttribute(const char *name, unsigned defaultValue=0) consttinyxml2::XMLElement
UnsignedText(unsigned defaultValue=0) consttinyxml2::XMLElement
Value() consttinyxml2::XMLNode
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_element.html b/docs/classtinyxml2_1_1_x_m_l_element.html new file mode 100644 index 0000000..b6e8d70 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_element.html @@ -0,0 +1,708 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLElement Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLElement Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLElement:
+
+
+ + +tinyxml2::XMLNode + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+const char * Name () const
 Get the name of an element (which is the Value() of the node.)
 
+void SetName (const char *str, bool staticMem=false)
 Set the name of the element.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
virtual bool Accept (XMLVisitor *visitor) const
 
const char * Attribute (const char *name, const char *value=0) const
 
int IntAttribute (const char *name, int defaultValue=0) const
 
+unsigned UnsignedAttribute (const char *name, unsigned defaultValue=0) const
 See IntAttribute()
 
+int64_t Int64Attribute (const char *name, int64_t defaultValue=0) const
 See IntAttribute()
 
+bool BoolAttribute (const char *name, bool defaultValue=false) const
 See IntAttribute()
 
+double DoubleAttribute (const char *name, double defaultValue=0) const
 See IntAttribute()
 
+float FloatAttribute (const char *name, float defaultValue=0) const
 See IntAttribute()
 
XMLError QueryIntAttribute (const char *name, int *value) const
 
+XMLError QueryUnsignedAttribute (const char *name, unsigned int *value) const
 See QueryIntAttribute()
 
+XMLError QueryInt64Attribute (const char *name, int64_t *value) const
 See QueryIntAttribute()
 
+XMLError QueryBoolAttribute (const char *name, bool *value) const
 See QueryIntAttribute()
 
+XMLError QueryDoubleAttribute (const char *name, double *value) const
 See QueryIntAttribute()
 
+XMLError QueryFloatAttribute (const char *name, float *value) const
 See QueryIntAttribute()
 
int QueryAttribute (const char *name, int *value) const
 
+void SetAttribute (const char *name, const char *value)
 Sets the named attribute to value.
 
+void SetAttribute (const char *name, int value)
 Sets the named attribute to value.
 
+void SetAttribute (const char *name, unsigned value)
 Sets the named attribute to value.
 
+void SetAttribute (const char *name, int64_t value)
 Sets the named attribute to value.
 
+void SetAttribute (const char *name, bool value)
 Sets the named attribute to value.
 
+void SetAttribute (const char *name, double value)
 Sets the named attribute to value.
 
+void SetAttribute (const char *name, float value)
 Sets the named attribute to value.
 
void DeleteAttribute (const char *name)
 
+const XMLAttributeFirstAttribute () const
 Return the first attribute in the list.
 
+const XMLAttributeFindAttribute (const char *name) const
 Query a specific attribute in the list.
 
const char * GetText () const
 
void SetText (const char *inText)
 
+void SetText (int value)
 Convenience method for setting text inside an element. See SetText() for important limitations.
 
+void SetText (unsigned value)
 Convenience method for setting text inside an element. See SetText() for important limitations.
 
+void SetText (int64_t value)
 Convenience method for setting text inside an element. See SetText() for important limitations.
 
+void SetText (bool value)
 Convenience method for setting text inside an element. See SetText() for important limitations.
 
+void SetText (double value)
 Convenience method for setting text inside an element. See SetText() for important limitations.
 
+void SetText (float value)
 Convenience method for setting text inside an element. See SetText() for important limitations.
 
XMLError QueryIntText (int *ival) const
 
+XMLError QueryUnsignedText (unsigned *uval) const
 See QueryIntText()
 
+XMLError QueryInt64Text (int64_t *uval) const
 See QueryIntText()
 
+XMLError QueryBoolText (bool *bval) const
 See QueryIntText()
 
+XMLError QueryDoubleText (double *dval) const
 See QueryIntText()
 
+XMLError QueryFloatText (float *fval) const
 See QueryIntText()
 
+unsigned UnsignedText (unsigned defaultValue=0) const
 See QueryIntText()
 
+int64_t Int64Text (int64_t defaultValue=0) const
 See QueryIntText()
 
+bool BoolText (bool defaultValue=false) const
 See QueryIntText()
 
+double DoubleText (double defaultValue=0) const
 See QueryIntText()
 
+float FloatText (float defaultValue=0) const
 See QueryIntText()
 
virtual XMLNodeShallowClone (XMLDocument *document) const
 
virtual bool ShallowEqual (const XMLNode *compare) const
 
- Public Member Functions inherited from tinyxml2::XMLNode
+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
XMLNodeDeepClone (XMLDocument *target) const
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes.

+

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLElement::Accept (XMLVisitorvisitor) const
+
+virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ Attribute()

+ +
+
+ + + + + + + + + + + + + + + + + + +
const char* tinyxml2::XMLElement::Attribute (const char * name,
const char * value = 0 
) const
+
+

Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. For example:

+
const char* value = ele->Attribute( "foo" );
+

The 'value' parameter is normally null. However, if specified, the attribute will only be returned if the 'name' and 'value' match. This allow you to write code:

+
if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
+

rather than:

if ( ele->Attribute( "foo" ) ) {
+    if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
+}
+
+
+
+ +

◆ DeleteAttribute()

+ +
+
+ + + + + + + + +
void tinyxml2::XMLElement::DeleteAttribute (const char * name)
+
+

Delete an attribute.

+ +
+
+ +

◆ GetText()

+ +
+
+ + + + + + + +
const char* tinyxml2::XMLElement::GetText () const
+
+

Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the XMLText child and accessing it directly.

+

If the first child of 'this' is a XMLText, the GetText() returns the character string of the Text node, else null is returned.

+

This is a convenient method for getting the text of simple contained text:

<foo>This is text</foo>
+    const char* str = fooElement->GetText();
+

'str' will be a pointer to "This is text".

+

Note that this function can be misleading. If the element foo was created from this XML:

    <foo><b>This is text</b></foo>
+

then the value of str would be null. The first child node isn't a text node, it is another element. From this XML:

    <foo>This is <b>text</b></foo>
+

GetText() will return "This is ".

+ +
+
+ +

◆ IntAttribute()

+ +
+
+ + + + + + + + + + + + + + + + + + +
int tinyxml2::XMLElement::IntAttribute (const char * name,
int defaultValue = 0 
) const
+
+

Given an attribute name, IntAttribute() returns the value of the attribute interpreted as an integer. The default value will be returned if the attribute isn't present, or if there is an error. (For a method with error checking, see QueryIntAttribute()).

+ +
+
+ +

◆ QueryAttribute()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
int tinyxml2::XMLElement::QueryAttribute (const char * name,
int * value 
) const
+
+inline
+
+

Given an attribute name, QueryAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion can't be performed, or XML_NO_ATTRIBUTE if the attribute doesn't exist. It is overloaded for the primitive types, and is a generally more convenient replacement of QueryIntAttribute() and related functions.

+

If successful, the result of the conversion will be written to 'value'. If not successful, nothing will be written to 'value'. This allows you to provide default value:

+
int value = 10;
+QueryAttribute( "foo", &value );        // if "foo" isn't found, value will still be 10
+
+
+
+ +

◆ QueryIntAttribute()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
XMLError tinyxml2::XMLElement::QueryIntAttribute (const char * name,
int * value 
) const
+
+inline
+
+

Given an attribute name, QueryIntAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion can't be performed, or XML_NO_ATTRIBUTE if the attribute doesn't exist. If successful, the result of the conversion will be written to 'value'. If not successful, nothing will be written to 'value'. This allows you to provide default value:

+
int value = 10;
+QueryIntAttribute( "foo", &value );     // if "foo" isn't found, value will still be 10
+
+
+
+ +

◆ QueryIntText()

+ +
+
+ + + + + + + + +
XMLError tinyxml2::XMLElement::QueryIntText (int * ival) const
+
+

Convenience method to query the value of a child text node. This is probably best shown by example. Given you have a document is this form:

    <point>
+        <x>1</x>
+        <y>1.4</y>
+    </point>
+

The QueryIntText() and similar functions provide a safe and easier way to get to the "value" of x and y.

+
    int x = 0;
+    float y = 0;    // types of x and y are contrived for example
+    const XMLElement* xElement = pointElement->FirstChildElement( "x" );
+    const XMLElement* yElement = pointElement->FirstChildElement( "y" );
+    xElement->QueryIntText( &x );
+    yElement->QueryFloatText( &y );
+
Returns
XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
+ +
+
+ +

◆ SetText()

+ +
+
+ + + + + + + + +
void tinyxml2::XMLElement::SetText (const char * inText)
+
+

Convenience function for easy access to the text inside an element. Although easy and concise, SetText() is limited compared to creating an XMLText child and mutating it directly.

+

If the first child of 'this' is a XMLText, SetText() sets its value to the given string, otherwise it will create a first child that is an XMLText.

+

This is a convenient method for setting the text of simple contained text:

<foo>This is text</foo>
+    fooElement->SetText( "Hullaballoo!" );
+<foo>Hullaballoo!</foo>
+

Note that this function can be misleading. If the element foo was created from this XML:

    <foo><b>This is text</b></foo>
+

then it will not change "This is text", but rather prefix it with a text element:

    <foo>Hullaballoo!<b>This is text</b></foo>
+

For this XML:

    <foo />
+

SetText() will generate

    <foo>Hullaballoo!</foo>
+
+
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLElement::ShallowClone (XMLDocumentdocument) const
+
+virtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLElement::ShallowEqual (const XMLNodecompare) const
+
+virtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_element.png b/docs/classtinyxml2_1_1_x_m_l_element.png new file mode 100644 index 0000000000000000000000000000000000000000..b76dc5b5465b9f7c5586846f92b117a0035c0983 GIT binary patch literal 618 zcmV-w0+s!VP)%jey0000OP)t-s|Ns90 z008Lh^>vTJkN^MxkN^Mxkifve1&Q1r00008bW%=J0RR90|NsC0)yh;d0005`NklyGOn41~vn)c1en)0CU-dP8znN}`o3Pk{jThk@iTN-5=jp^)U=N{qxH$w(eU zK1Py1YU>x7qiRh}oYm3grjw*mfI*UbYEdjlWvfkv@hQ(^Y^(fu`8cR*u3Cp%=>kLb zRX6R4O6Ja{G*8XPc-9$J?7^sl1{liIS2A}nZ0>t%W@nh_2qScO9;2s{6lGr&9j!B{ zjnkXii|t2p+AfAks*u|J)j5Shl12wG=Dx2nT%eK5(`Un82vresTFt6vGVp4^|J@Xl z+77%%Nb=X($GD1OALBBL{KAr)mKe{(D5aF!1pvR*3jprdGcaDSM{qm?<4y4dj)!36 zO#z@RF%km+A|*y*06?U~NDKgolo*Kt0Fe?SF#sS^V*F7I5s~`^0f4)e7>NM@kp{-Q zSOIPQ+o9HNGjUei@n5fTM4uP{u&3tMa#Xe!Te&^x)nT-&`~DlgYtL5L_-8R{0*9B` z-X8R+c2kh0Ff zc0Z{*Z_$h2tv_H~{f3V*F8|Kt7d9~fAkuR%L_}`aKX!Q>!ZILyHvj+t07*qoM6N<$ Ef;>?j^Z)<= literal 0 HcmV?d00001 diff --git a/docs/classtinyxml2_1_1_x_m_l_handle-members.html b/docs/classtinyxml2_1_1_x_m_l_handle-members.html new file mode 100644 index 0000000..24b4a12 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_handle-members.html @@ -0,0 +1,98 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLHandle Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLHandle, including all inherited members.

+ + + + + + + + + + + + + + + + + + +
FirstChild()tinyxml2::XMLHandleinline
FirstChildElement(const char *name=0)tinyxml2::XMLHandleinline
LastChild()tinyxml2::XMLHandleinline
LastChildElement(const char *name=0)tinyxml2::XMLHandleinline
NextSibling()tinyxml2::XMLHandleinline
NextSiblingElement(const char *name=0)tinyxml2::XMLHandleinline
operator=(const XMLHandle &ref)tinyxml2::XMLHandleinline
PreviousSibling()tinyxml2::XMLHandleinline
PreviousSiblingElement(const char *name=0)tinyxml2::XMLHandleinline
ToDeclaration()tinyxml2::XMLHandleinline
ToElement()tinyxml2::XMLHandleinline
ToNode()tinyxml2::XMLHandleinline
ToText()tinyxml2::XMLHandleinline
ToUnknown()tinyxml2::XMLHandleinline
XMLHandle(XMLNode *node)tinyxml2::XMLHandleinline
XMLHandle(XMLNode &node)tinyxml2::XMLHandleinline
XMLHandle(const XMLHandle &ref)tinyxml2::XMLHandleinline
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_handle.html b/docs/classtinyxml2_1_1_x_m_l_handle.html new file mode 100644 index 0000000..7662050 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_handle.html @@ -0,0 +1,189 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLHandle Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLHandle Class Reference
+
+
+ +

#include <tinyxml2.h>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

XMLHandle (XMLNode *node)
 Create a handle from any node (at any depth of the tree.) This can be a null pointer.
 
XMLHandle (XMLNode &node)
 Create a handle from a node.
 
XMLHandle (const XMLHandle &ref)
 Copy constructor.
 
+XMLHandleoperator= (const XMLHandle &ref)
 Assignment.
 
+XMLHandle FirstChild ()
 Get the first child of this handle.
 
+XMLHandle FirstChildElement (const char *name=0)
 Get the first child element of this handle.
 
+XMLHandle LastChild ()
 Get the last child of this handle.
 
+XMLHandle LastChildElement (const char *name=0)
 Get the last child element of this handle.
 
+XMLHandle PreviousSibling ()
 Get the previous sibling of this handle.
 
+XMLHandle PreviousSiblingElement (const char *name=0)
 Get the previous sibling element of this handle.
 
+XMLHandle NextSibling ()
 Get the next sibling of this handle.
 
+XMLHandle NextSiblingElement (const char *name=0)
 Get the next sibling element of this handle.
 
+XMLNodeToNode ()
 Safe cast to XMLNode. This can return null.
 
+XMLElementToElement ()
 Safe cast to XMLElement. This can return null.
 
+XMLTextToText ()
 Safe cast to XMLText. This can return null.
 
+XMLUnknownToUnknown ()
 Safe cast to XMLUnknown. This can return null.
 
+XMLDeclarationToDeclaration ()
 Safe cast to XMLDeclaration. This can return null.
 
+

Detailed Description

+

A XMLHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 DOM structure. It is a separate utility class.

+

Take an example:

<Document>
+    <Element attributeA = "valueA">
+        <Child attributeB = "value1" />
+        <Child attributeB = "value2" />
+    </Element>
+</Document>
+

Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a lot of code that looks like:

+
XMLElement* root = document.FirstChildElement( "Document" );
+if ( root )
+{
+    XMLElement* element = root->FirstChildElement( "Element" );
+    if ( element )
+    {
+        XMLElement* child = element->FirstChildElement( "Child" );
+        if ( child )
+        {
+            XMLElement* child2 = child->NextSiblingElement( "Child" );
+            if ( child2 )
+            {
+                // Finally do something useful.
+

And that doesn't even cover "else" cases. XMLHandle addresses the verbosity of such code. A XMLHandle checks for null pointers so it is perfectly safe and correct to use:

+
XMLHandle docHandle( &document );
+XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
+if ( child2 )
+{
+    // do something useful
+

Which is MUCH more concise and useful.

+

It is also safe to copy handles - internally they are nothing more than node pointers.

XMLHandle handleCopy = handle;
+

See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.

+

The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_node-members.html b/docs/classtinyxml2_1_1_x_m_l_node-members.html new file mode 100644 index 0000000..46d4609 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_node-members.html @@ -0,0 +1,113 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLNode Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLNode, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) const =0tinyxml2::XMLNodepure virtual
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetLineNum() consttinyxml2::XMLNodeinline
GetUserData() consttinyxml2::XMLNodeinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *document) const =0tinyxml2::XMLNodepure virtual
ShallowEqual(const XMLNode *compare) const =0tinyxml2::XMLNodepure virtual
ToComment()tinyxml2::XMLNodeinlinevirtual
ToDeclaration()tinyxml2::XMLNodeinlinevirtual
ToDocument()tinyxml2::XMLNodeinlinevirtual
ToElement()tinyxml2::XMLNodeinlinevirtual
ToText()tinyxml2::XMLNodeinlinevirtual
ToUnknown()tinyxml2::XMLNodeinlinevirtual
Value() consttinyxml2::XMLNode
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_node.html b/docs/classtinyxml2_1_1_x_m_l_node.html new file mode 100644 index 0000000..aa1dc30 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_node.html @@ -0,0 +1,581 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLNode Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLNode Class Referenceabstract
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLNode:
+
+
+ + +tinyxml2::XMLComment +tinyxml2::XMLDeclaration +tinyxml2::XMLDocument +tinyxml2::XMLElement +tinyxml2::XMLText +tinyxml2::XMLUnknown + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
virtual XMLNodeShallowClone (XMLDocument *document) const =0
 
XMLNodeDeepClone (XMLDocument *target) const
 
virtual bool ShallowEqual (const XMLNode *compare) const =0
 
virtual bool Accept (XMLVisitor *visitor) const =0
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

XMLNode is a base class for every object that is in the XML Document Object Model (DOM), except XMLAttributes. Nodes have siblings, a parent, and children which can be navigated. A node is always in a XMLDocument. The type of a XMLNode can be queried, and it can be cast to its more defined type.

+

A XMLDocument allocates memory for all its Nodes. When the XMLDocument gets deleted, all its Nodes will also be deleted.

+
A Document can contain: Element (container or leaf)
+                        Comment (leaf)
+                        Unknown (leaf)
+                        Declaration( leaf )
+
+An Element can contain: Element (container or leaf)
+                        Text    (leaf)
+                        Attributes (not on tree)
+                        Comment (leaf)
+                        Unknown (leaf)

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLNode::Accept (XMLVisitorvisitor) const
+
+pure virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implemented in tinyxml2::XMLDocument, tinyxml2::XMLElement, tinyxml2::XMLUnknown, tinyxml2::XMLDeclaration, tinyxml2::XMLComment, and tinyxml2::XMLText.

+ +
+
+ +

◆ DeepClone()

+ +
+
+ + + + + + + + +
XMLNode* tinyxml2::XMLNode::DeepClone (XMLDocumenttarget) const
+
+

Make a copy of this node and all its children.

+

If the 'target' is null, then the nodes will be allocated in the current document. If 'target' is specified, the memory will be allocated is the specified XMLDocument.

+

NOTE: This is probably not the correct tool to copy a document, since XMLDocuments can have multiple top level XMLNodes. You probably want to use XMLDocument::DeepCopy()

+ +
+
+ +

◆ DeleteChild()

+ +
+
+ + + + + + + + +
void tinyxml2::XMLNode::DeleteChild (XMLNodenode)
+
+

Delete a child of this node.

+ +
+
+ +

◆ DeleteChildren()

+ +
+
+ + + + + + + +
void tinyxml2::XMLNode::DeleteChildren ()
+
+

Delete all the children of this node.

+ +
+
+ +

◆ FirstChildElement()

+ +
+
+ + + + + + + + +
const XMLElement* tinyxml2::XMLNode::FirstChildElement (const char * name = 0) const
+
+

Get the first child element, or optionally the first child element with the specified name.

+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + +
void* tinyxml2::XMLNode::GetUserData () const
+
+inline
+
+

Get user data set into the XMLNode. TinyXML-2 in no way processes or interprets user data. It is initially 0.

+ +
+
+ +

◆ InsertAfterChild()

+ +
+
+ + + + + + + + + + + + + + + + + + +
XMLNode* tinyxml2::XMLNode::InsertAfterChild (XMLNodeafterThis,
XMLNodeaddThis 
)
+
+

Add a node after the specified child node. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the afterThis node is not a child of this node, or if the node does not belong to the same document.

+ +
+
+ +

◆ InsertEndChild()

+ +
+
+ + + + + + + + +
XMLNode* tinyxml2::XMLNode::InsertEndChild (XMLNodeaddThis)
+
+

Add a child node as the last (right) child. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the node does not belong to the same document.

+ +
+
+ +

◆ InsertFirstChild()

+ +
+
+ + + + + + + + +
XMLNode* tinyxml2::XMLNode::InsertFirstChild (XMLNodeaddThis)
+
+

Add a child node as the first (left) child. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the node does not belong to the same document.

+ +
+
+ +

◆ LastChildElement()

+ +
+
+ + + + + + + + +
const XMLElement* tinyxml2::XMLNode::LastChildElement (const char * name = 0) const
+
+

Get the last child element or optionally the last child element with the specified name.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
void tinyxml2::XMLNode::SetUserData (void * userData)
+
+inline
+
+

Set user data into the XMLNode. TinyXML-2 in no way processes or interprets user data. It is initially 0.

+ +
+
+ +

◆ SetValue()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void tinyxml2::XMLNode::SetValue (const char * val,
bool staticMem = false 
)
+
+

Set the Value of an XML node.

See also
Value()
+ +
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLNode::ShallowClone (XMLDocumentdocument) const
+
+pure virtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implemented in tinyxml2::XMLDocument, tinyxml2::XMLElement, tinyxml2::XMLUnknown, tinyxml2::XMLDeclaration, tinyxml2::XMLComment, and tinyxml2::XMLText.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLNode::ShallowEqual (const XMLNodecompare) const
+
+pure virtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implemented in tinyxml2::XMLDocument, tinyxml2::XMLElement, tinyxml2::XMLUnknown, tinyxml2::XMLDeclaration, tinyxml2::XMLComment, and tinyxml2::XMLText.

+ +
+
+ +

◆ Value()

+ +
+
+ + + + + + + +
const char* tinyxml2::XMLNode::Value () const
+
+

The meaning of 'value' changes for the specific type.

Document:   empty (NULL is returned, not an empty string)
+Element:    name of the element
+Comment:    the comment text
+Unknown:    the tag contents
+Text:       the text string
+
+
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_node.png b/docs/classtinyxml2_1_1_x_m_l_node.png new file mode 100644 index 0000000000000000000000000000000000000000..cb1e7ce191b61a5d9696a6ad4e8d0851896e182b GIT binary patch literal 1845 zcmb_dc~BE)6b~R^X=ADt)SzVOghQfGsmdj{N0!?VP)3fHN~1sv0YXigERx8TmcCc{a*H>-?o#j7Y^U;&C06I&#^jV%lw#RoLd`IG zV^?1SJDS@{b&|^$!kJ)vHUn*7SyrrH;X-_Ui7K#G7B^Nqx;h!x^{L@E!xlsNwD8kA zFnU#s%BF*<s~2<2lKq1GjGtk(cDdtdNpFB1GG>r)O;0Em*3z)ma8az#Kq%$*}!ymwgx}#18DFJHWz1EP!7!4T`Z4 z59V1NLt6l1!mQ9Yqc9*YPzIbj94dP)Fnj7NEJd{~^l4s9WzD;2L>IUsUfnD6dvSbj z>?yv$4dd}!z%%iu?=i!m?3aUb|b*2gg5?XzsZgQsGnQsoG@GNZ15p+Z4tNkz}cdB;` z86P3ThK!EmguXIv<{N=rL0;UgXMg0!)505OE~NoHm+LkxlT`8P(&8N-sPdC|^YcYf z{8_R5z`(*VeR#}jEwZ=jVd(5z04FS}S@srNQ^tSdF`O$y$rHgHB%jgSqRGyDrF|E5 z7+0W9c{V=&Y*KPSwXe5+DYvlSsk8XZ!U09B!!XNB>@2=r&1riPYm*hy9##vAw$+oZ z6-1fEU6tpoNiDc%zWdrpWFGSkI;McXbg+B5Wcu-Bdl4%Ss7m&f{rq5`fA)DJBT+Qd zahLT#f2F&uZqoWVJM6}pg@lO|f~)HUy=yS%VJw}03RH-2PAO>|Od&r|QV9mKd>JuA zO#b*a8`L9t1L@%|<4PBB8E2d_`~BYbk$W+8b-jN2hm_o;&iAWd7Tx$t=$&Cj;g-n> z(p#M;DrR^i+4f6?v`lbtuDkC?F1V*^)`8$3l#cHn=qD%A6el@7>?UvVUU9=VXRO0# znP6IG-6@$ov40<>$uMH*p$K#>pe0J8R)1O?#Pa&gDeUvNY*YyrCJNTIuuih&2w2iYHn{($h9S^Iu^rzE0x3K(YKz~N) z+pQd@yQ+aPC(UIsC_ht_=~zfr-WK+f z-3{`o3QbPg3(KXkgdmybWY6eOgbbqD>{)%)d65^X{DQOm*fD&}rpu1Rc>UcV!J@dS z!4n6RJ`)F}pXZ-w9I44XtezXVgZd^lOwvcUF(N66K8!+goVK)evMMN@+M65^zEgRE zu$C-&Oy?Sr%m%aVMp^HqzFU1J_;;myNg6c@WaC%m)Ikqn=&i-T13)?xvqucfm8?q* z)?7XaJh%i)ZC!H=M*#X7KvG-R9CWnx{#m8185~I9QfB|A>!bEU3&VunPwwk)*fm5p Xzr(?>R=o-O$02}Yen;y(KKc3&bpL#% literal 0 HcmV?d00001 diff --git a/docs/classtinyxml2_1_1_x_m_l_printer-members.html b/docs/classtinyxml2_1_1_x_m_l_printer-members.html new file mode 100644 index 0000000..c22d03d --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_printer-members.html @@ -0,0 +1,106 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLPrinter Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLPrinter, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ClearBuffer()tinyxml2::XMLPrinterinline
CloseElement(bool compactMode=false)tinyxml2::XMLPrintervirtual
CStr() consttinyxml2::XMLPrinterinline
CStrSize() consttinyxml2::XMLPrinterinline
OpenElement(const char *name, bool compactMode=false)tinyxml2::XMLPrinter
PrintSpace(int depth)tinyxml2::XMLPrinterprotectedvirtual
PushAttribute(const char *name, const char *value)tinyxml2::XMLPrinter
PushComment(const char *comment)tinyxml2::XMLPrinter
PushHeader(bool writeBOM, bool writeDeclaration)tinyxml2::XMLPrinter
PushText(const char *text, bool cdata=false)tinyxml2::XMLPrinter
PushText(int value)tinyxml2::XMLPrinter
PushText(unsigned value)tinyxml2::XMLPrinter
PushText(int64_t value)tinyxml2::XMLPrinter
PushText(bool value)tinyxml2::XMLPrinter
PushText(float value)tinyxml2::XMLPrinter
PushText(double value)tinyxml2::XMLPrinter
Visit(const XMLText &text)tinyxml2::XMLPrintervirtual
Visit(const XMLComment &comment)tinyxml2::XMLPrintervirtual
Visit(const XMLDeclaration &declaration)tinyxml2::XMLPrintervirtual
Visit(const XMLUnknown &unknown)tinyxml2::XMLPrintervirtual
VisitEnter(const XMLDocument &)tinyxml2::XMLPrintervirtual
VisitEnter(const XMLElement &element, const XMLAttribute *attribute)tinyxml2::XMLPrintervirtual
VisitExit(const XMLDocument &)tinyxml2::XMLPrinterinlinevirtual
VisitExit(const XMLElement &element)tinyxml2::XMLPrintervirtual
XMLPrinter(FILE *file=0, bool compact=false, int depth=0)tinyxml2::XMLPrinter
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_printer.html b/docs/classtinyxml2_1_1_x_m_l_printer.html new file mode 100644 index 0000000..693cce3 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_printer.html @@ -0,0 +1,410 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLPrinter Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLPrinter Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLPrinter:
+
+
+ + +tinyxml2::XMLVisitor + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 XMLPrinter (FILE *file=0, bool compact=false, int depth=0)
 
void PushHeader (bool writeBOM, bool writeDeclaration)
 
void OpenElement (const char *name, bool compactMode=false)
 
+void PushAttribute (const char *name, const char *value)
 If streaming, add an attribute to an open element.
 
+virtual void CloseElement (bool compactMode=false)
 If streaming, close the Element.
 
+void PushText (const char *text, bool cdata=false)
 Add a text node.
 
+void PushText (int value)
 Add a text node from an integer.
 
+void PushText (unsigned value)
 Add a text node from an unsigned.
 
+void PushText (int64_t value)
 Add a text node from an unsigned.
 
+void PushText (bool value)
 Add a text node from a bool.
 
+void PushText (float value)
 Add a text node from a float.
 
+void PushText (double value)
 Add a text node from a double.
 
+void PushComment (const char *comment)
 Add a comment.
 
+virtual bool VisitEnter (const XMLDocument &)
 Visit a document.
 
+virtual bool VisitExit (const XMLDocument &)
 Visit a document.
 
+virtual bool VisitEnter (const XMLElement &element, const XMLAttribute *attribute)
 Visit an element.
 
+virtual bool VisitExit (const XMLElement &element)
 Visit an element.
 
+virtual bool Visit (const XMLText &text)
 Visit a text node.
 
+virtual bool Visit (const XMLComment &comment)
 Visit a comment node.
 
+virtual bool Visit (const XMLDeclaration &declaration)
 Visit a declaration.
 
+virtual bool Visit (const XMLUnknown &unknown)
 Visit an unknown node.
 
const char * CStr () const
 
int CStrSize () const
 
void ClearBuffer ()
 
+ + + +

+Protected Member Functions

virtual void PrintSpace (int depth)
 
+

Detailed Description

+

Printing functionality. The XMLPrinter gives you more options than the XMLDocument::Print() method.

+

It can:

    +
  1. Print to memory.
  2. +
  3. Print to a file you provide.
  4. +
  5. Print XML without a XMLDocument.
  6. +
+

Print to Memory

+
XMLPrinter printer;
+doc.Print( &printer );
+SomeFunction( printer.CStr() );
+

Print to a File

+

You provide the file pointer.

XMLPrinter printer( fp );
+doc.Print( &printer );
+

Print without a XMLDocument

+

When loading, an XML parser is very useful. However, sometimes when saving, it just gets in the way. The code is often set up for streaming, and constructing the DOM is just overhead.

+

The Printer supports the streaming case. The following code prints out a trivially simple XML file without ever creating an XML document.

+
XMLPrinter printer( fp );
+printer.OpenElement( "foo" );
+printer.PushAttribute( "foo", "bar" );
+printer.CloseElement();
+

Constructor & Destructor Documentation

+ +

◆ XMLPrinter()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
tinyxml2::XMLPrinter::XMLPrinter (FILE * file = 0,
bool compact = false,
int depth = 0 
)
+
+

Construct the printer. If the FILE* is specified, this will print to the FILE. Else it will print to memory, and the result is available in CStr(). If 'compact' is set to true, then output is created with only required whitespace and newlines.

+ +
+
+

Member Function Documentation

+ +

◆ ClearBuffer()

+ +
+
+ + + + + +
+ + + + + + + +
void tinyxml2::XMLPrinter::ClearBuffer ()
+
+inline
+
+

If in print to memory mode, reset the buffer to the beginning.

+ +
+
+ +

◆ CStr()

+ +
+
+ + + + + +
+ + + + + + + +
const char* tinyxml2::XMLPrinter::CStr () const
+
+inline
+
+

If in print to memory mode, return a pointer to the XML file in memory.

+ +
+
+ +

◆ CStrSize()

+ +
+
+ + + + + +
+ + + + + + + +
int tinyxml2::XMLPrinter::CStrSize () const
+
+inline
+
+

If in print to memory mode, return the size of the XML file in memory. (Note the size returned includes the terminating null.)

+ +
+
+ +

◆ OpenElement()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void tinyxml2::XMLPrinter::OpenElement (const char * name,
bool compactMode = false 
)
+
+

If streaming, start writing an element. The element must be closed with CloseElement()

+ +
+
+ +

◆ PrintSpace()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void tinyxml2::XMLPrinter::PrintSpace (int depth)
+
+protectedvirtual
+
+

Prints out the space before an element. You may override to change the space and tabs used. A PrintSpace() override should call Print().

+ +
+
+ +

◆ PushHeader()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void tinyxml2::XMLPrinter::PushHeader (bool writeBOM,
bool writeDeclaration 
)
+
+

If streaming, write the BOM and declaration.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_printer.png b/docs/classtinyxml2_1_1_x_m_l_printer.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc674855364f4b2b9731ddf08f0b2af7159034e GIT binary patch literal 586 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^g!3-py-Rr#uq$C1-LR|m<{|{uoc=NTi|Ih>= z3ycpOIKbL@M;^%KC<*clW&kPzfvcxNj2IXgZ+f~ohEy=VotxcvSb?YIt>de|{d-hx z{&2K}Om*5?)G8fy_{U+1Pt$|EGM5K3HPnhRFe)(Am@v$U`euB3#id~3rPW1ezwk0J z#6(`*z|y+vj|{^PRtAH$%ulAue&*kpbiC!yhKcVPI#%!8T=Z@F#?U`|SVI^4z5Q=$ zrMkBClyk2k1J8?P6WJNeF6+uZDyhuz;bvH`uT|V2^p@qpWAhbav7)ihw`y%?_%-Xm zhqLnCrVIyG)iNmj-p#h*r(Am+!;PeHS+*rl`o}Xpdb7U zXUo3fVRf*b z@P7TeTOq3scim@wahX5;e^BFFv5?+Xcm8LWXsrs< + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLText Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLText, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) consttinyxml2::XMLTextvirtual
CData() consttinyxml2::XMLTextinline
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetLineNum() consttinyxml2::XMLNodeinline
GetUserData() consttinyxml2::XMLNodeinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
SetCData(bool isCData)tinyxml2::XMLTextinline
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *document) consttinyxml2::XMLTextvirtual
ShallowEqual(const XMLNode *compare) consttinyxml2::XMLTextvirtual
ToComment()tinyxml2::XMLNodeinlinevirtual
ToDeclaration()tinyxml2::XMLNodeinlinevirtual
ToDocument()tinyxml2::XMLNodeinlinevirtual
ToElement()tinyxml2::XMLNodeinlinevirtual
ToText()tinyxml2::XMLTextinlinevirtual
ToUnknown()tinyxml2::XMLNodeinlinevirtual
Value() consttinyxml2::XMLNode
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_text.html b/docs/classtinyxml2_1_1_x_m_l_text.html new file mode 100644 index 0000000..7a47230 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_text.html @@ -0,0 +1,310 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLText Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLText Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLText:
+
+
+ + +tinyxml2::XMLNode + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

virtual bool Accept (XMLVisitor *visitor) const
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+void SetCData (bool isCData)
 Declare whether this should be CDATA or standard text.
 
+bool CData () const
 Returns true if this is a CDATA text element.
 
virtual XMLNodeShallowClone (XMLDocument *document) const
 
virtual bool ShallowEqual (const XMLNode *compare) const
 
- Public Member Functions inherited from tinyxml2::XMLNode
+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
XMLNodeDeepClone (XMLDocument *target) const
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

XML text.

+

Note that a text node can have child element nodes, for example:

<root>This is <b>bold</b></root>
+

A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCData() and query it with CData().

+

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLText::Accept (XMLVisitorvisitor) const
+
+virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLText::ShallowClone (XMLDocumentdocument) const
+
+virtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLText::ShallowEqual (const XMLNodecompare) const
+
+virtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_text.png b/docs/classtinyxml2_1_1_x_m_l_text.png new file mode 100644 index 0000000000000000000000000000000000000000..5a9863acc475a4164a359cdca7f2ba64ba74433f GIT binary patch literal 591 zcmeAS@N?(olHy`uVBq!ia0vp^6+j%o!3-pyx;pL#QW60^A+G=b{|7Q(y!l$%e`o@b z1;z&s9ANFdBM;un$8s_wr3PH5_!%PyN|NpG0hop@<-(1vAKPMTLvO}Er` z){c}s!+68x)64A%@fY{}v8s&Nr~D!DfLwvzgjEv1A3RGjx|-8|cTvsFf9npc3t5!4 zHuv-T1Iy=6X1@M+H@o>l@4Z&vZkVr^?8w?0p*_3R`}&>>x38|sTKjl&Sm@u~eh2!C z{STZkzJ7kus#g+!RV-Qr)HoiTuVOrNLFdD3(@q=iKhMr7`ZNDe2-i0_Afan;Kma>- z*zV$z#=$7Do|R2v(SN2ta(7cVp3Rrdd_Ol?^4UGsRWon1@f0i-x&He|j?g)ux?|RC z%ky9VUGLI8`Swxa{fzHV_Z8Nxy%n_ld(e?jI_aqys;i3(-=}QoFW!1wEi1C?`xn(S zJ7b!&C9MyvwA0=3^x2P@w;F;QcOOjU#YMK&OXfDq+j;pP^p}75I$bcKqfSUi$;k0PgPVlp+Lc99 R9f7gW;OXk;vd$@?2>?U}6ovo* literal 0 HcmV?d00001 diff --git a/docs/classtinyxml2_1_1_x_m_l_unknown-members.html b/docs/classtinyxml2_1_1_x_m_l_unknown-members.html new file mode 100644 index 0000000..f22b3f1 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_unknown-members.html @@ -0,0 +1,113 @@ + + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLUnknown Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLUnknown, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Accept(XMLVisitor *visitor) consttinyxml2::XMLUnknownvirtual
DeepClone(XMLDocument *target) consttinyxml2::XMLNode
DeleteChild(XMLNode *node)tinyxml2::XMLNode
DeleteChildren()tinyxml2::XMLNode
FirstChild() consttinyxml2::XMLNodeinline
FirstChildElement(const char *name=0) consttinyxml2::XMLNode
GetDocument() consttinyxml2::XMLNodeinline
GetDocument()tinyxml2::XMLNodeinline
GetLineNum() consttinyxml2::XMLNodeinline
GetUserData() consttinyxml2::XMLNodeinline
InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)tinyxml2::XMLNode
InsertEndChild(XMLNode *addThis)tinyxml2::XMLNode
InsertFirstChild(XMLNode *addThis)tinyxml2::XMLNode
LastChild() consttinyxml2::XMLNodeinline
LastChildElement(const char *name=0) consttinyxml2::XMLNode
NextSibling() consttinyxml2::XMLNodeinline
NextSiblingElement(const char *name=0) consttinyxml2::XMLNode
NoChildren() consttinyxml2::XMLNodeinline
Parent() consttinyxml2::XMLNodeinline
PreviousSibling() consttinyxml2::XMLNodeinline
PreviousSiblingElement(const char *name=0) consttinyxml2::XMLNode
SetUserData(void *userData)tinyxml2::XMLNodeinline
SetValue(const char *val, bool staticMem=false)tinyxml2::XMLNode
ShallowClone(XMLDocument *document) consttinyxml2::XMLUnknownvirtual
ShallowEqual(const XMLNode *compare) consttinyxml2::XMLUnknownvirtual
ToComment()tinyxml2::XMLNodeinlinevirtual
ToDeclaration()tinyxml2::XMLNodeinlinevirtual
ToDocument()tinyxml2::XMLNodeinlinevirtual
ToElement()tinyxml2::XMLNodeinlinevirtual
ToText()tinyxml2::XMLNodeinlinevirtual
ToUnknown()tinyxml2::XMLUnknowninlinevirtual
Value() consttinyxml2::XMLNode
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_unknown.html b/docs/classtinyxml2_1_1_x_m_l_unknown.html new file mode 100644 index 0000000..8bd53e4 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_unknown.html @@ -0,0 +1,301 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLUnknown Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLUnknown Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLUnknown:
+
+
+ + +tinyxml2::XMLNode + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+virtual XMLUnknownToUnknown ()
 Safely cast to an Unknown, or null.
 
virtual bool Accept (XMLVisitor *visitor) const
 
virtual XMLNodeShallowClone (XMLDocument *document) const
 
virtual bool ShallowEqual (const XMLNode *compare) const
 
- Public Member Functions inherited from tinyxml2::XMLNode
+const XMLDocumentGetDocument () const
 Get the XMLDocument that owns this XMLNode.
 
+XMLDocumentGetDocument ()
 Get the XMLDocument that owns this XMLNode.
 
+virtual XMLElementToElement ()
 Safely cast to an Element, or null.
 
+virtual XMLTextToText ()
 Safely cast to Text, or null.
 
+virtual XMLCommentToComment ()
 Safely cast to a Comment, or null.
 
+virtual XMLDocumentToDocument ()
 Safely cast to a Document, or null.
 
+virtual XMLDeclarationToDeclaration ()
 Safely cast to a Declaration, or null.
 
const char * Value () const
 
void SetValue (const char *val, bool staticMem=false)
 
+int GetLineNum () const
 Gets the line number the node is in, if the document was parsed from a file.
 
+const XMLNodeParent () const
 Get the parent of this node on the DOM.
 
+bool NoChildren () const
 Returns true if this node has no children.
 
+const XMLNodeFirstChild () const
 Get the first child node, or null if none exists.
 
const XMLElementFirstChildElement (const char *name=0) const
 
+const XMLNodeLastChild () const
 Get the last child node, or null if none exists.
 
const XMLElementLastChildElement (const char *name=0) const
 
+const XMLNodePreviousSibling () const
 Get the previous (left) sibling node of this node.
 
+const XMLElementPreviousSiblingElement (const char *name=0) const
 Get the previous (left) sibling element of this node, with an optionally supplied name.
 
+const XMLNodeNextSibling () const
 Get the next (right) sibling node of this node.
 
+const XMLElementNextSiblingElement (const char *name=0) const
 Get the next (right) sibling element of this node, with an optionally supplied name.
 
XMLNodeInsertEndChild (XMLNode *addThis)
 
XMLNodeInsertFirstChild (XMLNode *addThis)
 
XMLNodeInsertAfterChild (XMLNode *afterThis, XMLNode *addThis)
 
void DeleteChildren ()
 
void DeleteChild (XMLNode *node)
 
XMLNodeDeepClone (XMLDocument *target) const
 
void SetUserData (void *userData)
 
void * GetUserData () const
 
+

Detailed Description

+

Any tag that TinyXML-2 doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved.

+

DTD tags get thrown into XMLUnknowns.

+

Member Function Documentation

+ +

◆ Accept()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLUnknown::Accept (XMLVisitorvisitor) const
+
+virtual
+
+

Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface.

+

This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.)

+

The interface has been based on ideas from:

+ +

Which are both good references for "visiting".

+

An example of using Accept():

XMLPrinter printer;
+tinyxmlDoc.Accept( &printer );
+const char* xmlcstr = printer.CStr();
+
+

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowClone()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual XMLNode* tinyxml2::XMLUnknown::ShallowClone (XMLDocumentdocument) const
+
+virtual
+
+

Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument())

+

Note: if called on a XMLDocument, this will return null.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+ +

◆ ShallowEqual()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool tinyxml2::XMLUnknown::ShallowEqual (const XMLNodecompare) const
+
+virtual
+
+

Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document.

+

Note: if called on a XMLDocument, this will return false.

+ +

Implements tinyxml2::XMLNode.

+ +
+
+
The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_unknown.png b/docs/classtinyxml2_1_1_x_m_l_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..217b62c5590fd41f7e30a49d292a0a03662d9083 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^y+9nm!3-pY71+{%lth3}i0l9V|AEXGZ@!lHADRGU zf$@O@2Ut7r$OE|?B|(0{3_wL7aP?G(5d#C0n5Tv(X1Z$W+JwA7hwVxF^FwoF_y1B4GO%W<8g7x~-!<>GJCc5XC} zzFx3fWo}2V%1hBwqxGA$-`V$`4f}s1t@fGj4YBm)Zfj%@7vH}zW1p?h-lU-F{XwP) zyjR!Bu5w$ra@I~}Y2lYsZdFU~S8!icl|JL|2{oP{$+MOB2N^z9DVC7aN;7@SC4cpo zx@VuY^z@fXH;v>r?cX$UiSYZIUu+BWjn7;+`hB_faerT?$ja%qSHsTQHcNi+PxqRn zo4=<{<)!kSTYr|FS$lTqkezT*3o63I7ytn1$$6x)n`^#ocd!M-Um4$TT z-m(=^t;=p{885qS(w}!*e(Sb3x%ZCgcT{gM{9E=q=2po{!yVk!>A}TTw|b1yJQv0O z5u82mB$Klw|IKK#x{Tdr_a z{mLr|b}?(vy + + + + + + +TinyXML-2: Member List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
tinyxml2::XMLVisitor Member List
+
+
+ +

This is the complete list of members for tinyxml2::XMLVisitor, including all inherited members.

+ + + + + + + + + +
Visit(const XMLDeclaration &)tinyxml2::XMLVisitorinlinevirtual
Visit(const XMLText &)tinyxml2::XMLVisitorinlinevirtual
Visit(const XMLComment &)tinyxml2::XMLVisitorinlinevirtual
Visit(const XMLUnknown &)tinyxml2::XMLVisitorinlinevirtual
VisitEnter(const XMLDocument &)tinyxml2::XMLVisitorinlinevirtual
VisitEnter(const XMLElement &, const XMLAttribute *)tinyxml2::XMLVisitorinlinevirtual
VisitExit(const XMLDocument &)tinyxml2::XMLVisitorinlinevirtual
VisitExit(const XMLElement &)tinyxml2::XMLVisitorinlinevirtual
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_visitor.html b/docs/classtinyxml2_1_1_x_m_l_visitor.html new file mode 100644 index 0000000..4e46128 --- /dev/null +++ b/docs/classtinyxml2_1_1_x_m_l_visitor.html @@ -0,0 +1,138 @@ + + + + + + + +TinyXML-2: tinyxml2::XMLVisitor Class Reference + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
tinyxml2::XMLVisitor Class Reference
+
+
+ +

#include <tinyxml2.h>

+
+Inheritance diagram for tinyxml2::XMLVisitor:
+
+
+ + +tinyxml2::XMLPrinter + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

+virtual bool VisitEnter (const XMLDocument &)
 Visit a document.
 
+virtual bool VisitExit (const XMLDocument &)
 Visit a document.
 
+virtual bool VisitEnter (const XMLElement &, const XMLAttribute *)
 Visit an element.
 
+virtual bool VisitExit (const XMLElement &)
 Visit an element.
 
+virtual bool Visit (const XMLDeclaration &)
 Visit a declaration.
 
+virtual bool Visit (const XMLText &)
 Visit a text node.
 
+virtual bool Visit (const XMLComment &)
 Visit a comment node.
 
+virtual bool Visit (const XMLUnknown &)
 Visit an unknown node.
 
+

Detailed Description

+

Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a XMLVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs are simply called with Visit().

+

If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its siblings will be visited.

+

All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you.

+

Generally Accept() is called on the XMLDocument, although all nodes support visiting.

+

You should never change the document from a callback.

+
See also
XMLNode::Accept()
+

The documentation for this class was generated from the following file: +
+ + + + diff --git a/docs/classtinyxml2_1_1_x_m_l_visitor.png b/docs/classtinyxml2_1_1_x_m_l_visitor.png new file mode 100644 index 0000000000000000000000000000000000000000..8ae4c23cfa5be521ed0b30b0fa6a8048f73e4ee2 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^g!3-py-Rr#uq$C1-LR|m<{|{uoc=NTi|Ih>= z3ycpOIKbL@M;^%KC<*clW&kPzfvcxNj2IXg?|Zs9hEy=Vo%?!Sivmx}a@CK2<$tb- zsS-SLR&A4I=B0IObT6Oh`XTP(qAkn9@Y;rf$${b9>z=0_@~^}Gn+vB_aQ1%TWnj2d zd2s{FOs)TK8Gf)cB&=baBD?dy$yFIEy=|X_891+gSXgtUc-@uKx7t#vS-ZnuPT6wp zr1;ci2968MCR#IWyS!CasHAp{k1)gf_0x}WD1`53`0-10RoM4a*N<1QT$snnl3y2n zhLIuY8)L(s`<4xF%lCg_IiOc&s^IYEPlKeCcC^qLznt|B@0)IV{&i0R7CQWtETEz3+#Pf^sj7T451LOOZ7q?f^s3g+MMWYF*Gn&mGu(c8i;r`cUf42j zhgjyY0PpYO3w_@J{k+v{?YsEPq6-$>W!{pWlmzs34cCKfk7dEWj+8QPsAGSV6waI^ zcAEE!Nmz)`E`}=cJM&xk`&iSSy{~2X5cQYwK=s$h*%A!)j1z*qxc~CcJ|-QRW+x*J PjD7}BS3j3^P61|%O$WD@{V-kvUwAr*{o@8{^CZMh(5KoB^r_<4^zF@3)Cp&&t3hdujKf f*?bjBoY!V+E))@{xMcbjXe@)LtDnm{r-UW|*e5JT literal 0 HcmV?d00001 diff --git a/docs/doc.png b/docs/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..17edabff95f7b8da13c9516a04efe05493c29501 GIT binary patch literal 746 zcmV7=@pnbNXRFEm&G8P!&WHG=d)>K?YZ1bzou)2{$)) zumDct!>4SyxL;zgaG>wy`^Hv*+}0kUfCrz~BCOViSb$_*&;{TGGn2^x9K*!Sf0=lV zpP=7O;GA0*Jm*tTYj$IoXvimpnV4S1Z5f$p*f$Db2iq2zrVGQUz~yq`ahn7ck(|CE z7Gz;%OP~J6)tEZWDzjhL9h2hdfoU2)Nd%T<5Kt;Y0XLt&<@6pQx!nw*5`@bq#?l*?3z{Hlzoc=Pr>oB5(9i6~_&-}A(4{Q$>c>%rV&E|a(r&;?i5cQB=} zYSDU5nXG)NS4HEs0it2AHe2>shCyr7`6@4*6{r@8fXRbTA?=IFVWAQJL&H5H{)DpM#{W(GL+Idzf^)uRV@oB8u$ z8v{MfJbTiiRg4bza<41NAzrl{=3fl_D+$t+^!xlQ8S}{UtY`e z;;&9UhyZqQRN%2pot{*Ei0*4~hSF_3AH2@fKU!$NSflS>{@tZpDT4`M2WRTTVH+D? z)GFlEGGHe?koB}i|1w45!BF}N_q&^HJ&-tyR{(afC6H7|aml|tBBbv}55C5DNP8p3 z)~jLEO4Z&2hZmP^i-e%(@d!(E|KRafiU8Q5u(wU((j8un3OR*Hvj+t literal 0 HcmV?d00001 diff --git a/docs/doxygen.css b/docs/doxygen.css new file mode 100644 index 0000000..4f1ab91 --- /dev/null +++ b/docs/doxygen.css @@ -0,0 +1,1596 @@ +/* The standard CSS for doxygen 1.8.13 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0px; + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #E2E8F2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-color: #DFE5F1; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + + +/* @end */ diff --git a/docs/doxygen.png b/docs/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff17d807fd8aa003bed8bb2a69e8f0909592fd1 GIT binary patch literal 3779 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 literal 0 HcmV?d00001 diff --git a/docs/dynsections.js b/docs/dynsections.js new file mode 100644 index 0000000..85e1836 --- /dev/null +++ b/docs/dynsections.js @@ -0,0 +1,97 @@ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + + +TinyXML-2: File List + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ + +
 tinyxml2.h
+
+
+ + + + diff --git a/docs/folderclosed.png b/docs/folderclosed.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8ab35edce8e97554e360005ee9fc5bffb36e66 GIT binary patch literal 616 zcmV-u0+;=XP)a9#ETzayK)T~Jw&MMH>OIr#&;dC}is*2Mqdf&akCc=O@`qC+4i z5Iu3w#1M@KqXCz8TIZd1wli&kkl2HVcAiZ8PUn5z_kG@-y;?yK06=cA0U%H0PH+kU zl6dp}OR(|r8-RG+YLu`zbI}5TlOU6ToR41{9=uz^?dGTNL;wIMf|V3`d1Wj3y!#6` zBLZ?xpKR~^2x}?~zA(_NUu3IaDB$tKma*XUdOZN~c=dLt_h_k!dbxm_*ibDM zlFX`g{k$X}yIe%$N)cn1LNu=q9_CS)*>A zsX_mM4L@`(cSNQKMFc$RtYbx{79#j-J7hk*>*+ZZhM4Hw?I?rsXCi#mRWJ=-0LGV5a-WR0Qgt<|Nqf)C-@80`5gIz45^_20000IqP)X=#(TiCT&PiIIVc55T}TU}EUh*{q$|`3@{d>{Tc9Bo>e= zfmF3!f>fbI9#GoEHh0f`i5)wkLpva0ztf%HpZneK?w-7AK@b4Itw{y|Zd3k!fH?q2 zlhckHd_V2M_X7+)U&_Xcfvtw60l;--DgZmLSw-Y?S>)zIqMyJ1#FwLU*%bl38ok+! zh78H87n`ZTS;uhzAR$M`zZ`bVhq=+%u9^$5jDplgxd44}9;IRqUH1YHH|@6oFe%z( zo4)_>E$F&^P-f(#)>(TrnbE>Pefs9~@iN=|)Rz|V`sGfHNrJ)0gJb8xx+SBmRf@1l zvuzt=vGfI)<-F9!o&3l?>9~0QbUDT(wFdnQPv%xdD)m*g%!20>Bc9iYmGAp<9YAa( z0QgYgTWqf1qN++Gqp z8@AYPTB3E|6s=WLG?xw0tm|U!o=&zd+H0oRYE;Dbx+Na9s^STqX|Gnq%H8s(nGDGJ j8vwW|`Ts`)fSK|Kx=IK@RG@g200000NkvXXu0mjfauFEA literal 0 HcmV?d00001 diff --git a/docs/functions.html b/docs/functions.html new file mode 100644 index 0000000..1e61737 --- /dev/null +++ b/docs/functions.html @@ -0,0 +1,544 @@ + + + + + + + +TinyXML-2: Class Members + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- a -

+ + +

- b -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- h -

+ + +

- i -

+ + +

- l -

+ + +

- n -

+ + +

- o -

+ + +

- p -

+ + +

- q -

+ + +

- r -

+ + +

- s -

+ + +

- t -

+ + +

- u -

+ + +

- v -

+ + +

- x -

+
+ + + + diff --git a/docs/functions_func.html b/docs/functions_func.html new file mode 100644 index 0000000..f82f7cb --- /dev/null +++ b/docs/functions_func.html @@ -0,0 +1,544 @@ + + + + + + + +TinyXML-2: Class Members - Functions + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+ + +

- b -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- h -

+ + +

- i -

+ + +

- l -

+ + +

- n -

+ + +

- o -

+ + +

- p -

+ + +

- q -

+ + +

- r -

+ + +

- s -

+ + +

- t -

+ + +

- u -

+ + +

- v -

+ + +

- x -

+
+ + + + diff --git a/docs/hierarchy.html b/docs/hierarchy.html new file mode 100644 index 0000000..97c3cd4 --- /dev/null +++ b/docs/hierarchy.html @@ -0,0 +1,90 @@ + + + + + + + +TinyXML-2: Class Hierarchy + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class Hierarchy
+
+
+
This inheritance list is sorted roughly, but not completely, alphabetically:
+
+ + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..a3808ea --- /dev/null +++ b/docs/index.html @@ -0,0 +1,230 @@ + + + + + + + +TinyXML-2: TinyXML-2 + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
TinyXML-2
+
+
+

+
+TinyXML-2 Logo +
+

TinyXML-2 is a simple, small, efficient, C++ XML parser that can be easily integrated into other programs.

+

The master is hosted on github: https://github.com/leethomason/tinyxml2

+

The online HTML version of these docs: http://leethomason.github.io/tinyxml2/

+

Examples are in the "related pages" tab of the HTML docs.

+

What it does.

+

In brief, TinyXML-2 parses an XML document, and builds from that a Document Object Model (DOM) that can be read, modified, and saved.

+

XML stands for "eXtensible Markup Language." It is a general purpose human and machine readable markup language to describe arbitrary data. All those random file formats created to store application data can all be replaced with XML. One parser for everything.

+

http://en.wikipedia.org/wiki/XML

+

There are different ways to access and interact with XML data. TinyXML-2 uses a Document Object Model (DOM), meaning the XML data is parsed into a C++ objects that can be browsed and manipulated, and then written to disk or another output stream. You can also construct an XML document from scratch with C++ objects and write this to disk or another output stream. You can even use TinyXML-2 to stream XML programmatically from code without creating a document first.

+

TinyXML-2 is designed to be easy and fast to learn. It is one header and one cpp file. Simply add these to your project and off you go. There is an example file - xmltest.cpp - to get you started.

+

TinyXML-2 is released under the ZLib license, so you can use it in open source or commercial code. The details of the license are at the top of every source file.

+

TinyXML-2 attempts to be a flexible parser, but with truly correct and compliant XML output. TinyXML-2 should compile on any reasonably C++ compliant system. It does not rely on exceptions, RTTI, or the STL.

+

What it doesn't do.

+

TinyXML-2 doesn't parse or use DTDs (Document Type Definitions) or XSLs (eXtensible Stylesheet Language.) There are other parsers out there that are much more fully featured. But they are also much bigger, take longer to set up in your project, have a higher learning curve, and often have a more restrictive license. If you are working with browsers or have more complete XML needs, TinyXML-2 is not the parser for you.

+

TinyXML-1 vs. TinyXML-2

+

TinyXML-2 is now the focus of all development, well tested, and your best choice unless you have a requirement to maintain TinyXML-1 code.

+

TinyXML-2 uses a similar API to TinyXML-1 and the same rich test cases. But the implementation of the parser is completely re-written to make it more appropriate for use in a game. It uses less memory, is faster, and uses far fewer memory allocations.

+

TinyXML-2 has no requirement for STL, but has also dropped all STL support. All strings are query and set as 'const char*'. This allows the use of internal allocators, and keeps the code much simpler.

+

Both parsers:

+
    +
  1. Simple to use with similar APIs.
  2. +
  3. DOM based parser.
  4. +
  5. UTF-8 Unicode support. http://en.wikipedia.org/wiki/UTF-8
  6. +
+

Advantages of TinyXML-2

+
    +
  1. The focus of all future dev.
  2. +
  3. Many fewer memory allocation (1/10th to 1/100th), uses less memory (about 40% of TinyXML-1), and faster.
  4. +
  5. No STL requirement.
  6. +
  7. More modern C++, including a proper namespace.
  8. +
  9. Proper and useful handling of whitespace
  10. +
+

Advantages of TinyXML-1

+
    +
  1. Support for some C++ STL conventions: streams and strings
  2. +
  3. Very mature and well debugged code base.
  4. +
+

Features

+

Memory Model

+

An XMLDocument is a C++ object like any other, that can be on the stack, or new'd and deleted on the heap.

+

However, any sub-node of the Document, XMLElement, XMLText, etc, can only be created by calling the appropriate XMLDocument::NewElement, NewText, etc. method. Although you have pointers to these objects, they are still owned by the Document. When the Document is deleted, so are all the nodes it contains.

+

White Space

+

Whitespace Preservation (default)

+

Microsoft has an excellent article on white space: http://msdn.microsoft.com/en-us/library/ms256097.aspx

+

By default, TinyXML-2 preserves white space in a (hopefully) sane way that is almost compliant with the spec. (TinyXML-1 used a completely different model, much more similar to 'collapse', below.)

+

As a first step, all newlines / carriage-returns / line-feeds are normalized to a line-feed character, as required by the XML spec.

+

White space in text is preserved. For example:

<element> Hello,  World</element>
+

The leading space before the "Hello" and the double space after the comma are preserved. Line-feeds are preserved, as in this example:

<element> Hello again,  
+          World</element>
+

However, white space between elements is not preserved. Although not strictly compliant, tracking and reporting inter-element space is awkward, and not normally valuable. TinyXML-2 sees these as the same XML:

<document>
+    <data>1</data>
+    <data>2</data>
+    <data>3</data>
+</document>
+
+<document><data>1</data><data>2</data><data>3</data></document>
+

Whitespace Collapse

+

For some applications, it is preferable to collapse whitespace. Collapsing whitespace gives you "HTML-like" behavior, which is sometimes more suitable for hand typed documents.

+

TinyXML-2 supports this with the 'whitespace' parameter to the XMLDocument constructor. (The default is to preserve whitespace, as described above.)

+

However, you may also use COLLAPSE_WHITESPACE, which will:

+
    +
  • Remove leading and trailing whitespace
  • +
  • Convert newlines and line-feeds into a space character
  • +
  • Collapse a run of any number of space characters into a single space character
  • +
+

Note that (currently) there is a performance impact for using COLLAPSE_WHITESPACE. It essentially causes the XML to be parsed twice.

+

Error Reporting

+

TinyXML-2 reports the line number of any errors in an XML document that cannot be parsed correctly. In addition, all nodes (elements, declarations, text, comments etc.) and attributes have a line number recorded as they are parsed. This allows an application that performs additional validation of the parsed XML document (e.g. application-implemented DTD validation) to report line number information in it's errors.

+

Entities

+

TinyXML-2 recognizes the pre-defined "character entities", meaning special characters. Namely:

&amp;   &
+&lt;    <
+&gt;    >
+&quot;  "
+&apos;  '
+

These are recognized when the XML document is read, and translated to their UTF-8 equivalents. For instance, text with the XML of:

Far &amp; Away
+

will have the Value() of "Far & Away" when queried from the XMLText object, and will be written back to the XML stream/file as an ampersand.

+

Additionally, any character can be specified by its Unicode code point: The syntax &#xA0; or &#160; are both to the non-breaking space character. This is called a 'numeric character reference'. Any numeric character reference that isn't one of the special entities above, will be read, but written as a regular code point. The output is correct, but the entity syntax isn't preserved.

+

Printing

+

Print to file

+

You can directly use the convenience function:

XMLDocument doc;
+...
+doc.SaveFile( "foo.xml" );
+

Or the XMLPrinter class:

XMLPrinter printer( fp );
+doc.Print( &printer );
+

Print to memory

+

Printing to memory is supported by the XMLPrinter.

XMLPrinter printer;
+doc.Print( &printer );
+// printer.CStr() has a const char* to the XML
+

Print without an XMLDocument

+

When loading, an XML parser is very useful. However, sometimes when saving, it just gets in the way. The code is often set up for streaming, and constructing the DOM is just overhead.

+

The Printer supports the streaming case. The following code prints out a trivially simple XML file without ever creating an XML document.

XMLPrinter printer( fp );
+printer.OpenElement( "foo" );
+printer.PushAttribute( "foo", "bar" );
+printer.CloseElement();
+

Examples

+

Load and parse an XML file.

+
/* ------ Example 1: Load and parse an XML file. ---- */    
+{
+    XMLDocument doc;
+    doc.LoadFile( "dream.xml" );
+}
+

Lookup information.

+
/* ------ Example 2: Lookup information. ---- */    
+{
+    XMLDocument doc;
+    doc.LoadFile( "dream.xml" );
+
+    // Structure of the XML file:
+    // - Element "PLAY"      the root Element, which is the 
+    //                       FirstChildElement of the Document
+    // - - Element "TITLE"   child of the root PLAY Element
+    // - - - Text            child of the TITLE Element
+
+    // Navigate to the title, using the convenience function,
+    // with a dangerous lack of error checking.
+    const char* title = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->GetText();
+    printf( "Name of play (1): %s\n", title );
+
+    // Text is just another Node to TinyXML-2. The more
+    // general way to get to the XMLText:
+    XMLText* textNode = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->FirstChild()->ToText();
+    title = textNode->Value();
+    printf( "Name of play (2): %s\n", title );
+}
+

Using and Installing

+

There are 2 files in TinyXML-2:

+

And additionally a test file:

    +
  • xmltest.cpp
  • +
+

Simply compile and run. There is a visual studio 2015 project included, a simple Makefile, an Xcode project, a Code::Blocks project, and a cmake CMakeLists.txt included to help you. The top of tinyxml.h even has a simple g++ command line if you are are *nix and don't want to use a build system.

+

Versioning

+

TinyXML-2 uses semantic versioning. http://semver.org/ Releases are now tagged in github.

+

Note that the major version will (probably) change fairly rapidly. API changes are fairly common.

+

Documentation

+

The documentation is build with Doxygen, using the 'dox' configuration file.

+

License

+

TinyXML-2 is released under the zlib license:

+

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

+

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

+
    +
  1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  2. +
  3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  4. +
  5. This notice may not be removed or altered from any source distribution.
  6. +
+

Contributors

+

Thanks very much to everyone who sends suggestions, bugs, ideas, and encouragement. It all helps, and makes this project fun.

+

The original TinyXML-1 has many contributors, who all deserve thanks in shaping what is a very successful library. Extra thanks to Yves Berquin and Andrew Ellerton who were key contributors.

+

TinyXML-2 grew from that effort. Lee Thomason is the original author of TinyXML-2 (and TinyXML-1) but TinyXML-2 has been and is being improved by many contributors.

+

Thanks to John Mackay at http://john.mackay.rosalilastudio.com for the TinyXML-2 logo!

+
+ + + + diff --git a/docs/jquery.js b/docs/jquery.js new file mode 100644 index 0000000..f5343ed --- /dev/null +++ b/docs/jquery.js @@ -0,0 +1,87 @@ +/*! + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ +(function(bb,L){var av=bb.document,bu=bb.navigator,bl=bb.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bb.jQuery,bH=bb.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b40){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bb.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bb.attachEvent("onload",bF.ready);var b0=false;try{b0=bb.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0&&typeof b0==="object"&&"setInterval" in b0},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bb.JSON&&bb.JSON.parse){return bb.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){var b0,b1;try{if(bb.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bb.execScript||function(b1){bb["eval"].call(bb,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b40&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b21?aJ.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aJ.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv
a";bI=bv.getElementsByTagName("*");bF=bv.getElementsByTagName("a")[0];if(!bI||!bI.length||!bF){return{}}bG=av.createElement("select");bx=bG.appendChild(av.createElement("option"));bE=bv.getElementsByTagName("input")[0];bJ={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bF.getAttribute("style")),hrefNormalized:(bF.getAttribute("href")==="/a"),opacity:/^0.55/.test(bF.style.opacity),cssFloat:!!bF.style.cssFloat,checkOn:(bE.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true};bE.checked=true;bJ.noCloneChecked=bE.cloneNode(true).checked;bG.disabled=true;bJ.optDisabled=!bx.disabled;try{delete bv.test}catch(bC){bJ.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bJ.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bE=av.createElement("input");bE.value="t";bE.setAttribute("type","radio");bJ.radioValue=bE.value==="t";bE.setAttribute("checked","checked");bv.appendChild(bE);bD=av.createDocumentFragment();bD.appendChild(bv.lastChild);bJ.checkClone=bD.cloneNode(true).cloneNode(true).lastChild.checked;bJ.appendChecked=bE.checked;bD.removeChild(bE);bD.appendChild(bv);bv.innerHTML="";if(bb.getComputedStyle){bA=av.createElement("div");bA.style.width="0";bA.style.marginRight="0";bv.style.width="2px";bv.appendChild(bA);bJ.reliableMarginRight=(parseInt((bb.getComputedStyle(bA,null)||{marginRight:0}).marginRight,10)||0)===0}if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bB="on"+by;bw=(bB in bv);if(!bw){bv.setAttribute(bB,"return;");bw=(typeof bv[bB]==="function")}bJ[by+"Bubbles"]=bw}}bD.removeChild(bv);bD=bG=bx=bA=bv=bE=null;b(function(){var bM,bU,bV,bT,bN,bO,bL,bS,bR,e,bP,bQ=av.getElementsByTagName("body")[0];if(!bQ){return}bL=1;bS="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";bR="visibility:hidden;border:0;";e="style='"+bS+"border:5px solid #000;padding:0;'";bP="
";bM=av.createElement("div");bM.style.cssText=bR+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bQ.insertBefore(bM,bQ.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="
t
";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bJ.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);bv.innerHTML="";bv.style.width=bv.style.paddingLeft="1px";b.boxModel=bJ.boxModel=bv.offsetWidth===2;if(typeof bv.style.zoom!=="undefined"){bv.style.display="inline";bv.style.zoom=1;bJ.inlineBlockNeedsLayout=(bv.offsetWidth===2);bv.style.display="";bv.innerHTML="
";bJ.shrinkWrapBlocks=(bv.offsetWidth!==2)}bv.style.cssText=bS+bR;bv.innerHTML=bP;bU=bv.firstChild;bV=bU.firstChild;bN=bU.nextSibling.firstChild.firstChild;bO={doesNotAddBorder:(bV.offsetTop!==5),doesAddBorderForTableAndCells:(bN.offsetTop===5)};bV.style.position="fixed";bV.style.top="20px";bO.fixedPosition=(bV.offsetTop===20||bV.offsetTop===15);bV.style.position=bV.style.top="";bU.style.overflow="hidden";bU.style.position="relative";bO.subtractsBorderForOverflowNotVisible=(bV.offsetTop===-5);bO.doesNotIncludeMarginInBodyOffset=(bQ.offsetTop!==bL);bQ.removeChild(bM);bv=bM=null;b.extend(bJ,bO)});return bJ})();var aS=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.nodeName.toLowerCase()]||b.valHooks[bw.type];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aU,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.nodeName.toLowerCase()]||b.valHooks[this.type];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType;if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aY:be)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(bx,bz){var by,bA,bv,e,bw=0;if(bz&&bx.nodeType===1){bA=bz.toLowerCase().split(af);e=bA.length;for(;bw=0)}}})});var bd=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/\bhover(\.\S+)?\b/,aO=/^key/,bf=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bb,bI])}}for(bC=0;bCbA){bH.push({elem:this,matches:bz.slice(bA)})}for(bC=0;bC0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aO.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bf.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1},lt:function(bS,bR,e){return bRe[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="

";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="
";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT0){for(bB=bA;bB=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(C(bx[0])||C(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function C(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling(e.parentNode.firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||a9.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aG(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aR.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aR="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ag=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,w=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},ac=a(av);ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div
","
"]}b.fn.extend({text:function(e){if(b.isFunction(e)){return this.each(function(bw){var bv=b(this);bv.text(e.call(this,bw,bv.text()))})}if(typeof e!=="object"&&e!==L){return this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(e))}return b.text(this)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(bx){if(bx===L){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ag,""):null}else{if(typeof bx==="string"&&!ae.test(bx)&&(b.support.leadingWhitespace||!ar.test(bx))&&!ax[(d.exec(bx)||["",""])[1].toLowerCase()]){bx=bx.replace(R,"<$1>");try{for(var bw=0,bv=this.length;bw1&&bw0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bg(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function E(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function al(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||!ah.test("<"+by.nodeName)?by.cloneNode(true):al(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){ai(by,bz);e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){if(bv[bx]){ai(e[bx],bv[bx])}}}if(bA){t(by,bz);if(bw){e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){t(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bw,by,bH,bA){var bF;by=by||av;if(typeof by.createElement==="undefined"){by=by.ownerDocument||by[0]&&by[0].ownerDocument||av}var bI=[],bB;for(var bE=0,bz;(bz=bw[bE])!=null;bE++){if(typeof bz==="number"){bz+=""}if(!bz){continue}if(typeof bz==="string"){if(!W.test(bz)){bz=by.createTextNode(bz)}else{bz=bz.replace(R,"<$1>");var bK=(d.exec(bz)||["",""])[1].toLowerCase(),bx=ax[bK]||ax._default,bD=bx[0],bv=by.createElement("div");if(by===av){ac.appendChild(bv)}else{a(by).appendChild(bv)}bv.innerHTML=bx[1]+bz+bx[2];while(bD--){bv=bv.lastChild}if(!b.support.tbody){var e=w.test(bz),bC=bK==="table"&&!e?bv.firstChild&&bv.firstChild.childNodes:bx[1]===""&&!e?bv.childNodes:[];for(bB=bC.length-1;bB>=0;--bB){if(b.nodeName(bC[bB],"tbody")&&!bC[bB].childNodes.length){bC[bB].parentNode.removeChild(bC[bB])}}}if(!b.support.leadingWhitespace&&ar.test(bz)){bv.insertBefore(by.createTextNode(ar.exec(bz)[0]),bv.firstChild)}bz=bv.childNodes}}var bG;if(!b.support.appendChecked){if(bz[0]&&typeof(bG=bz.length)==="number"){for(bB=0;bB=0){return bx+"px"}}else{return bx}}}});if(!b.support.opacity){b.cssHooks.opacity={get:function(bv,e){return au.test((e&&bv.currentStyle?bv.currentStyle.filter:bv.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(by,bz){var bx=by.style,bv=by.currentStyle,e=b.isNumeric(bz)?"alpha(opacity="+bz*100+")":"",bw=bv&&bv.filter||bx.filter||"";bx.zoom=1;if(bz>=1&&b.trim(bw.replace(ak,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=ak.test(bw)?bw.replace(ak,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bw,bv){var e;b.swap(bw,{display:"inline-block"},function(){if(bv){e=Z(bw,"margin-right","marginRight")}else{e=bw.style.marginRight}});return e}}}});if(av.defaultView&&av.defaultView.getComputedStyle){aI=function(by,bw){var bv,bx,e;bw=bw.replace(z,"-$1").toLowerCase();if((bx=by.ownerDocument.defaultView)&&(e=bx.getComputedStyle(by,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(by.ownerDocument.documentElement,by)){bv=b.style(by,bw)}}return bv}}if(av.documentElement.currentStyle){aX=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv===null&&bx&&(by=bx[bw])){bv=by}if(!bc.test(bv)&&bn.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":(bv||0);bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aI||aX;function p(by,bw,bv){var bA=bw==="width"?by.offsetWidth:by.offsetHeight,bz=bw==="width"?an:a1,bx=0,e=bz.length;if(bA>0){if(bv!=="border"){for(;bx)<[^<]*)*<\/script>/gi,q=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,A=b.fn.load,aa={},r={},aE,s,aV=["*/"]+["*"];try{aE=bl.href}catch(aw){aE=av.createElement("a");aE.href="";aE=aE.href}s=K.exec(aE.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("
").append(bD.replace(a6,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||q.test(this.nodeName)||aZ.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){am(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}am(bv,e);return bv},ajaxSettings:{url:aE,isLocal:aM.test(s[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aV},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bb.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(r),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bj(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=G(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,s[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=s[1]||bI[2]!=s[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(s[3]||(s[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aW(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aQ.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aV+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aW(r,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){v(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function v(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{v(bw+"["+(typeof bz==="object"||b.isArray(bz)?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&by!=null&&typeof by==="object"){for(var e in by){v(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bj(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function G(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!a8){a8=av.createElement("iframe");a8.frameBorder=a8.width=a8.height=0}e.appendChild(a8);if(!m||!a8.createElement){m=(a8.contentWindow||a8.contentDocument).document;m.write((av.compatMode==="CSS1Compat"?"":"")+"");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(a8)}Q[bx]=bw}return Q[bx]}var V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){b.fn.offset=function(bI){var by=this[0],bB;if(bI){return this.each(function(e){b.offset.setOffset(this,bI,e)})}if(!by||!by.ownerDocument){return null}if(by===by.ownerDocument.body){return b.offset.bodyOffset(by)}try{bB=by.getBoundingClientRect()}catch(bF){}var bH=by.ownerDocument,bw=bH.documentElement;if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aK(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{b.fn.offset=function(bF){var bz=this[0];if(bF){return this.each(function(bG){b.offset.setOffset(this,bF,bG)})}if(!bz||!bz.ownerDocument){return null}if(bz===bz.ownerDocument.body){return b.offset.bodyOffset(bz)}var bC,bw=bz.offsetParent,bv=bz,bE=bz.ownerDocument,bx=bE.documentElement,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each(["Left","Top"],function(bv,e){var bw="scroll"+e;b.fn[bw]=function(bz){var bx,by;if(bz===L){bx=this[0];if(!bx){return null}by=aK(bx);return by?("pageXOffset" in by)?by[bv?"pageYOffset":"pageXOffset"]:b.support.boxModel&&by.document.documentElement[bw]||by.document.body[bw]:bx[bw]}return this.each(function(){by=aK(this);if(by){by.scrollTo(!bv?bz:b(by).scrollLeft(),bv?bz:b(by).scrollTop())}else{this[bw]=bz}})}});function aK(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each(["Height","Width"],function(bv,e){var bw=e.toLowerCase();b.fn["inner"+e]=function(){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,"padding")):this[bw]():null};b.fn["outer"+e]=function(by){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,by?"margin":"border")):this[bw]():null};b.fn[bw]=function(bz){var bA=this[0];if(!bA){return bz==null?null:this}if(b.isFunction(bz)){return this.each(function(bE){var bD=b(this);bD[bw](bz.call(this,bE,bD[bw]()))})}if(b.isWindow(bA)){var bB=bA.document.documentElement["client"+e],bx=bA.document.body;return bA.document.compatMode==="CSS1Compat"&&bB||bx&&bx["client"+e]||bB}else{if(bA.nodeType===9){return Math.max(bA.documentElement["client"+e],bA.body["scroll"+e],bA.documentElement["scroll"+e],bA.body["offset"+e],bA.documentElement["offset"+e])}else{if(bz===L){var bC=b.css(bA,bw),by=parseFloat(bC);return b.isNumeric(by)?by:bC}else{return this.css(bw,typeof bz==="string"?bz:bz+"px")}}}}});bb.jQuery=bb.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b})}})(window);/*! + * jQuery UI 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/*! + * jQuery UI Widget 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/*! + * jQuery UI Mouse 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Mouse + * + * Depends: + * jquery.ui.widget.js + */ +(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('
').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g
');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null;p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/*! + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$(' + + +
+
+
Related Pages
+
+
+
Here is a list of all related documentation pages:
+
+ + + + +
 Load an XML File
 Parse an XML from char buffer
 Get information out of XML
 Read attributes and text information.
+ + + + + + diff --git a/docs/search/all_0.html b/docs/search/all_0.html new file mode 100644 index 0000000..f25360b --- /dev/null +++ b/docs/search/all_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_0.js b/docs/search/all_0.js new file mode 100644 index 0000000..28cfce2 --- /dev/null +++ b/docs/search/all_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['accept',['Accept',['../classtinyxml2_1_1_x_m_l_node.html#a81e66df0a44c67a7af17f3b77a152785',1,'tinyxml2::XMLNode::Accept()'],['../classtinyxml2_1_1_x_m_l_text.html#a1b2c1448f1a21299d0a7913f18b55206',1,'tinyxml2::XMLText::Accept()'],['../classtinyxml2_1_1_x_m_l_comment.html#a4a33dc32fae0285b03f9cfcb3e43e122',1,'tinyxml2::XMLComment::Accept()'],['../classtinyxml2_1_1_x_m_l_declaration.html#a5f376019fb34752eb248548f42f32045',1,'tinyxml2::XMLDeclaration::Accept()'],['../classtinyxml2_1_1_x_m_l_unknown.html#a70983aa1b1cff3d3aa6d4d0a80e5ee48',1,'tinyxml2::XMLUnknown::Accept()'],['../classtinyxml2_1_1_x_m_l_element.html#a3ea8a40e788fb9ad876c28a32932c6d5',1,'tinyxml2::XMLElement::Accept()'],['../classtinyxml2_1_1_x_m_l_document.html#a9efa54f7ecb37c17ab1fa2b3078ccca1',1,'tinyxml2::XMLDocument::Accept()']]], + ['attribute',['Attribute',['../classtinyxml2_1_1_x_m_l_element.html#a70e49ed60b11212ae35f7e354cfe1de9',1,'tinyxml2::XMLElement']]] +]; diff --git a/docs/search/all_1.html b/docs/search/all_1.html new file mode 100644 index 0000000..b13f0f7 --- /dev/null +++ b/docs/search/all_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_1.js b/docs/search/all_1.js new file mode 100644 index 0000000..2f5497b --- /dev/null +++ b/docs/search/all_1.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['boolattribute',['BoolAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a53eda26131e1ad1031ef8ec8adb51bd8',1,'tinyxml2::XMLElement']]], + ['booltext',['BoolText',['../classtinyxml2_1_1_x_m_l_element.html#a68569f59f6382bcea7f5013ec59736d2',1,'tinyxml2::XMLElement']]], + ['boolvalue',['BoolValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a98ce5207344ad33a265b0422addae1ff',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/all_10.html b/docs/search/all_10.html new file mode 100644 index 0000000..d1345a1 --- /dev/null +++ b/docs/search/all_10.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_10.js b/docs/search/all_10.js new file mode 100644 index 0000000..280048c --- /dev/null +++ b/docs/search/all_10.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['tinyxml_2d2',['TinyXML-2',['../index.html',1,'']]], + ['tocomment',['ToComment',['../classtinyxml2_1_1_x_m_l_node.html#aff47671055aa99840a1c1ebd661e63e3',1,'tinyxml2::XMLNode::ToComment()'],['../classtinyxml2_1_1_x_m_l_comment.html#a8093e1dc8a34fa446d9dc3fde0e6c0ee',1,'tinyxml2::XMLComment::ToComment()']]], + ['todeclaration',['ToDeclaration',['../classtinyxml2_1_1_x_m_l_node.html#a174fd4c22c010b58138c1b84a0dfbd51',1,'tinyxml2::XMLNode::ToDeclaration()'],['../classtinyxml2_1_1_x_m_l_declaration.html#a159d8ac45865215e88059ea1e5b52fc5',1,'tinyxml2::XMLDeclaration::ToDeclaration()'],['../classtinyxml2_1_1_x_m_l_handle.html#a108858be7ee3eb53f73b5194c1aa8ff0',1,'tinyxml2::XMLHandle::ToDeclaration()']]], + ['todocument',['ToDocument',['../classtinyxml2_1_1_x_m_l_node.html#a836e2966ed736fc3c94f70e12a2a3357',1,'tinyxml2::XMLNode::ToDocument()'],['../classtinyxml2_1_1_x_m_l_document.html#a3e185f880882bd978367bb55937735ec',1,'tinyxml2::XMLDocument::ToDocument()']]], + ['toelement',['ToElement',['../classtinyxml2_1_1_x_m_l_node.html#aab516e699567f75cc9ab2ef2eee501e8',1,'tinyxml2::XMLNode::ToElement()'],['../classtinyxml2_1_1_x_m_l_element.html#ad9ff5c2dbc15df36cf664ce1b0ea0a5d',1,'tinyxml2::XMLElement::ToElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a5e73ed8f3f6f9619d5a8bb1862c47d99',1,'tinyxml2::XMLHandle::ToElement()']]], + ['tonode',['ToNode',['../classtinyxml2_1_1_x_m_l_handle.html#a03ea6ec970a021b71bf1219a0f6717df',1,'tinyxml2::XMLHandle']]], + ['totext',['ToText',['../classtinyxml2_1_1_x_m_l_node.html#a41c55dab9162d1eb62db2008430e376b',1,'tinyxml2::XMLNode::ToText()'],['../classtinyxml2_1_1_x_m_l_text.html#ab1213b4ddebe9b17ec7e7040e9f1caf7',1,'tinyxml2::XMLText::ToText()'],['../classtinyxml2_1_1_x_m_l_handle.html#a6ab9e8cbfb41417246e5657e3842c62a',1,'tinyxml2::XMLHandle::ToText()']]], + ['tounknown',['ToUnknown',['../classtinyxml2_1_1_x_m_l_node.html#a8675a74aa0ada6eccab0c77ef3e5b9bd',1,'tinyxml2::XMLNode::ToUnknown()'],['../classtinyxml2_1_1_x_m_l_unknown.html#af4374856421921cad578c8affae872b6',1,'tinyxml2::XMLUnknown::ToUnknown()'],['../classtinyxml2_1_1_x_m_l_handle.html#aa387368a1ad8d843a9f12df863d298de',1,'tinyxml2::XMLHandle::ToUnknown()']]] +]; diff --git a/docs/search/all_11.html b/docs/search/all_11.html new file mode 100644 index 0000000..2be8b71 --- /dev/null +++ b/docs/search/all_11.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_11.js b/docs/search/all_11.js new file mode 100644 index 0000000..7e35c72 --- /dev/null +++ b/docs/search/all_11.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['unsignedattribute',['UnsignedAttribute',['../classtinyxml2_1_1_x_m_l_element.html#afea43a1d4aa33e3703ddee5fc9adc26c',1,'tinyxml2::XMLElement']]], + ['unsignedtext',['UnsignedText',['../classtinyxml2_1_1_x_m_l_element.html#a49bad014ffcc17b0b6119d5b2c97dfb5',1,'tinyxml2::XMLElement']]], + ['unsignedvalue',['UnsignedValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a0be5343b08a957c42c02c5d32c35d338',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/all_12.html b/docs/search/all_12.html new file mode 100644 index 0000000..13c5263 --- /dev/null +++ b/docs/search/all_12.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_12.js b/docs/search/all_12.js new file mode 100644 index 0000000..bc84876 --- /dev/null +++ b/docs/search/all_12.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['value',['Value',['../classtinyxml2_1_1_x_m_l_node.html#a66344989a4b436155bcda72bd6b07b82',1,'tinyxml2::XMLNode::Value()'],['../classtinyxml2_1_1_x_m_l_attribute.html#a1aab1dd0e43ecbcfa306adbcf3a3d853',1,'tinyxml2::XMLAttribute::Value()']]], + ['visit',['Visit',['../classtinyxml2_1_1_x_m_l_visitor.html#adc75bd459fc7ba8223b50f0616767f9a',1,'tinyxml2::XMLVisitor::Visit(const XMLDeclaration &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#af30233565856480ea48b6fa0d6dec65b',1,'tinyxml2::XMLVisitor::Visit(const XMLText &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#acc8147fb5a85f6c65721654e427752d7',1,'tinyxml2::XMLVisitor::Visit(const XMLComment &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#a14e4748387c34bf53d24e8119bb1f292',1,'tinyxml2::XMLVisitor::Visit(const XMLUnknown &)'],['../classtinyxml2_1_1_x_m_l_printer.html#a275ae25544a12199ae40b6994ca6e4de',1,'tinyxml2::XMLPrinter::Visit(const XMLText &text)'],['../classtinyxml2_1_1_x_m_l_printer.html#a3f16a30be1537ac141d9bd2db824ba9e',1,'tinyxml2::XMLPrinter::Visit(const XMLComment &comment)'],['../classtinyxml2_1_1_x_m_l_printer.html#a9ceff5cd85e5db65838962174fcdcc46',1,'tinyxml2::XMLPrinter::Visit(const XMLDeclaration &declaration)'],['../classtinyxml2_1_1_x_m_l_printer.html#aa15e1da81e17dea5da6499ac5b08d9d8',1,'tinyxml2::XMLPrinter::Visit(const XMLUnknown &unknown)']]], + ['visitenter',['VisitEnter',['../classtinyxml2_1_1_x_m_l_visitor.html#acb3c22fc5f60eb9db98f533f2761f67d',1,'tinyxml2::XMLVisitor::VisitEnter(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#af97980a17dd4e37448b181f5ddfa92b5',1,'tinyxml2::XMLVisitor::VisitEnter(const XMLElement &, const XMLAttribute *)'],['../classtinyxml2_1_1_x_m_l_printer.html#ae966b988a7a28c41e91c5ca17fb2054b',1,'tinyxml2::XMLPrinter::VisitEnter(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_printer.html#a2ce2aa508c21ac91615093ddb9c282c5',1,'tinyxml2::XMLPrinter::VisitEnter(const XMLElement &element, const XMLAttribute *attribute)']]], + ['visitexit',['VisitExit',['../classtinyxml2_1_1_x_m_l_visitor.html#a170e9989cd046ba904f302d087e07086',1,'tinyxml2::XMLVisitor::VisitExit(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#a772f10ddc83f881956d32628faa16eb6',1,'tinyxml2::XMLVisitor::VisitExit(const XMLElement &)'],['../classtinyxml2_1_1_x_m_l_printer.html#a15fc1f2b922f540917dcf52808737b29',1,'tinyxml2::XMLPrinter::VisitExit(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_printer.html#ae99e0a7086543591edfb565f24689098',1,'tinyxml2::XMLPrinter::VisitExit(const XMLElement &element)']]] +]; diff --git a/docs/search/all_13.html b/docs/search/all_13.html new file mode 100644 index 0000000..b4a8bca --- /dev/null +++ b/docs/search/all_13.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_13.js b/docs/search/all_13.js new file mode 100644 index 0000000..9c06153 --- /dev/null +++ b/docs/search/all_13.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['xmlattribute',['XMLAttribute',['../classtinyxml2_1_1_x_m_l_attribute.html',1,'tinyxml2']]], + ['xmlcomment',['XMLComment',['../classtinyxml2_1_1_x_m_l_comment.html',1,'tinyxml2']]], + ['xmlconsthandle',['XMLConstHandle',['../classtinyxml2_1_1_x_m_l_const_handle.html',1,'tinyxml2']]], + ['xmldeclaration',['XMLDeclaration',['../classtinyxml2_1_1_x_m_l_declaration.html',1,'tinyxml2']]], + ['xmldocument',['XMLDocument',['../classtinyxml2_1_1_x_m_l_document.html',1,'tinyxml2::XMLDocument'],['../classtinyxml2_1_1_x_m_l_document.html#a57ddf17b6e054dda10af98991b1b8f70',1,'tinyxml2::XMLDocument::XMLDocument()']]], + ['xmlelement',['XMLElement',['../classtinyxml2_1_1_x_m_l_element.html',1,'tinyxml2']]], + ['xmlhandle',['XMLHandle',['../classtinyxml2_1_1_x_m_l_handle.html',1,'tinyxml2::XMLHandle'],['../classtinyxml2_1_1_x_m_l_handle.html#a9c240a35c18f053509b4b97ddccd9793',1,'tinyxml2::XMLHandle::XMLHandle(XMLNode *node)'],['../classtinyxml2_1_1_x_m_l_handle.html#aa2edbc1c0d3e3e8259bd98de7f1cf500',1,'tinyxml2::XMLHandle::XMLHandle(XMLNode &node)'],['../classtinyxml2_1_1_x_m_l_handle.html#afd8e01e6018c07347b8e6d80272466aa',1,'tinyxml2::XMLHandle::XMLHandle(const XMLHandle &ref)']]], + ['xmlnode',['XMLNode',['../classtinyxml2_1_1_x_m_l_node.html',1,'tinyxml2']]], + ['xmlprinter',['XMLPrinter',['../classtinyxml2_1_1_x_m_l_printer.html',1,'tinyxml2::XMLPrinter'],['../classtinyxml2_1_1_x_m_l_printer.html#aa6d3841c069085f5b8a27bc7103c04f7',1,'tinyxml2::XMLPrinter::XMLPrinter()']]], + ['xmltext',['XMLText',['../classtinyxml2_1_1_x_m_l_text.html',1,'tinyxml2']]], + ['xmlunknown',['XMLUnknown',['../classtinyxml2_1_1_x_m_l_unknown.html',1,'tinyxml2']]], + ['xmlvisitor',['XMLVisitor',['../classtinyxml2_1_1_x_m_l_visitor.html',1,'tinyxml2']]] +]; diff --git a/docs/search/all_2.html b/docs/search/all_2.html new file mode 100644 index 0000000..9543c57 --- /dev/null +++ b/docs/search/all_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_2.js b/docs/search/all_2.js new file mode 100644 index 0000000..62ab567 --- /dev/null +++ b/docs/search/all_2.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['cdata',['CData',['../classtinyxml2_1_1_x_m_l_text.html#ac1bb5ea4166c320882d9e0ad16fd385b',1,'tinyxml2::XMLText']]], + ['clear',['Clear',['../classtinyxml2_1_1_x_m_l_document.html#a65656b0b2cbc822708eb351504178aaf',1,'tinyxml2::XMLDocument']]], + ['clearbuffer',['ClearBuffer',['../classtinyxml2_1_1_x_m_l_printer.html#a216157765b7267bf389975b1cbf9a909',1,'tinyxml2::XMLPrinter']]], + ['closeelement',['CloseElement',['../classtinyxml2_1_1_x_m_l_printer.html#ad04d29562b46fcdb23ab320f8b664240',1,'tinyxml2::XMLPrinter']]], + ['cstr',['CStr',['../classtinyxml2_1_1_x_m_l_printer.html#a180671d73844f159f2d4aafbc11d106e',1,'tinyxml2::XMLPrinter']]], + ['cstrsize',['CStrSize',['../classtinyxml2_1_1_x_m_l_printer.html#a3256cf3523d4898b91abb18b924be04c',1,'tinyxml2::XMLPrinter']]] +]; diff --git a/docs/search/all_3.html b/docs/search/all_3.html new file mode 100644 index 0000000..03405c0 --- /dev/null +++ b/docs/search/all_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_3.js b/docs/search/all_3.js new file mode 100644 index 0000000..c24f73b --- /dev/null +++ b/docs/search/all_3.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['deepclone',['DeepClone',['../classtinyxml2_1_1_x_m_l_node.html#a62c71b6bf8734b5424063b8d9a61c266',1,'tinyxml2::XMLNode']]], + ['deepcopy',['DeepCopy',['../classtinyxml2_1_1_x_m_l_document.html#aab792e90adc38cdc5446616573b8b01b',1,'tinyxml2::XMLDocument']]], + ['deleteattribute',['DeleteAttribute',['../classtinyxml2_1_1_x_m_l_element.html#aebd45aa7118964c30b32fe12e944628a',1,'tinyxml2::XMLElement']]], + ['deletechild',['DeleteChild',['../classtinyxml2_1_1_x_m_l_node.html#a363b6edbd6ebd55f8387d2b89f2b0921',1,'tinyxml2::XMLNode']]], + ['deletechildren',['DeleteChildren',['../classtinyxml2_1_1_x_m_l_node.html#a0360085cc54df5bff85d5c5da13afdce',1,'tinyxml2::XMLNode']]], + ['deletenode',['DeleteNode',['../classtinyxml2_1_1_x_m_l_document.html#ac1d6e2c7fcc1a660624ac4f68e96380d',1,'tinyxml2::XMLDocument']]], + ['doubleattribute',['DoubleAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a10a90c505aea716bf073eea1c97f33b5',1,'tinyxml2::XMLElement']]], + ['doubletext',['DoubleText',['../classtinyxml2_1_1_x_m_l_element.html#a81b1ff0cf2f2cd09be8badc08b39a2b7',1,'tinyxml2::XMLElement']]], + ['doublevalue',['DoubleValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a4aa73513f54ff0087d3e804f0f54e30f',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/all_4.html b/docs/search/all_4.html new file mode 100644 index 0000000..8e1f4b9 --- /dev/null +++ b/docs/search/all_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_4.js b/docs/search/all_4.js new file mode 100644 index 0000000..eb6c1f6 --- /dev/null +++ b/docs/search/all_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['error',['Error',['../classtinyxml2_1_1_x_m_l_document.html#a34e6318e182e40e3cc4f4ba5d59ed9ed',1,'tinyxml2::XMLDocument']]], + ['errorid',['ErrorID',['../classtinyxml2_1_1_x_m_l_document.html#afa3ed33b3107f920ec2b301f805ac17d',1,'tinyxml2::XMLDocument']]] +]; diff --git a/docs/search/all_5.html b/docs/search/all_5.html new file mode 100644 index 0000000..89a879e --- /dev/null +++ b/docs/search/all_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_5.js b/docs/search/all_5.js new file mode 100644 index 0000000..182bbfe --- /dev/null +++ b/docs/search/all_5.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['findattribute',['FindAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a2dcd4d5d6fb63396cd2f257c318b42c4',1,'tinyxml2::XMLElement']]], + ['firstattribute',['FirstAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a3e191704c8d499906ec11fe2f60c6686',1,'tinyxml2::XMLElement']]], + ['firstchild',['FirstChild',['../classtinyxml2_1_1_x_m_l_node.html#ae7dc225e1018cdd685f7563593a1fe08',1,'tinyxml2::XMLNode::FirstChild()'],['../classtinyxml2_1_1_x_m_l_handle.html#a536447dc7f54c0cd11e031dad94795ae',1,'tinyxml2::XMLHandle::FirstChild()']]], + ['firstchildelement',['FirstChildElement',['../classtinyxml2_1_1_x_m_l_node.html#a1795a35852dc8aae877cc8ded986e59b',1,'tinyxml2::XMLNode::FirstChildElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a74b04dd0f15e0bf01860e282b840b6a3',1,'tinyxml2::XMLHandle::FirstChildElement()']]], + ['floatattribute',['FloatAttribute',['../classtinyxml2_1_1_x_m_l_element.html#ab1f4be2332e27dc640e9b6abd01d64dd',1,'tinyxml2::XMLElement']]], + ['floattext',['FloatText',['../classtinyxml2_1_1_x_m_l_element.html#a45444eb21f99ca46101545992dc2e927',1,'tinyxml2::XMLElement']]], + ['floatvalue',['FloatValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a27797b45d21c981257720db94f5f8801',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/all_6.html b/docs/search/all_6.html new file mode 100644 index 0000000..6afac06 --- /dev/null +++ b/docs/search/all_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_6.js b/docs/search/all_6.js new file mode 100644 index 0000000..0d5723e --- /dev/null +++ b/docs/search/all_6.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['get_20information_20out_20of_20xml',['Get information out of XML',['../_example-3.html',1,'']]], + ['getdocument',['GetDocument',['../classtinyxml2_1_1_x_m_l_node.html#a2de84cfa4ec3fe249bad745069d145f1',1,'tinyxml2::XMLNode::GetDocument() const'],['../classtinyxml2_1_1_x_m_l_node.html#af343d1ef0b45c0020e62d784d7e67a68',1,'tinyxml2::XMLNode::GetDocument()']]], + ['geterrorlinenum',['GetErrorLineNum',['../classtinyxml2_1_1_x_m_l_document.html#ad82d07e43e096e834dbdfd06312398c1',1,'tinyxml2::XMLDocument']]], + ['geterrorstr1',['GetErrorStr1',['../classtinyxml2_1_1_x_m_l_document.html#a229494e30e5473237f3fa547eee4c43f',1,'tinyxml2::XMLDocument']]], + ['geterrorstr2',['GetErrorStr2',['../classtinyxml2_1_1_x_m_l_document.html#a2d952f49c761bffd2903250680a8716b',1,'tinyxml2::XMLDocument']]], + ['getlinenum',['GetLineNum',['../classtinyxml2_1_1_x_m_l_node.html#a9b5fc636646fda761d342c72e91cb286',1,'tinyxml2::XMLNode::GetLineNum()'],['../classtinyxml2_1_1_x_m_l_attribute.html#a02d5ea924586e35f9c13857d1671b765',1,'tinyxml2::XMLAttribute::GetLineNum()']]], + ['gettext',['GetText',['../classtinyxml2_1_1_x_m_l_element.html#a6d5c8d115561ade4e4456b71d91b6f51',1,'tinyxml2::XMLElement']]], + ['getuserdata',['GetUserData',['../classtinyxml2_1_1_x_m_l_node.html#a7f0687574afa03bc479dc44f29db0afe',1,'tinyxml2::XMLNode']]] +]; diff --git a/docs/search/all_7.html b/docs/search/all_7.html new file mode 100644 index 0000000..de19107 --- /dev/null +++ b/docs/search/all_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_7.js b/docs/search/all_7.js new file mode 100644 index 0000000..b7d6d1f --- /dev/null +++ b/docs/search/all_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['hasbom',['HasBOM',['../classtinyxml2_1_1_x_m_l_document.html#a33fc5d159db873a179fa26338adb05bd',1,'tinyxml2::XMLDocument']]] +]; diff --git a/docs/search/all_8.html b/docs/search/all_8.html new file mode 100644 index 0000000..11e27cd --- /dev/null +++ b/docs/search/all_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_8.js b/docs/search/all_8.js new file mode 100644 index 0000000..b1519d5 --- /dev/null +++ b/docs/search/all_8.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['insertafterchild',['InsertAfterChild',['../classtinyxml2_1_1_x_m_l_node.html#a85adb8f0b7477eec30f9a41d420b09c2',1,'tinyxml2::XMLNode']]], + ['insertendchild',['InsertEndChild',['../classtinyxml2_1_1_x_m_l_node.html#aeb249ed60f4e8bfad3709151c3ee4286',1,'tinyxml2::XMLNode']]], + ['insertfirstchild',['InsertFirstChild',['../classtinyxml2_1_1_x_m_l_node.html#a8ff7dc071f3a1a6ae2ac25a37492865d',1,'tinyxml2::XMLNode']]], + ['int64attribute',['Int64Attribute',['../classtinyxml2_1_1_x_m_l_element.html#a66d96972adecd816194191f13cc4a0a0',1,'tinyxml2::XMLElement']]], + ['int64text',['Int64Text',['../classtinyxml2_1_1_x_m_l_element.html#aab6151f7e3b4c2c0a8234e262d7b6b8a',1,'tinyxml2::XMLElement']]], + ['intattribute',['IntAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a95a89b13bb14a2d4655e2b5b406c00d4',1,'tinyxml2::XMLElement']]], + ['intvalue',['IntValue',['../classtinyxml2_1_1_x_m_l_attribute.html#adfa2433f0fdafd5c3880936de9affa80',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/all_9.html b/docs/search/all_9.html new file mode 100644 index 0000000..f8abbbe --- /dev/null +++ b/docs/search/all_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_9.js b/docs/search/all_9.js new file mode 100644 index 0000000..1b64fe0 --- /dev/null +++ b/docs/search/all_9.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['load_20an_20xml_20file',['Load an XML File',['../_example-1.html',1,'']]], + ['lastchild',['LastChild',['../classtinyxml2_1_1_x_m_l_node.html#a9b8583a277e8e26f4cbbb5492786778e',1,'tinyxml2::XMLNode::LastChild()'],['../classtinyxml2_1_1_x_m_l_handle.html#a9d09f04435f0f2f7d0816b0198d0517b',1,'tinyxml2::XMLHandle::LastChild()']]], + ['lastchildelement',['LastChildElement',['../classtinyxml2_1_1_x_m_l_node.html#a173e9d1341bc56992e2d320a35936551',1,'tinyxml2::XMLNode::LastChildElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a42cccd0ce8b1ce704f431025e9f19e0c',1,'tinyxml2::XMLHandle::LastChildElement()']]], + ['loadfile',['LoadFile',['../classtinyxml2_1_1_x_m_l_document.html#a2ebd4647a8af5fc6831b294ac26a150a',1,'tinyxml2::XMLDocument::LoadFile(const char *filename)'],['../classtinyxml2_1_1_x_m_l_document.html#a5f1d330fad44c52f3d265338dd2a6dc2',1,'tinyxml2::XMLDocument::LoadFile(FILE *)']]] +]; diff --git a/docs/search/all_a.html b/docs/search/all_a.html new file mode 100644 index 0000000..9601fce --- /dev/null +++ b/docs/search/all_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_a.js b/docs/search/all_a.js new file mode 100644 index 0000000..953470a --- /dev/null +++ b/docs/search/all_a.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['name',['Name',['../classtinyxml2_1_1_x_m_l_attribute.html#ab886c486ec19f02ed826f8dc129e5ad8',1,'tinyxml2::XMLAttribute::Name()'],['../classtinyxml2_1_1_x_m_l_element.html#a63e057fb5baee1dd29f323cb85907b35',1,'tinyxml2::XMLElement::Name()']]], + ['newcomment',['NewComment',['../classtinyxml2_1_1_x_m_l_document.html#ade4874bcb439954972ef2b3723ff3259',1,'tinyxml2::XMLDocument']]], + ['newdeclaration',['NewDeclaration',['../classtinyxml2_1_1_x_m_l_document.html#aee2eb3435923f5494dcc70ac225b60a2',1,'tinyxml2::XMLDocument']]], + ['newelement',['NewElement',['../classtinyxml2_1_1_x_m_l_document.html#a8aa7817d4a1001364b06373763ab99d6',1,'tinyxml2::XMLDocument']]], + ['newtext',['NewText',['../classtinyxml2_1_1_x_m_l_document.html#ab7e8b29ae4099092a8bb947da6361296',1,'tinyxml2::XMLDocument']]], + ['newunknown',['NewUnknown',['../classtinyxml2_1_1_x_m_l_document.html#a5385c937734ff6db9226ab707d2c7147',1,'tinyxml2::XMLDocument']]], + ['next',['Next',['../classtinyxml2_1_1_x_m_l_attribute.html#aee53571b21e7ce5421eb929523a8bbe6',1,'tinyxml2::XMLAttribute']]], + ['nextsibling',['NextSibling',['../classtinyxml2_1_1_x_m_l_node.html#a79db9ef0fe014d27790f2218b87bcbb5',1,'tinyxml2::XMLNode::NextSibling()'],['../classtinyxml2_1_1_x_m_l_handle.html#aad2eccc7c7c7b18145877c978c3850b5',1,'tinyxml2::XMLHandle::NextSibling()']]], + ['nextsiblingelement',['NextSiblingElement',['../classtinyxml2_1_1_x_m_l_node.html#a1264c86233328f0cd36297552d982f80',1,'tinyxml2::XMLNode::NextSiblingElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#ae41d88ee061f3c49a081630ff753b2c5',1,'tinyxml2::XMLHandle::NextSiblingElement()']]], + ['nochildren',['NoChildren',['../classtinyxml2_1_1_x_m_l_node.html#ac3ab489e6e202a3cd1762d3b332e89d4',1,'tinyxml2::XMLNode']]] +]; diff --git a/docs/search/all_b.html b/docs/search/all_b.html new file mode 100644 index 0000000..0814e4e --- /dev/null +++ b/docs/search/all_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_b.js b/docs/search/all_b.js new file mode 100644 index 0000000..9772c30 --- /dev/null +++ b/docs/search/all_b.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['openelement',['OpenElement',['../classtinyxml2_1_1_x_m_l_printer.html#a20fb06c83bd13e5140d7dd13af06c010',1,'tinyxml2::XMLPrinter']]], + ['operator_3d',['operator=',['../classtinyxml2_1_1_x_m_l_handle.html#a75b908322bb4b83be3281b6845252b20',1,'tinyxml2::XMLHandle']]] +]; diff --git a/docs/search/all_c.html b/docs/search/all_c.html new file mode 100644 index 0000000..da08c38 --- /dev/null +++ b/docs/search/all_c.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_c.js b/docs/search/all_c.js new file mode 100644 index 0000000..7d117f6 --- /dev/null +++ b/docs/search/all_c.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['parse_20an_20xml_20from_20char_20buffer',['Parse an XML from char buffer',['../_example-2.html',1,'']]], + ['parent',['Parent',['../classtinyxml2_1_1_x_m_l_node.html#ae0f62bc186c56c2e0483ebd52dbfbe34',1,'tinyxml2::XMLNode']]], + ['parse',['Parse',['../classtinyxml2_1_1_x_m_l_document.html#a1819bd34f540a7304c105a6232d25a1f',1,'tinyxml2::XMLDocument']]], + ['previoussibling',['PreviousSibling',['../classtinyxml2_1_1_x_m_l_node.html#aac667c513d445f8b783e1e15ef9d3551',1,'tinyxml2::XMLNode::PreviousSibling()'],['../classtinyxml2_1_1_x_m_l_handle.html#a428374e756f4db4cbc287fec64eae02c',1,'tinyxml2::XMLHandle::PreviousSibling()']]], + ['previoussiblingelement',['PreviousSiblingElement',['../classtinyxml2_1_1_x_m_l_node.html#a872936cae46fb473eb47fec99129fc70',1,'tinyxml2::XMLNode::PreviousSiblingElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a786957e498039554ed334cdc36612a7e',1,'tinyxml2::XMLHandle::PreviousSiblingElement()']]], + ['print',['Print',['../classtinyxml2_1_1_x_m_l_document.html#a867cf5fa3e3ff6ae4847a8b7ee8ec083',1,'tinyxml2::XMLDocument']]], + ['printerror',['PrintError',['../classtinyxml2_1_1_x_m_l_document.html#a1d033945b42e125d933d6231e4571552',1,'tinyxml2::XMLDocument']]], + ['printspace',['PrintSpace',['../classtinyxml2_1_1_x_m_l_printer.html#a01148e2ebe6776e38c5a3e41bc5feb74',1,'tinyxml2::XMLPrinter']]], + ['pushattribute',['PushAttribute',['../classtinyxml2_1_1_x_m_l_printer.html#a9a4e2c9348b42e147629d5a99f4af3f0',1,'tinyxml2::XMLPrinter']]], + ['pushcomment',['PushComment',['../classtinyxml2_1_1_x_m_l_printer.html#afc8416814219591c2fd5656e0c233140',1,'tinyxml2::XMLPrinter']]], + ['pushheader',['PushHeader',['../classtinyxml2_1_1_x_m_l_printer.html#a178c608ce8476043d5d6513819cde903',1,'tinyxml2::XMLPrinter']]], + ['pushtext',['PushText',['../classtinyxml2_1_1_x_m_l_printer.html#a1cc16a9362df4332012cb13cff6441b3',1,'tinyxml2::XMLPrinter::PushText(const char *text, bool cdata=false)'],['../classtinyxml2_1_1_x_m_l_printer.html#a3e0d4d78de25d4cf081009e1431cea7e',1,'tinyxml2::XMLPrinter::PushText(int value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a661fb50e7e0a4918d2d259cb0fae647e',1,'tinyxml2::XMLPrinter::PushText(unsigned value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a96b0a0bfe105154a0a6c37d725258f0a',1,'tinyxml2::XMLPrinter::PushText(int64_t value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a4390e5fa1ed05189a8686647345ab29f',1,'tinyxml2::XMLPrinter::PushText(bool value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a1dbb1390e829d0673af66b9cd1928bd7',1,'tinyxml2::XMLPrinter::PushText(float value)'],['../classtinyxml2_1_1_x_m_l_printer.html#aa715302dfc09473c77c853cbd5431965',1,'tinyxml2::XMLPrinter::PushText(double value)']]] +]; diff --git a/docs/search/all_d.html b/docs/search/all_d.html new file mode 100644 index 0000000..9986c9c --- /dev/null +++ b/docs/search/all_d.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_d.js b/docs/search/all_d.js new file mode 100644 index 0000000..b78f218 --- /dev/null +++ b/docs/search/all_d.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['queryattribute',['QueryAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a042fc30504347b84a56cf863ad528a4f',1,'tinyxml2::XMLElement']]], + ['queryboolattribute',['QueryBoolAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a14c1bb77c39689838be01838d86ca872',1,'tinyxml2::XMLElement']]], + ['querybooltext',['QueryBoolText',['../classtinyxml2_1_1_x_m_l_element.html#a3fe5417d59eb8f5c4afe924b7d332736',1,'tinyxml2::XMLElement']]], + ['queryboolvalue',['QueryBoolValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a5f32e038954256f61c21ff20fd13a09c',1,'tinyxml2::XMLAttribute']]], + ['querydoubleattribute',['QueryDoubleAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a5f0964e2dbd8e2ee7fce9beab689443c',1,'tinyxml2::XMLElement']]], + ['querydoubletext',['QueryDoubleText',['../classtinyxml2_1_1_x_m_l_element.html#a684679c99bb036a25652744cec6c4d96',1,'tinyxml2::XMLElement']]], + ['querydoublevalue',['QueryDoubleValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a2aa6e55e8ea03af0609cf6690bff79b9',1,'tinyxml2::XMLAttribute']]], + ['queryfloatattribute',['QueryFloatAttribute',['../classtinyxml2_1_1_x_m_l_element.html#acd5eeddf6002ef90806af794b9d9a5a5',1,'tinyxml2::XMLElement']]], + ['queryfloattext',['QueryFloatText',['../classtinyxml2_1_1_x_m_l_element.html#afa332afedd93210daa6d44b88eb11e29',1,'tinyxml2::XMLElement']]], + ['queryfloatvalue',['QueryFloatValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a049dea6449a6259b6cfed44a9427b607',1,'tinyxml2::XMLAttribute']]], + ['queryint64attribute',['QueryInt64Attribute',['../classtinyxml2_1_1_x_m_l_element.html#a7c0955d80b6f8d196744eacb0f6e90a8',1,'tinyxml2::XMLElement']]], + ['queryint64text',['QueryInt64Text',['../classtinyxml2_1_1_x_m_l_element.html#a120c538c8eead169e635dbc70fb226d8',1,'tinyxml2::XMLElement']]], + ['queryint64value',['QueryInt64Value',['../classtinyxml2_1_1_x_m_l_attribute.html#a4e25344d6e4159026be34dbddf1dcac2',1,'tinyxml2::XMLAttribute']]], + ['queryintattribute',['QueryIntAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a8a78bc1187c1c45ad89f2690eab567b1',1,'tinyxml2::XMLElement']]], + ['queryinttext',['QueryIntText',['../classtinyxml2_1_1_x_m_l_element.html#a926357996bef633cb736e1a558419632',1,'tinyxml2::XMLElement']]], + ['queryintvalue',['QueryIntValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a6d5176260db00ea301c01af8457cd993',1,'tinyxml2::XMLAttribute']]], + ['queryunsignedattribute',['QueryUnsignedAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a26fc84cbfba6769dafcfbf256c05e22f',1,'tinyxml2::XMLElement']]], + ['queryunsignedtext',['QueryUnsignedText',['../classtinyxml2_1_1_x_m_l_element.html#a14d38aa4b5e18a46274a27425188a6a1',1,'tinyxml2::XMLElement']]], + ['queryunsignedvalue',['QueryUnsignedValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a48a7f3496f1415832e451bd8d09c9cb9',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/all_e.html b/docs/search/all_e.html new file mode 100644 index 0000000..9fa42bb --- /dev/null +++ b/docs/search/all_e.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_e.js b/docs/search/all_e.js new file mode 100644 index 0000000..a327229 --- /dev/null +++ b/docs/search/all_e.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['read_20attributes_20and_20text_20information_2e',['Read attributes and text information.',['../_example-4.html',1,'']]], + ['rootelement',['RootElement',['../classtinyxml2_1_1_x_m_l_document.html#ad2b70320d3c2a071c2f36928edff3e1c',1,'tinyxml2::XMLDocument']]] +]; diff --git a/docs/search/all_f.html b/docs/search/all_f.html new file mode 100644 index 0000000..6ecfc0e --- /dev/null +++ b/docs/search/all_f.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/all_f.js b/docs/search/all_f.js new file mode 100644 index 0000000..be8e75d --- /dev/null +++ b/docs/search/all_f.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['savefile',['SaveFile',['../classtinyxml2_1_1_x_m_l_document.html#a73ac416b4a2aa0952e841220eb3da18f',1,'tinyxml2::XMLDocument::SaveFile(const char *filename, bool compact=false)'],['../classtinyxml2_1_1_x_m_l_document.html#a8b95779479a0035acc67b3a61dfe1b74',1,'tinyxml2::XMLDocument::SaveFile(FILE *fp, bool compact=false)']]], + ['setattribute',['SetAttribute',['../classtinyxml2_1_1_x_m_l_attribute.html#a406d2c4a13c7af99a65edb59dd9f7581',1,'tinyxml2::XMLAttribute::SetAttribute(const char *value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ad86d7d7058d76761c3a80662566a57e5',1,'tinyxml2::XMLAttribute::SetAttribute(int value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ae70468c0f6df2748ba3529c716999fae',1,'tinyxml2::XMLAttribute::SetAttribute(unsigned value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#a7c1240f479722b9aa29b6c030aa116c2',1,'tinyxml2::XMLAttribute::SetAttribute(int64_t value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ab3516def4fe058fe328f2b89fc2d77da',1,'tinyxml2::XMLAttribute::SetAttribute(bool value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#a9a65ab3147abe8ccbbd373ce8791e818',1,'tinyxml2::XMLAttribute::SetAttribute(double value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ae95e843313aaf5d56c32530b6456df02',1,'tinyxml2::XMLAttribute::SetAttribute(float value)'],['../classtinyxml2_1_1_x_m_l_element.html#a11943abf2d0831548c3790dd5d9f119c',1,'tinyxml2::XMLElement::SetAttribute(const char *name, const char *value)'],['../classtinyxml2_1_1_x_m_l_element.html#aae6568c64c7f1cc88be8461ba41a79cf',1,'tinyxml2::XMLElement::SetAttribute(const char *name, int value)'],['../classtinyxml2_1_1_x_m_l_element.html#ae143997e90064ba82326b29a9930ea8f',1,'tinyxml2::XMLElement::SetAttribute(const char *name, unsigned value)'],['../classtinyxml2_1_1_x_m_l_element.html#aaeefdf9171fec91b13a776b42299b0dd',1,'tinyxml2::XMLElement::SetAttribute(const char *name, int64_t value)'],['../classtinyxml2_1_1_x_m_l_element.html#aa848b696e6a75e4e545c6da9893b11e1',1,'tinyxml2::XMLElement::SetAttribute(const char *name, bool value)'],['../classtinyxml2_1_1_x_m_l_element.html#a233397ee81e70eb5d4b814c5f8698533',1,'tinyxml2::XMLElement::SetAttribute(const char *name, double value)'],['../classtinyxml2_1_1_x_m_l_element.html#a554b70d882e65b28fc084b23df9b9759',1,'tinyxml2::XMLElement::SetAttribute(const char *name, float value)']]], + ['setbom',['SetBOM',['../classtinyxml2_1_1_x_m_l_document.html#a14419b698f7c4b140df4e80f3f0c93b0',1,'tinyxml2::XMLDocument']]], + ['setcdata',['SetCData',['../classtinyxml2_1_1_x_m_l_text.html#ad080357d76ab7cc59d7651249949329d',1,'tinyxml2::XMLText']]], + ['setname',['SetName',['../classtinyxml2_1_1_x_m_l_element.html#a97712009a530d8cb8a63bf705f02b4f1',1,'tinyxml2::XMLElement']]], + ['settext',['SetText',['../classtinyxml2_1_1_x_m_l_element.html#a1f9c2cd61b72af5ae708d37b7ad283ce',1,'tinyxml2::XMLElement::SetText(const char *inText)'],['../classtinyxml2_1_1_x_m_l_element.html#aeae8917b5ea6060b3c08d4e3d8d632d7',1,'tinyxml2::XMLElement::SetText(int value)'],['../classtinyxml2_1_1_x_m_l_element.html#a7bbfcc11d516598bc924a8fba4d08597',1,'tinyxml2::XMLElement::SetText(unsigned value)'],['../classtinyxml2_1_1_x_m_l_element.html#a7b62cd33acdfeff7ea2b1b330d4368e4',1,'tinyxml2::XMLElement::SetText(int64_t value)'],['../classtinyxml2_1_1_x_m_l_element.html#ae4b543d6770de76fb6ab68e541c192a4',1,'tinyxml2::XMLElement::SetText(bool value)'],['../classtinyxml2_1_1_x_m_l_element.html#a67bd77ac9aaeff58ff20b4275a65ba4e',1,'tinyxml2::XMLElement::SetText(double value)'],['../classtinyxml2_1_1_x_m_l_element.html#a51d560da5ae3ad6b75e0ab9ffb2ae42a',1,'tinyxml2::XMLElement::SetText(float value)']]], + ['setuserdata',['SetUserData',['../classtinyxml2_1_1_x_m_l_node.html#a002978fc889cc011d143185f2377eca2',1,'tinyxml2::XMLNode']]], + ['setvalue',['SetValue',['../classtinyxml2_1_1_x_m_l_node.html#a09dd68cf9eae137579f6e50f36487513',1,'tinyxml2::XMLNode']]], + ['shallowclone',['ShallowClone',['../classtinyxml2_1_1_x_m_l_node.html#a8402cbd3129d20e9e6024bbcc0531283',1,'tinyxml2::XMLNode::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_text.html#af3a81ed4dd49d5151c477b3f265a3011',1,'tinyxml2::XMLText::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_comment.html#a08991cc63fadf7e95078ac4f9ea1b073',1,'tinyxml2::XMLComment::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_declaration.html#a118d47518dd9e522644e42efa259aed7',1,'tinyxml2::XMLDeclaration::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_unknown.html#a0125f41c89763dea06619b5fd5246b4c',1,'tinyxml2::XMLUnknown::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_element.html#ac035742d68b0c50c3f676374e59fe750',1,'tinyxml2::XMLElement::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_document.html#aa37cc1709d7e1e988bc17dcfb24a69b8',1,'tinyxml2::XMLDocument::ShallowClone()']]], + ['shallowequal',['ShallowEqual',['../classtinyxml2_1_1_x_m_l_node.html#a7ce18b751c3ea09eac292dca264f9226',1,'tinyxml2::XMLNode::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_text.html#ae0fff8a24e2de7eb073fd192e9db0331',1,'tinyxml2::XMLText::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_comment.html#a6f7d227b25afa8cc3c763b7cc8833739',1,'tinyxml2::XMLComment::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_declaration.html#aa26b70011694e9b9e9480b929e9b78d6',1,'tinyxml2::XMLDeclaration::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_unknown.html#a0715ab2c05d7f74845c188122213b116',1,'tinyxml2::XMLUnknown::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_element.html#ad9ea913a460b48979bd83cf9871c99f6',1,'tinyxml2::XMLElement::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_document.html#a6fe5ef18699091844fcf64b56ffa5bf9',1,'tinyxml2::XMLDocument::ShallowEqual()']]] +]; diff --git a/docs/search/classes_0.html b/docs/search/classes_0.html new file mode 100644 index 0000000..1c3e406 --- /dev/null +++ b/docs/search/classes_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/classes_0.js b/docs/search/classes_0.js new file mode 100644 index 0000000..e1d0d44 --- /dev/null +++ b/docs/search/classes_0.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['xmlattribute',['XMLAttribute',['../classtinyxml2_1_1_x_m_l_attribute.html',1,'tinyxml2']]], + ['xmlcomment',['XMLComment',['../classtinyxml2_1_1_x_m_l_comment.html',1,'tinyxml2']]], + ['xmlconsthandle',['XMLConstHandle',['../classtinyxml2_1_1_x_m_l_const_handle.html',1,'tinyxml2']]], + ['xmldeclaration',['XMLDeclaration',['../classtinyxml2_1_1_x_m_l_declaration.html',1,'tinyxml2']]], + ['xmldocument',['XMLDocument',['../classtinyxml2_1_1_x_m_l_document.html',1,'tinyxml2']]], + ['xmlelement',['XMLElement',['../classtinyxml2_1_1_x_m_l_element.html',1,'tinyxml2']]], + ['xmlhandle',['XMLHandle',['../classtinyxml2_1_1_x_m_l_handle.html',1,'tinyxml2']]], + ['xmlnode',['XMLNode',['../classtinyxml2_1_1_x_m_l_node.html',1,'tinyxml2']]], + ['xmlprinter',['XMLPrinter',['../classtinyxml2_1_1_x_m_l_printer.html',1,'tinyxml2']]], + ['xmltext',['XMLText',['../classtinyxml2_1_1_x_m_l_text.html',1,'tinyxml2']]], + ['xmlunknown',['XMLUnknown',['../classtinyxml2_1_1_x_m_l_unknown.html',1,'tinyxml2']]], + ['xmlvisitor',['XMLVisitor',['../classtinyxml2_1_1_x_m_l_visitor.html',1,'tinyxml2']]] +]; diff --git a/docs/search/close.png b/docs/search/close.png new file mode 100644 index 0000000000000000000000000000000000000000..9342d3dfeea7b7c4ee610987e717804b5a42ceb9 GIT binary patch literal 273 zcmV+s0q*{ZP)4(RlMby96)VwnbG{ zbe&}^BDn7x>$<{ck4zAK-=nT;=hHG)kmplIF${xqm8db3oX6wT3bvp`TE@m0cg;b) zBuSL}5?N7O(iZLdAlz@)b)Rd~DnSsSX&P5qC`XwuFwcAYLC+d2>+1(8on;wpt8QIC X2MT$R4iQDd00000NkvXXu0mjfia~GN literal 0 HcmV?d00001 diff --git a/docs/search/functions_0.html b/docs/search/functions_0.html new file mode 100644 index 0000000..4e6d87d --- /dev/null +++ b/docs/search/functions_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js new file mode 100644 index 0000000..28cfce2 --- /dev/null +++ b/docs/search/functions_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['accept',['Accept',['../classtinyxml2_1_1_x_m_l_node.html#a81e66df0a44c67a7af17f3b77a152785',1,'tinyxml2::XMLNode::Accept()'],['../classtinyxml2_1_1_x_m_l_text.html#a1b2c1448f1a21299d0a7913f18b55206',1,'tinyxml2::XMLText::Accept()'],['../classtinyxml2_1_1_x_m_l_comment.html#a4a33dc32fae0285b03f9cfcb3e43e122',1,'tinyxml2::XMLComment::Accept()'],['../classtinyxml2_1_1_x_m_l_declaration.html#a5f376019fb34752eb248548f42f32045',1,'tinyxml2::XMLDeclaration::Accept()'],['../classtinyxml2_1_1_x_m_l_unknown.html#a70983aa1b1cff3d3aa6d4d0a80e5ee48',1,'tinyxml2::XMLUnknown::Accept()'],['../classtinyxml2_1_1_x_m_l_element.html#a3ea8a40e788fb9ad876c28a32932c6d5',1,'tinyxml2::XMLElement::Accept()'],['../classtinyxml2_1_1_x_m_l_document.html#a9efa54f7ecb37c17ab1fa2b3078ccca1',1,'tinyxml2::XMLDocument::Accept()']]], + ['attribute',['Attribute',['../classtinyxml2_1_1_x_m_l_element.html#a70e49ed60b11212ae35f7e354cfe1de9',1,'tinyxml2::XMLElement']]] +]; diff --git a/docs/search/functions_1.html b/docs/search/functions_1.html new file mode 100644 index 0000000..b343e2d --- /dev/null +++ b/docs/search/functions_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_1.js b/docs/search/functions_1.js new file mode 100644 index 0000000..2f5497b --- /dev/null +++ b/docs/search/functions_1.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['boolattribute',['BoolAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a53eda26131e1ad1031ef8ec8adb51bd8',1,'tinyxml2::XMLElement']]], + ['booltext',['BoolText',['../classtinyxml2_1_1_x_m_l_element.html#a68569f59f6382bcea7f5013ec59736d2',1,'tinyxml2::XMLElement']]], + ['boolvalue',['BoolValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a98ce5207344ad33a265b0422addae1ff',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/functions_10.html b/docs/search/functions_10.html new file mode 100644 index 0000000..72bc1ea --- /dev/null +++ b/docs/search/functions_10.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_10.js b/docs/search/functions_10.js new file mode 100644 index 0000000..b5500db --- /dev/null +++ b/docs/search/functions_10.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['tocomment',['ToComment',['../classtinyxml2_1_1_x_m_l_node.html#aff47671055aa99840a1c1ebd661e63e3',1,'tinyxml2::XMLNode::ToComment()'],['../classtinyxml2_1_1_x_m_l_comment.html#a8093e1dc8a34fa446d9dc3fde0e6c0ee',1,'tinyxml2::XMLComment::ToComment()']]], + ['todeclaration',['ToDeclaration',['../classtinyxml2_1_1_x_m_l_node.html#a174fd4c22c010b58138c1b84a0dfbd51',1,'tinyxml2::XMLNode::ToDeclaration()'],['../classtinyxml2_1_1_x_m_l_declaration.html#a159d8ac45865215e88059ea1e5b52fc5',1,'tinyxml2::XMLDeclaration::ToDeclaration()'],['../classtinyxml2_1_1_x_m_l_handle.html#a108858be7ee3eb53f73b5194c1aa8ff0',1,'tinyxml2::XMLHandle::ToDeclaration()']]], + ['todocument',['ToDocument',['../classtinyxml2_1_1_x_m_l_node.html#a836e2966ed736fc3c94f70e12a2a3357',1,'tinyxml2::XMLNode::ToDocument()'],['../classtinyxml2_1_1_x_m_l_document.html#a3e185f880882bd978367bb55937735ec',1,'tinyxml2::XMLDocument::ToDocument()']]], + ['toelement',['ToElement',['../classtinyxml2_1_1_x_m_l_node.html#aab516e699567f75cc9ab2ef2eee501e8',1,'tinyxml2::XMLNode::ToElement()'],['../classtinyxml2_1_1_x_m_l_element.html#ad9ff5c2dbc15df36cf664ce1b0ea0a5d',1,'tinyxml2::XMLElement::ToElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a5e73ed8f3f6f9619d5a8bb1862c47d99',1,'tinyxml2::XMLHandle::ToElement()']]], + ['tonode',['ToNode',['../classtinyxml2_1_1_x_m_l_handle.html#a03ea6ec970a021b71bf1219a0f6717df',1,'tinyxml2::XMLHandle']]], + ['totext',['ToText',['../classtinyxml2_1_1_x_m_l_node.html#a41c55dab9162d1eb62db2008430e376b',1,'tinyxml2::XMLNode::ToText()'],['../classtinyxml2_1_1_x_m_l_text.html#ab1213b4ddebe9b17ec7e7040e9f1caf7',1,'tinyxml2::XMLText::ToText()'],['../classtinyxml2_1_1_x_m_l_handle.html#a6ab9e8cbfb41417246e5657e3842c62a',1,'tinyxml2::XMLHandle::ToText()']]], + ['tounknown',['ToUnknown',['../classtinyxml2_1_1_x_m_l_node.html#a8675a74aa0ada6eccab0c77ef3e5b9bd',1,'tinyxml2::XMLNode::ToUnknown()'],['../classtinyxml2_1_1_x_m_l_unknown.html#af4374856421921cad578c8affae872b6',1,'tinyxml2::XMLUnknown::ToUnknown()'],['../classtinyxml2_1_1_x_m_l_handle.html#aa387368a1ad8d843a9f12df863d298de',1,'tinyxml2::XMLHandle::ToUnknown()']]] +]; diff --git a/docs/search/functions_11.html b/docs/search/functions_11.html new file mode 100644 index 0000000..6948a61 --- /dev/null +++ b/docs/search/functions_11.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_11.js b/docs/search/functions_11.js new file mode 100644 index 0000000..7e35c72 --- /dev/null +++ b/docs/search/functions_11.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['unsignedattribute',['UnsignedAttribute',['../classtinyxml2_1_1_x_m_l_element.html#afea43a1d4aa33e3703ddee5fc9adc26c',1,'tinyxml2::XMLElement']]], + ['unsignedtext',['UnsignedText',['../classtinyxml2_1_1_x_m_l_element.html#a49bad014ffcc17b0b6119d5b2c97dfb5',1,'tinyxml2::XMLElement']]], + ['unsignedvalue',['UnsignedValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a0be5343b08a957c42c02c5d32c35d338',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/functions_12.html b/docs/search/functions_12.html new file mode 100644 index 0000000..3df8489 --- /dev/null +++ b/docs/search/functions_12.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_12.js b/docs/search/functions_12.js new file mode 100644 index 0000000..bc84876 --- /dev/null +++ b/docs/search/functions_12.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['value',['Value',['../classtinyxml2_1_1_x_m_l_node.html#a66344989a4b436155bcda72bd6b07b82',1,'tinyxml2::XMLNode::Value()'],['../classtinyxml2_1_1_x_m_l_attribute.html#a1aab1dd0e43ecbcfa306adbcf3a3d853',1,'tinyxml2::XMLAttribute::Value()']]], + ['visit',['Visit',['../classtinyxml2_1_1_x_m_l_visitor.html#adc75bd459fc7ba8223b50f0616767f9a',1,'tinyxml2::XMLVisitor::Visit(const XMLDeclaration &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#af30233565856480ea48b6fa0d6dec65b',1,'tinyxml2::XMLVisitor::Visit(const XMLText &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#acc8147fb5a85f6c65721654e427752d7',1,'tinyxml2::XMLVisitor::Visit(const XMLComment &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#a14e4748387c34bf53d24e8119bb1f292',1,'tinyxml2::XMLVisitor::Visit(const XMLUnknown &)'],['../classtinyxml2_1_1_x_m_l_printer.html#a275ae25544a12199ae40b6994ca6e4de',1,'tinyxml2::XMLPrinter::Visit(const XMLText &text)'],['../classtinyxml2_1_1_x_m_l_printer.html#a3f16a30be1537ac141d9bd2db824ba9e',1,'tinyxml2::XMLPrinter::Visit(const XMLComment &comment)'],['../classtinyxml2_1_1_x_m_l_printer.html#a9ceff5cd85e5db65838962174fcdcc46',1,'tinyxml2::XMLPrinter::Visit(const XMLDeclaration &declaration)'],['../classtinyxml2_1_1_x_m_l_printer.html#aa15e1da81e17dea5da6499ac5b08d9d8',1,'tinyxml2::XMLPrinter::Visit(const XMLUnknown &unknown)']]], + ['visitenter',['VisitEnter',['../classtinyxml2_1_1_x_m_l_visitor.html#acb3c22fc5f60eb9db98f533f2761f67d',1,'tinyxml2::XMLVisitor::VisitEnter(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#af97980a17dd4e37448b181f5ddfa92b5',1,'tinyxml2::XMLVisitor::VisitEnter(const XMLElement &, const XMLAttribute *)'],['../classtinyxml2_1_1_x_m_l_printer.html#ae966b988a7a28c41e91c5ca17fb2054b',1,'tinyxml2::XMLPrinter::VisitEnter(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_printer.html#a2ce2aa508c21ac91615093ddb9c282c5',1,'tinyxml2::XMLPrinter::VisitEnter(const XMLElement &element, const XMLAttribute *attribute)']]], + ['visitexit',['VisitExit',['../classtinyxml2_1_1_x_m_l_visitor.html#a170e9989cd046ba904f302d087e07086',1,'tinyxml2::XMLVisitor::VisitExit(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_visitor.html#a772f10ddc83f881956d32628faa16eb6',1,'tinyxml2::XMLVisitor::VisitExit(const XMLElement &)'],['../classtinyxml2_1_1_x_m_l_printer.html#a15fc1f2b922f540917dcf52808737b29',1,'tinyxml2::XMLPrinter::VisitExit(const XMLDocument &)'],['../classtinyxml2_1_1_x_m_l_printer.html#ae99e0a7086543591edfb565f24689098',1,'tinyxml2::XMLPrinter::VisitExit(const XMLElement &element)']]] +]; diff --git a/docs/search/functions_13.html b/docs/search/functions_13.html new file mode 100644 index 0000000..febf8e0 --- /dev/null +++ b/docs/search/functions_13.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_13.js b/docs/search/functions_13.js new file mode 100644 index 0000000..3c26364 --- /dev/null +++ b/docs/search/functions_13.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['xmldocument',['XMLDocument',['../classtinyxml2_1_1_x_m_l_document.html#a57ddf17b6e054dda10af98991b1b8f70',1,'tinyxml2::XMLDocument']]], + ['xmlhandle',['XMLHandle',['../classtinyxml2_1_1_x_m_l_handle.html#a9c240a35c18f053509b4b97ddccd9793',1,'tinyxml2::XMLHandle::XMLHandle(XMLNode *node)'],['../classtinyxml2_1_1_x_m_l_handle.html#aa2edbc1c0d3e3e8259bd98de7f1cf500',1,'tinyxml2::XMLHandle::XMLHandle(XMLNode &node)'],['../classtinyxml2_1_1_x_m_l_handle.html#afd8e01e6018c07347b8e6d80272466aa',1,'tinyxml2::XMLHandle::XMLHandle(const XMLHandle &ref)']]], + ['xmlprinter',['XMLPrinter',['../classtinyxml2_1_1_x_m_l_printer.html#aa6d3841c069085f5b8a27bc7103c04f7',1,'tinyxml2::XMLPrinter']]] +]; diff --git a/docs/search/functions_2.html b/docs/search/functions_2.html new file mode 100644 index 0000000..ecce2f3 --- /dev/null +++ b/docs/search/functions_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_2.js b/docs/search/functions_2.js new file mode 100644 index 0000000..62ab567 --- /dev/null +++ b/docs/search/functions_2.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['cdata',['CData',['../classtinyxml2_1_1_x_m_l_text.html#ac1bb5ea4166c320882d9e0ad16fd385b',1,'tinyxml2::XMLText']]], + ['clear',['Clear',['../classtinyxml2_1_1_x_m_l_document.html#a65656b0b2cbc822708eb351504178aaf',1,'tinyxml2::XMLDocument']]], + ['clearbuffer',['ClearBuffer',['../classtinyxml2_1_1_x_m_l_printer.html#a216157765b7267bf389975b1cbf9a909',1,'tinyxml2::XMLPrinter']]], + ['closeelement',['CloseElement',['../classtinyxml2_1_1_x_m_l_printer.html#ad04d29562b46fcdb23ab320f8b664240',1,'tinyxml2::XMLPrinter']]], + ['cstr',['CStr',['../classtinyxml2_1_1_x_m_l_printer.html#a180671d73844f159f2d4aafbc11d106e',1,'tinyxml2::XMLPrinter']]], + ['cstrsize',['CStrSize',['../classtinyxml2_1_1_x_m_l_printer.html#a3256cf3523d4898b91abb18b924be04c',1,'tinyxml2::XMLPrinter']]] +]; diff --git a/docs/search/functions_3.html b/docs/search/functions_3.html new file mode 100644 index 0000000..15f06ab --- /dev/null +++ b/docs/search/functions_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_3.js b/docs/search/functions_3.js new file mode 100644 index 0000000..c24f73b --- /dev/null +++ b/docs/search/functions_3.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['deepclone',['DeepClone',['../classtinyxml2_1_1_x_m_l_node.html#a62c71b6bf8734b5424063b8d9a61c266',1,'tinyxml2::XMLNode']]], + ['deepcopy',['DeepCopy',['../classtinyxml2_1_1_x_m_l_document.html#aab792e90adc38cdc5446616573b8b01b',1,'tinyxml2::XMLDocument']]], + ['deleteattribute',['DeleteAttribute',['../classtinyxml2_1_1_x_m_l_element.html#aebd45aa7118964c30b32fe12e944628a',1,'tinyxml2::XMLElement']]], + ['deletechild',['DeleteChild',['../classtinyxml2_1_1_x_m_l_node.html#a363b6edbd6ebd55f8387d2b89f2b0921',1,'tinyxml2::XMLNode']]], + ['deletechildren',['DeleteChildren',['../classtinyxml2_1_1_x_m_l_node.html#a0360085cc54df5bff85d5c5da13afdce',1,'tinyxml2::XMLNode']]], + ['deletenode',['DeleteNode',['../classtinyxml2_1_1_x_m_l_document.html#ac1d6e2c7fcc1a660624ac4f68e96380d',1,'tinyxml2::XMLDocument']]], + ['doubleattribute',['DoubleAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a10a90c505aea716bf073eea1c97f33b5',1,'tinyxml2::XMLElement']]], + ['doubletext',['DoubleText',['../classtinyxml2_1_1_x_m_l_element.html#a81b1ff0cf2f2cd09be8badc08b39a2b7',1,'tinyxml2::XMLElement']]], + ['doublevalue',['DoubleValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a4aa73513f54ff0087d3e804f0f54e30f',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/functions_4.html b/docs/search/functions_4.html new file mode 100644 index 0000000..8985ff2 --- /dev/null +++ b/docs/search/functions_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_4.js b/docs/search/functions_4.js new file mode 100644 index 0000000..eb6c1f6 --- /dev/null +++ b/docs/search/functions_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['error',['Error',['../classtinyxml2_1_1_x_m_l_document.html#a34e6318e182e40e3cc4f4ba5d59ed9ed',1,'tinyxml2::XMLDocument']]], + ['errorid',['ErrorID',['../classtinyxml2_1_1_x_m_l_document.html#afa3ed33b3107f920ec2b301f805ac17d',1,'tinyxml2::XMLDocument']]] +]; diff --git a/docs/search/functions_5.html b/docs/search/functions_5.html new file mode 100644 index 0000000..0314918 --- /dev/null +++ b/docs/search/functions_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_5.js b/docs/search/functions_5.js new file mode 100644 index 0000000..182bbfe --- /dev/null +++ b/docs/search/functions_5.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['findattribute',['FindAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a2dcd4d5d6fb63396cd2f257c318b42c4',1,'tinyxml2::XMLElement']]], + ['firstattribute',['FirstAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a3e191704c8d499906ec11fe2f60c6686',1,'tinyxml2::XMLElement']]], + ['firstchild',['FirstChild',['../classtinyxml2_1_1_x_m_l_node.html#ae7dc225e1018cdd685f7563593a1fe08',1,'tinyxml2::XMLNode::FirstChild()'],['../classtinyxml2_1_1_x_m_l_handle.html#a536447dc7f54c0cd11e031dad94795ae',1,'tinyxml2::XMLHandle::FirstChild()']]], + ['firstchildelement',['FirstChildElement',['../classtinyxml2_1_1_x_m_l_node.html#a1795a35852dc8aae877cc8ded986e59b',1,'tinyxml2::XMLNode::FirstChildElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a74b04dd0f15e0bf01860e282b840b6a3',1,'tinyxml2::XMLHandle::FirstChildElement()']]], + ['floatattribute',['FloatAttribute',['../classtinyxml2_1_1_x_m_l_element.html#ab1f4be2332e27dc640e9b6abd01d64dd',1,'tinyxml2::XMLElement']]], + ['floattext',['FloatText',['../classtinyxml2_1_1_x_m_l_element.html#a45444eb21f99ca46101545992dc2e927',1,'tinyxml2::XMLElement']]], + ['floatvalue',['FloatValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a27797b45d21c981257720db94f5f8801',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/functions_6.html b/docs/search/functions_6.html new file mode 100644 index 0000000..c506123 --- /dev/null +++ b/docs/search/functions_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_6.js b/docs/search/functions_6.js new file mode 100644 index 0000000..39c82fb --- /dev/null +++ b/docs/search/functions_6.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['getdocument',['GetDocument',['../classtinyxml2_1_1_x_m_l_node.html#a2de84cfa4ec3fe249bad745069d145f1',1,'tinyxml2::XMLNode::GetDocument() const'],['../classtinyxml2_1_1_x_m_l_node.html#af343d1ef0b45c0020e62d784d7e67a68',1,'tinyxml2::XMLNode::GetDocument()']]], + ['geterrorlinenum',['GetErrorLineNum',['../classtinyxml2_1_1_x_m_l_document.html#ad82d07e43e096e834dbdfd06312398c1',1,'tinyxml2::XMLDocument']]], + ['geterrorstr1',['GetErrorStr1',['../classtinyxml2_1_1_x_m_l_document.html#a229494e30e5473237f3fa547eee4c43f',1,'tinyxml2::XMLDocument']]], + ['geterrorstr2',['GetErrorStr2',['../classtinyxml2_1_1_x_m_l_document.html#a2d952f49c761bffd2903250680a8716b',1,'tinyxml2::XMLDocument']]], + ['getlinenum',['GetLineNum',['../classtinyxml2_1_1_x_m_l_node.html#a9b5fc636646fda761d342c72e91cb286',1,'tinyxml2::XMLNode::GetLineNum()'],['../classtinyxml2_1_1_x_m_l_attribute.html#a02d5ea924586e35f9c13857d1671b765',1,'tinyxml2::XMLAttribute::GetLineNum()']]], + ['gettext',['GetText',['../classtinyxml2_1_1_x_m_l_element.html#a6d5c8d115561ade4e4456b71d91b6f51',1,'tinyxml2::XMLElement']]], + ['getuserdata',['GetUserData',['../classtinyxml2_1_1_x_m_l_node.html#a7f0687574afa03bc479dc44f29db0afe',1,'tinyxml2::XMLNode']]] +]; diff --git a/docs/search/functions_7.html b/docs/search/functions_7.html new file mode 100644 index 0000000..83a7b84 --- /dev/null +++ b/docs/search/functions_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_7.js b/docs/search/functions_7.js new file mode 100644 index 0000000..b7d6d1f --- /dev/null +++ b/docs/search/functions_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['hasbom',['HasBOM',['../classtinyxml2_1_1_x_m_l_document.html#a33fc5d159db873a179fa26338adb05bd',1,'tinyxml2::XMLDocument']]] +]; diff --git a/docs/search/functions_8.html b/docs/search/functions_8.html new file mode 100644 index 0000000..b55f0e6 --- /dev/null +++ b/docs/search/functions_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_8.js b/docs/search/functions_8.js new file mode 100644 index 0000000..b1519d5 --- /dev/null +++ b/docs/search/functions_8.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['insertafterchild',['InsertAfterChild',['../classtinyxml2_1_1_x_m_l_node.html#a85adb8f0b7477eec30f9a41d420b09c2',1,'tinyxml2::XMLNode']]], + ['insertendchild',['InsertEndChild',['../classtinyxml2_1_1_x_m_l_node.html#aeb249ed60f4e8bfad3709151c3ee4286',1,'tinyxml2::XMLNode']]], + ['insertfirstchild',['InsertFirstChild',['../classtinyxml2_1_1_x_m_l_node.html#a8ff7dc071f3a1a6ae2ac25a37492865d',1,'tinyxml2::XMLNode']]], + ['int64attribute',['Int64Attribute',['../classtinyxml2_1_1_x_m_l_element.html#a66d96972adecd816194191f13cc4a0a0',1,'tinyxml2::XMLElement']]], + ['int64text',['Int64Text',['../classtinyxml2_1_1_x_m_l_element.html#aab6151f7e3b4c2c0a8234e262d7b6b8a',1,'tinyxml2::XMLElement']]], + ['intattribute',['IntAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a95a89b13bb14a2d4655e2b5b406c00d4',1,'tinyxml2::XMLElement']]], + ['intvalue',['IntValue',['../classtinyxml2_1_1_x_m_l_attribute.html#adfa2433f0fdafd5c3880936de9affa80',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/functions_9.html b/docs/search/functions_9.html new file mode 100644 index 0000000..c73f07b --- /dev/null +++ b/docs/search/functions_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_9.js b/docs/search/functions_9.js new file mode 100644 index 0000000..42991e3 --- /dev/null +++ b/docs/search/functions_9.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['lastchild',['LastChild',['../classtinyxml2_1_1_x_m_l_node.html#a9b8583a277e8e26f4cbbb5492786778e',1,'tinyxml2::XMLNode::LastChild()'],['../classtinyxml2_1_1_x_m_l_handle.html#a9d09f04435f0f2f7d0816b0198d0517b',1,'tinyxml2::XMLHandle::LastChild()']]], + ['lastchildelement',['LastChildElement',['../classtinyxml2_1_1_x_m_l_node.html#a173e9d1341bc56992e2d320a35936551',1,'tinyxml2::XMLNode::LastChildElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a42cccd0ce8b1ce704f431025e9f19e0c',1,'tinyxml2::XMLHandle::LastChildElement()']]], + ['loadfile',['LoadFile',['../classtinyxml2_1_1_x_m_l_document.html#a2ebd4647a8af5fc6831b294ac26a150a',1,'tinyxml2::XMLDocument::LoadFile(const char *filename)'],['../classtinyxml2_1_1_x_m_l_document.html#a5f1d330fad44c52f3d265338dd2a6dc2',1,'tinyxml2::XMLDocument::LoadFile(FILE *)']]] +]; diff --git a/docs/search/functions_a.html b/docs/search/functions_a.html new file mode 100644 index 0000000..f10ad63 --- /dev/null +++ b/docs/search/functions_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_a.js b/docs/search/functions_a.js new file mode 100644 index 0000000..953470a --- /dev/null +++ b/docs/search/functions_a.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['name',['Name',['../classtinyxml2_1_1_x_m_l_attribute.html#ab886c486ec19f02ed826f8dc129e5ad8',1,'tinyxml2::XMLAttribute::Name()'],['../classtinyxml2_1_1_x_m_l_element.html#a63e057fb5baee1dd29f323cb85907b35',1,'tinyxml2::XMLElement::Name()']]], + ['newcomment',['NewComment',['../classtinyxml2_1_1_x_m_l_document.html#ade4874bcb439954972ef2b3723ff3259',1,'tinyxml2::XMLDocument']]], + ['newdeclaration',['NewDeclaration',['../classtinyxml2_1_1_x_m_l_document.html#aee2eb3435923f5494dcc70ac225b60a2',1,'tinyxml2::XMLDocument']]], + ['newelement',['NewElement',['../classtinyxml2_1_1_x_m_l_document.html#a8aa7817d4a1001364b06373763ab99d6',1,'tinyxml2::XMLDocument']]], + ['newtext',['NewText',['../classtinyxml2_1_1_x_m_l_document.html#ab7e8b29ae4099092a8bb947da6361296',1,'tinyxml2::XMLDocument']]], + ['newunknown',['NewUnknown',['../classtinyxml2_1_1_x_m_l_document.html#a5385c937734ff6db9226ab707d2c7147',1,'tinyxml2::XMLDocument']]], + ['next',['Next',['../classtinyxml2_1_1_x_m_l_attribute.html#aee53571b21e7ce5421eb929523a8bbe6',1,'tinyxml2::XMLAttribute']]], + ['nextsibling',['NextSibling',['../classtinyxml2_1_1_x_m_l_node.html#a79db9ef0fe014d27790f2218b87bcbb5',1,'tinyxml2::XMLNode::NextSibling()'],['../classtinyxml2_1_1_x_m_l_handle.html#aad2eccc7c7c7b18145877c978c3850b5',1,'tinyxml2::XMLHandle::NextSibling()']]], + ['nextsiblingelement',['NextSiblingElement',['../classtinyxml2_1_1_x_m_l_node.html#a1264c86233328f0cd36297552d982f80',1,'tinyxml2::XMLNode::NextSiblingElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#ae41d88ee061f3c49a081630ff753b2c5',1,'tinyxml2::XMLHandle::NextSiblingElement()']]], + ['nochildren',['NoChildren',['../classtinyxml2_1_1_x_m_l_node.html#ac3ab489e6e202a3cd1762d3b332e89d4',1,'tinyxml2::XMLNode']]] +]; diff --git a/docs/search/functions_b.html b/docs/search/functions_b.html new file mode 100644 index 0000000..172ea1b --- /dev/null +++ b/docs/search/functions_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_b.js b/docs/search/functions_b.js new file mode 100644 index 0000000..9772c30 --- /dev/null +++ b/docs/search/functions_b.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['openelement',['OpenElement',['../classtinyxml2_1_1_x_m_l_printer.html#a20fb06c83bd13e5140d7dd13af06c010',1,'tinyxml2::XMLPrinter']]], + ['operator_3d',['operator=',['../classtinyxml2_1_1_x_m_l_handle.html#a75b908322bb4b83be3281b6845252b20',1,'tinyxml2::XMLHandle']]] +]; diff --git a/docs/search/functions_c.html b/docs/search/functions_c.html new file mode 100644 index 0000000..99492ba --- /dev/null +++ b/docs/search/functions_c.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_c.js b/docs/search/functions_c.js new file mode 100644 index 0000000..ce9baee --- /dev/null +++ b/docs/search/functions_c.js @@ -0,0 +1,14 @@ +var searchData= +[ + ['parent',['Parent',['../classtinyxml2_1_1_x_m_l_node.html#ae0f62bc186c56c2e0483ebd52dbfbe34',1,'tinyxml2::XMLNode']]], + ['parse',['Parse',['../classtinyxml2_1_1_x_m_l_document.html#a1819bd34f540a7304c105a6232d25a1f',1,'tinyxml2::XMLDocument']]], + ['previoussibling',['PreviousSibling',['../classtinyxml2_1_1_x_m_l_node.html#aac667c513d445f8b783e1e15ef9d3551',1,'tinyxml2::XMLNode::PreviousSibling()'],['../classtinyxml2_1_1_x_m_l_handle.html#a428374e756f4db4cbc287fec64eae02c',1,'tinyxml2::XMLHandle::PreviousSibling()']]], + ['previoussiblingelement',['PreviousSiblingElement',['../classtinyxml2_1_1_x_m_l_node.html#a872936cae46fb473eb47fec99129fc70',1,'tinyxml2::XMLNode::PreviousSiblingElement()'],['../classtinyxml2_1_1_x_m_l_handle.html#a786957e498039554ed334cdc36612a7e',1,'tinyxml2::XMLHandle::PreviousSiblingElement()']]], + ['print',['Print',['../classtinyxml2_1_1_x_m_l_document.html#a867cf5fa3e3ff6ae4847a8b7ee8ec083',1,'tinyxml2::XMLDocument']]], + ['printerror',['PrintError',['../classtinyxml2_1_1_x_m_l_document.html#a1d033945b42e125d933d6231e4571552',1,'tinyxml2::XMLDocument']]], + ['printspace',['PrintSpace',['../classtinyxml2_1_1_x_m_l_printer.html#a01148e2ebe6776e38c5a3e41bc5feb74',1,'tinyxml2::XMLPrinter']]], + ['pushattribute',['PushAttribute',['../classtinyxml2_1_1_x_m_l_printer.html#a9a4e2c9348b42e147629d5a99f4af3f0',1,'tinyxml2::XMLPrinter']]], + ['pushcomment',['PushComment',['../classtinyxml2_1_1_x_m_l_printer.html#afc8416814219591c2fd5656e0c233140',1,'tinyxml2::XMLPrinter']]], + ['pushheader',['PushHeader',['../classtinyxml2_1_1_x_m_l_printer.html#a178c608ce8476043d5d6513819cde903',1,'tinyxml2::XMLPrinter']]], + ['pushtext',['PushText',['../classtinyxml2_1_1_x_m_l_printer.html#a1cc16a9362df4332012cb13cff6441b3',1,'tinyxml2::XMLPrinter::PushText(const char *text, bool cdata=false)'],['../classtinyxml2_1_1_x_m_l_printer.html#a3e0d4d78de25d4cf081009e1431cea7e',1,'tinyxml2::XMLPrinter::PushText(int value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a661fb50e7e0a4918d2d259cb0fae647e',1,'tinyxml2::XMLPrinter::PushText(unsigned value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a96b0a0bfe105154a0a6c37d725258f0a',1,'tinyxml2::XMLPrinter::PushText(int64_t value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a4390e5fa1ed05189a8686647345ab29f',1,'tinyxml2::XMLPrinter::PushText(bool value)'],['../classtinyxml2_1_1_x_m_l_printer.html#a1dbb1390e829d0673af66b9cd1928bd7',1,'tinyxml2::XMLPrinter::PushText(float value)'],['../classtinyxml2_1_1_x_m_l_printer.html#aa715302dfc09473c77c853cbd5431965',1,'tinyxml2::XMLPrinter::PushText(double value)']]] +]; diff --git a/docs/search/functions_d.html b/docs/search/functions_d.html new file mode 100644 index 0000000..5be9ecc --- /dev/null +++ b/docs/search/functions_d.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_d.js b/docs/search/functions_d.js new file mode 100644 index 0000000..b78f218 --- /dev/null +++ b/docs/search/functions_d.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['queryattribute',['QueryAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a042fc30504347b84a56cf863ad528a4f',1,'tinyxml2::XMLElement']]], + ['queryboolattribute',['QueryBoolAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a14c1bb77c39689838be01838d86ca872',1,'tinyxml2::XMLElement']]], + ['querybooltext',['QueryBoolText',['../classtinyxml2_1_1_x_m_l_element.html#a3fe5417d59eb8f5c4afe924b7d332736',1,'tinyxml2::XMLElement']]], + ['queryboolvalue',['QueryBoolValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a5f32e038954256f61c21ff20fd13a09c',1,'tinyxml2::XMLAttribute']]], + ['querydoubleattribute',['QueryDoubleAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a5f0964e2dbd8e2ee7fce9beab689443c',1,'tinyxml2::XMLElement']]], + ['querydoubletext',['QueryDoubleText',['../classtinyxml2_1_1_x_m_l_element.html#a684679c99bb036a25652744cec6c4d96',1,'tinyxml2::XMLElement']]], + ['querydoublevalue',['QueryDoubleValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a2aa6e55e8ea03af0609cf6690bff79b9',1,'tinyxml2::XMLAttribute']]], + ['queryfloatattribute',['QueryFloatAttribute',['../classtinyxml2_1_1_x_m_l_element.html#acd5eeddf6002ef90806af794b9d9a5a5',1,'tinyxml2::XMLElement']]], + ['queryfloattext',['QueryFloatText',['../classtinyxml2_1_1_x_m_l_element.html#afa332afedd93210daa6d44b88eb11e29',1,'tinyxml2::XMLElement']]], + ['queryfloatvalue',['QueryFloatValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a049dea6449a6259b6cfed44a9427b607',1,'tinyxml2::XMLAttribute']]], + ['queryint64attribute',['QueryInt64Attribute',['../classtinyxml2_1_1_x_m_l_element.html#a7c0955d80b6f8d196744eacb0f6e90a8',1,'tinyxml2::XMLElement']]], + ['queryint64text',['QueryInt64Text',['../classtinyxml2_1_1_x_m_l_element.html#a120c538c8eead169e635dbc70fb226d8',1,'tinyxml2::XMLElement']]], + ['queryint64value',['QueryInt64Value',['../classtinyxml2_1_1_x_m_l_attribute.html#a4e25344d6e4159026be34dbddf1dcac2',1,'tinyxml2::XMLAttribute']]], + ['queryintattribute',['QueryIntAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a8a78bc1187c1c45ad89f2690eab567b1',1,'tinyxml2::XMLElement']]], + ['queryinttext',['QueryIntText',['../classtinyxml2_1_1_x_m_l_element.html#a926357996bef633cb736e1a558419632',1,'tinyxml2::XMLElement']]], + ['queryintvalue',['QueryIntValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a6d5176260db00ea301c01af8457cd993',1,'tinyxml2::XMLAttribute']]], + ['queryunsignedattribute',['QueryUnsignedAttribute',['../classtinyxml2_1_1_x_m_l_element.html#a26fc84cbfba6769dafcfbf256c05e22f',1,'tinyxml2::XMLElement']]], + ['queryunsignedtext',['QueryUnsignedText',['../classtinyxml2_1_1_x_m_l_element.html#a14d38aa4b5e18a46274a27425188a6a1',1,'tinyxml2::XMLElement']]], + ['queryunsignedvalue',['QueryUnsignedValue',['../classtinyxml2_1_1_x_m_l_attribute.html#a48a7f3496f1415832e451bd8d09c9cb9',1,'tinyxml2::XMLAttribute']]] +]; diff --git a/docs/search/functions_e.html b/docs/search/functions_e.html new file mode 100644 index 0000000..e256cb6 --- /dev/null +++ b/docs/search/functions_e.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_e.js b/docs/search/functions_e.js new file mode 100644 index 0000000..f56f3e3 --- /dev/null +++ b/docs/search/functions_e.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['rootelement',['RootElement',['../classtinyxml2_1_1_x_m_l_document.html#ad2b70320d3c2a071c2f36928edff3e1c',1,'tinyxml2::XMLDocument']]] +]; diff --git a/docs/search/functions_f.html b/docs/search/functions_f.html new file mode 100644 index 0000000..424126c --- /dev/null +++ b/docs/search/functions_f.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/functions_f.js b/docs/search/functions_f.js new file mode 100644 index 0000000..be8e75d --- /dev/null +++ b/docs/search/functions_f.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['savefile',['SaveFile',['../classtinyxml2_1_1_x_m_l_document.html#a73ac416b4a2aa0952e841220eb3da18f',1,'tinyxml2::XMLDocument::SaveFile(const char *filename, bool compact=false)'],['../classtinyxml2_1_1_x_m_l_document.html#a8b95779479a0035acc67b3a61dfe1b74',1,'tinyxml2::XMLDocument::SaveFile(FILE *fp, bool compact=false)']]], + ['setattribute',['SetAttribute',['../classtinyxml2_1_1_x_m_l_attribute.html#a406d2c4a13c7af99a65edb59dd9f7581',1,'tinyxml2::XMLAttribute::SetAttribute(const char *value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ad86d7d7058d76761c3a80662566a57e5',1,'tinyxml2::XMLAttribute::SetAttribute(int value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ae70468c0f6df2748ba3529c716999fae',1,'tinyxml2::XMLAttribute::SetAttribute(unsigned value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#a7c1240f479722b9aa29b6c030aa116c2',1,'tinyxml2::XMLAttribute::SetAttribute(int64_t value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ab3516def4fe058fe328f2b89fc2d77da',1,'tinyxml2::XMLAttribute::SetAttribute(bool value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#a9a65ab3147abe8ccbbd373ce8791e818',1,'tinyxml2::XMLAttribute::SetAttribute(double value)'],['../classtinyxml2_1_1_x_m_l_attribute.html#ae95e843313aaf5d56c32530b6456df02',1,'tinyxml2::XMLAttribute::SetAttribute(float value)'],['../classtinyxml2_1_1_x_m_l_element.html#a11943abf2d0831548c3790dd5d9f119c',1,'tinyxml2::XMLElement::SetAttribute(const char *name, const char *value)'],['../classtinyxml2_1_1_x_m_l_element.html#aae6568c64c7f1cc88be8461ba41a79cf',1,'tinyxml2::XMLElement::SetAttribute(const char *name, int value)'],['../classtinyxml2_1_1_x_m_l_element.html#ae143997e90064ba82326b29a9930ea8f',1,'tinyxml2::XMLElement::SetAttribute(const char *name, unsigned value)'],['../classtinyxml2_1_1_x_m_l_element.html#aaeefdf9171fec91b13a776b42299b0dd',1,'tinyxml2::XMLElement::SetAttribute(const char *name, int64_t value)'],['../classtinyxml2_1_1_x_m_l_element.html#aa848b696e6a75e4e545c6da9893b11e1',1,'tinyxml2::XMLElement::SetAttribute(const char *name, bool value)'],['../classtinyxml2_1_1_x_m_l_element.html#a233397ee81e70eb5d4b814c5f8698533',1,'tinyxml2::XMLElement::SetAttribute(const char *name, double value)'],['../classtinyxml2_1_1_x_m_l_element.html#a554b70d882e65b28fc084b23df9b9759',1,'tinyxml2::XMLElement::SetAttribute(const char *name, float value)']]], + ['setbom',['SetBOM',['../classtinyxml2_1_1_x_m_l_document.html#a14419b698f7c4b140df4e80f3f0c93b0',1,'tinyxml2::XMLDocument']]], + ['setcdata',['SetCData',['../classtinyxml2_1_1_x_m_l_text.html#ad080357d76ab7cc59d7651249949329d',1,'tinyxml2::XMLText']]], + ['setname',['SetName',['../classtinyxml2_1_1_x_m_l_element.html#a97712009a530d8cb8a63bf705f02b4f1',1,'tinyxml2::XMLElement']]], + ['settext',['SetText',['../classtinyxml2_1_1_x_m_l_element.html#a1f9c2cd61b72af5ae708d37b7ad283ce',1,'tinyxml2::XMLElement::SetText(const char *inText)'],['../classtinyxml2_1_1_x_m_l_element.html#aeae8917b5ea6060b3c08d4e3d8d632d7',1,'tinyxml2::XMLElement::SetText(int value)'],['../classtinyxml2_1_1_x_m_l_element.html#a7bbfcc11d516598bc924a8fba4d08597',1,'tinyxml2::XMLElement::SetText(unsigned value)'],['../classtinyxml2_1_1_x_m_l_element.html#a7b62cd33acdfeff7ea2b1b330d4368e4',1,'tinyxml2::XMLElement::SetText(int64_t value)'],['../classtinyxml2_1_1_x_m_l_element.html#ae4b543d6770de76fb6ab68e541c192a4',1,'tinyxml2::XMLElement::SetText(bool value)'],['../classtinyxml2_1_1_x_m_l_element.html#a67bd77ac9aaeff58ff20b4275a65ba4e',1,'tinyxml2::XMLElement::SetText(double value)'],['../classtinyxml2_1_1_x_m_l_element.html#a51d560da5ae3ad6b75e0ab9ffb2ae42a',1,'tinyxml2::XMLElement::SetText(float value)']]], + ['setuserdata',['SetUserData',['../classtinyxml2_1_1_x_m_l_node.html#a002978fc889cc011d143185f2377eca2',1,'tinyxml2::XMLNode']]], + ['setvalue',['SetValue',['../classtinyxml2_1_1_x_m_l_node.html#a09dd68cf9eae137579f6e50f36487513',1,'tinyxml2::XMLNode']]], + ['shallowclone',['ShallowClone',['../classtinyxml2_1_1_x_m_l_node.html#a8402cbd3129d20e9e6024bbcc0531283',1,'tinyxml2::XMLNode::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_text.html#af3a81ed4dd49d5151c477b3f265a3011',1,'tinyxml2::XMLText::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_comment.html#a08991cc63fadf7e95078ac4f9ea1b073',1,'tinyxml2::XMLComment::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_declaration.html#a118d47518dd9e522644e42efa259aed7',1,'tinyxml2::XMLDeclaration::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_unknown.html#a0125f41c89763dea06619b5fd5246b4c',1,'tinyxml2::XMLUnknown::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_element.html#ac035742d68b0c50c3f676374e59fe750',1,'tinyxml2::XMLElement::ShallowClone()'],['../classtinyxml2_1_1_x_m_l_document.html#aa37cc1709d7e1e988bc17dcfb24a69b8',1,'tinyxml2::XMLDocument::ShallowClone()']]], + ['shallowequal',['ShallowEqual',['../classtinyxml2_1_1_x_m_l_node.html#a7ce18b751c3ea09eac292dca264f9226',1,'tinyxml2::XMLNode::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_text.html#ae0fff8a24e2de7eb073fd192e9db0331',1,'tinyxml2::XMLText::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_comment.html#a6f7d227b25afa8cc3c763b7cc8833739',1,'tinyxml2::XMLComment::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_declaration.html#aa26b70011694e9b9e9480b929e9b78d6',1,'tinyxml2::XMLDeclaration::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_unknown.html#a0715ab2c05d7f74845c188122213b116',1,'tinyxml2::XMLUnknown::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_element.html#ad9ea913a460b48979bd83cf9871c99f6',1,'tinyxml2::XMLElement::ShallowEqual()'],['../classtinyxml2_1_1_x_m_l_document.html#a6fe5ef18699091844fcf64b56ffa5bf9',1,'tinyxml2::XMLDocument::ShallowEqual()']]] +]; diff --git a/docs/search/mag_sel.png b/docs/search/mag_sel.png new file mode 100644 index 0000000000000000000000000000000000000000..81f6040a2092402b4d98f9ffa8855d12a0d4ca17 GIT binary patch literal 563 zcmV-30?hr1P)zxx&tqG15pu7)IiiXFflOc2k;dXd>%13GZAy? zRz!q0=|E6a6vV)&ZBS~G9oe0kbqyw1*gvY`{Pop2oKq#FlzgXt@Xh-7fxh>}`Fxg> z$%N%{$!4=5nM{(;=c!aG1Ofr^Do{u%Ih{^&Fc@H2)+a-?TBXrw5DW&z%Nb6mQ!L9O zl}b@6mB?f=tX3;#vl)}ggh(Vpyh(IK z(Mb0D{l{U$FsRjP;!{($+bsaaVi8T#1c0V#qEIOCYa9@UVLV`f__E81L;?WEaRA;Y zUH;rZ;vb;mk7JX|$=i3O~&If0O@oZfLg8gfIjW=dcBsz;gI=!{-r4# z4%6v$&~;q^j7Fo67yJ(NJWuX+I~I!tj^nW3?}^9bq|<3^+vapS5sgM^x7!cs(+mMT z&y%j};&~po+YO)3hoUH4E*E;e9>?R6SS&`X)p`njycAVcg{rEb41T{~Hk(bl-7eSb zmFxA2uIqo#@R?lKm50ND`~6Nfn|-b1|L6O98vt3Tx@gKz#isxO002ovPDHLkV1kyW B_l^Jn literal 0 HcmV?d00001 diff --git a/docs/search/nomatches.html b/docs/search/nomatches.html new file mode 100644 index 0000000..b1ded27 --- /dev/null +++ b/docs/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
+
No Matches
+
+ + diff --git a/docs/search/pages_0.html b/docs/search/pages_0.html new file mode 100644 index 0000000..4955b9e --- /dev/null +++ b/docs/search/pages_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/pages_0.js b/docs/search/pages_0.js new file mode 100644 index 0000000..868fb87 --- /dev/null +++ b/docs/search/pages_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['get_20information_20out_20of_20xml',['Get information out of XML',['../_example-3.html',1,'']]] +]; diff --git a/docs/search/pages_1.html b/docs/search/pages_1.html new file mode 100644 index 0000000..aedb14e --- /dev/null +++ b/docs/search/pages_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/pages_1.js b/docs/search/pages_1.js new file mode 100644 index 0000000..a11be89 --- /dev/null +++ b/docs/search/pages_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['load_20an_20xml_20file',['Load an XML File',['../_example-1.html',1,'']]] +]; diff --git a/docs/search/pages_2.html b/docs/search/pages_2.html new file mode 100644 index 0000000..bd91593 --- /dev/null +++ b/docs/search/pages_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/pages_2.js b/docs/search/pages_2.js new file mode 100644 index 0000000..5b909ab --- /dev/null +++ b/docs/search/pages_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['parse_20an_20xml_20from_20char_20buffer',['Parse an XML from char buffer',['../_example-2.html',1,'']]] +]; diff --git a/docs/search/pages_3.html b/docs/search/pages_3.html new file mode 100644 index 0000000..bc0e37f --- /dev/null +++ b/docs/search/pages_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/pages_3.js b/docs/search/pages_3.js new file mode 100644 index 0000000..41376dd --- /dev/null +++ b/docs/search/pages_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['read_20attributes_20and_20text_20information_2e',['Read attributes and text information.',['../_example-4.html',1,'']]] +]; diff --git a/docs/search/pages_4.html b/docs/search/pages_4.html new file mode 100644 index 0000000..d4c3e8e --- /dev/null +++ b/docs/search/pages_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/search/pages_4.js b/docs/search/pages_4.js new file mode 100644 index 0000000..f9587cc --- /dev/null +++ b/docs/search/pages_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['tinyxml_2d2',['TinyXML-2',['../index.html',1,'']]] +]; diff --git a/docs/search/search.css b/docs/search/search.css new file mode 100644 index 0000000..3cf9df9 --- /dev/null +++ b/docs/search/search.css @@ -0,0 +1,271 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + float: none; + margin-top: 8px; + right: 0px; + width: 170px; + height: 24px; + z-index: 102; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:115px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; + -webkit-border-radius: 0px; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:8px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 10001; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; + z-index:10000; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/docs/search/search.js b/docs/search/search.js new file mode 100644 index 0000000..dedce3b --- /dev/null +++ b/docs/search/search.js @@ -0,0 +1,791 @@ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; ek7RCwB~R6VQOP#AvB$vH7i{6H{96zot$7cZT<7246EF5Np6N}+$IbiG6W zg#87A+NFaX+=_^xM1#gCtshC=E{%9^uQX_%?YwXvo{#q&MnpJ8uh(O?ZRc&~_1%^SsPxG@rfElJg-?U zm!Cz-IOn(qJP3kDp-^~qt+FGbl=5jNli^Wj_xIBG{Rc0en{!oFvyoNC7{V~T8}b>| z=jL2WIReZzX(YN(_9fV;BBD$VXQIxNasAL8ATvEu822WQ%mvv4FO#qs` BFGc_W literal 0 HcmV?d00001 diff --git a/docs/search/search_r.png b/docs/search/search_r.png new file mode 100644 index 0000000000000000000000000000000000000000..97ee8b439687084201b79c6f776a41f495c6392a GIT binary patch literal 612 zcmV-q0-ODbP)PbXFRCwB?)W514K@j&X?z2*SxFI6-@HT2E2K=9X9%Pb zEK*!TBw&g(DMC;|A)uGlRkOS9vd-?zNs%bR4d$w+ox_iFnE8fvIvv7^5<(>Te12Li z7C)9srCzmK{ZcNM{YIl9j{DePFgOWiS%xG@5CnnnJa4nvY<^glbz7^|-ZY!dUkAwd z{gaTC@_>b5h~;ug#R0wRL0>o5!hxm*s0VW?8dr}O#zXTRTnrQm_Z7z1Mrnx>&p zD4qifUjzLvbVVWi?l?rUzwt^sdb~d!f_LEhsRVIXZtQ=qSxuxqm zEX#tf>$?M_Y1-LSDT)HqG?`%-%ZpY!#{N!rcNIiL;G7F0`l?)mNGTD9;f9F5Up3Kg zw}a<-JylhG&;=!>B+fZaCX+?C+kHYrP%c?X2!Zu_olK|GcS4A70HEy;vn)I0>0kLH z`jc(WIaaHc7!HS@f*^R^Znx8W=_jIl2oWJoQ*h1^$FX!>*PqR1J8k|fw}w_y}TpE>7m8DqDO<3z`OzXt$ccSejbEZCg@0000-{AmhX=Jf(#6djGiuzAr*{o?=JLmPLyc> z_*`QK&+BH@jWrYJ7>r6%keRM@)Qyv8R=enp0jiI>aWlGyB58O zFVR20d+y`K7vDw(hJF3;>dD*3-?v=<8M)@x|EEGLnJsniYK!2U1 Y!`|5biEc?d1`HDhPgg&ebxsLQ02F6;9RL6T literal 0 HcmV?d00001 diff --git a/docs/sync_off.png b/docs/sync_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3b443fc62892114406e3d399421b2a881b897acc GIT binary patch literal 853 zcmV-b1FHOqP)oT|#XixUYy%lpuf3i8{fX!o zUyDD0jOrAiT^tq>fLSOOABs-#u{dV^F$b{L9&!2=9&RmV;;8s^x&UqB$PCj4FdKbh zoB1WTskPUPu05XzFbA}=KZ-GP1fPpAfSs>6AHb12UlR%-i&uOlTpFNS7{jm@mkU1V zh`nrXr~+^lsV-s1dkZOaI|kYyVj3WBpPCY{n~yd%u%e+d=f%`N0FItMPtdgBb@py; zq@v6NVArhyTC7)ULw-Jy8y42S1~4n(3LkrW8mW(F-4oXUP3E`e#g**YyqI7h-J2zK zK{m9##m4ri!7N>CqQqCcnI3hqo1I;Yh&QLNY4T`*ptiQGozK>FF$!$+84Z`xwmeMh zJ0WT+OH$WYFALEaGj2_l+#DC3t7_S`vHpSivNeFbP6+r50cO8iu)`7i%Z4BTPh@_m3Tk!nAm^)5Bqnr%Ov|Baunj#&RPtRuK& z4RGz|D5HNrW83-#ydk}tVKJrNmyYt-sTxLGlJY5nc&Re zU4SgHNPx8~Yxwr$bsju?4q&%T1874xxzq+_%?h8_ofw~(bld=o3iC)LUNR*BY%c0y zWd_jX{Y8`l%z+ol1$@Qa?Cy!(0CVIEeYpKZ`(9{z>3$CIe;pJDQk$m3p}$>xBm4lb zKo{4S)`wdU9Ba9jJbVJ0C=SOefZe%d$8=2r={nu<_^a3~>c#t_U6dye5)JrR(_a^E f@}b6j1K9lwFJq@>o)+Ry00000NkvXXu0mjfWa5j* literal 0 HcmV?d00001 diff --git a/docs/sync_on.png b/docs/sync_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e08320fb64e6fa33b573005ed6d8fe294e19db76 GIT binary patch literal 845 zcmV-T1G4;yP)Y;xxyHF2B5Wzm| zOOGupOTn@c(JmBOl)e;XMNnZuiTJP>rM8<|Q`7I_))aP?*T)ow&n59{}X4$3Goat zgjs?*aasfbrokzG5cT4K=uG`E14xZl@z)F={P0Y^?$4t z>v!teRnNZym<6h{7sLyF1V0HsfEl+l6TrZpsfr1}luH~F7L}ktXu|*uVX^RG$L0`K zWs3j|0tIvVe(N%_?2{(iCPFGf#B6Hjy6o&}D$A%W%jfO8_W%ZO#-mh}EM$LMn7joJ z05dHr!5Y92g+31l<%i1(=L1a1pXX+OYnalY>31V4K}BjyRe3)9n#;-cCVRD_IG1fT zOKGeNY8q;TL@K{dj@D^scf&VCs*-Jb>8b>|`b*osv52-!A?BpbYtTQBns5EAU**$m zSnVSm(teh>tQi*S*A>#ySc=n;`BHz`DuG4&g4Kf8lLhca+zvZ7t7RflD6-i-mcK=M z!=^P$*u2)bkY5asG4gsss!Hn%u~>}kIW`vMs%lJLH+u*9<4PaV_c6U`KqWXQH%+Nu zTv41O(^ZVi@qhjQdG!fbZw&y+2o!iYymO^?ud3{P*HdoX83YV*Uu_HB=?U&W9%AU# z80}k1SS-CXTU7dcQlsm<^oYLxVSseqY6NO}dc`Nj?8vrhNuCdm@^{a3AQ_>6myOj+ z`1RsLUXF|dm|3k7s2jD(B{rzE>WI2scH8i1;=O5Cc9xB3^aJk%fQjqsu+kH#0=_5a z0nCE8@dbQa-|YIuUVvG0L_IwHMEhOj$Mj4Uq05 X8=0q~qBNan00000NkvXXu0mjfptF>5 literal 0 HcmV?d00001 diff --git a/docs/tab_a.png b/docs/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3b725c41c5a527a3a3e40097077d0e206a681247 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QlXwMjv*C{Z|8b*H5dputLHD# z=<0|*y7z(Vor?d;H&?EG&cXR}?!j-Lm&u1OOI7AIF5&c)RFE;&p0MYK>*Kl@eiymD r@|NpwKX@^z+;{u_Z~trSBfrMKa%3`zocFjEXaR$#tDnm{r-UW|TZ1%4 literal 0 HcmV?d00001 diff --git a/docs/tab_b.png b/docs/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b4a8638cb3496a016eaed9e16ffc12846dea18 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QU#tajv*C{Z}0l@H7kg?K0Lnr z!j&C6_(~HV9oQ0Pa6x{-v0AGV_E?vLn=ZI-;YrdjIl`U`uzuDWSP?o#Dmo{%SgM#oan kX~E1%D-|#H#QbHoIja2U-MgvsK&LQxy85}Sb4q9e0Efg%P5=M^ literal 0 HcmV?d00001 diff --git a/docs/tabs.css b/docs/tabs.css new file mode 100644 index 0000000..a28614b --- /dev/null +++ b/docs/tabs.css @@ -0,0 +1 @@ +.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#doc-content{overflow:auto;display:block;padding:0;margin:0;-webkit-overflow-scrolling:touch}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace!important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0!important;-webkit-border-radius:0;border-radius:0!important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px!important;-webkit-border-radius:5px;border-radius:5px!important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0!important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px!important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}} \ No newline at end of file diff --git a/docs/tinyxml2_8h_source.html b/docs/tinyxml2_8h_source.html new file mode 100644 index 0000000..7a25e69 --- /dev/null +++ b/docs/tinyxml2_8h_source.html @@ -0,0 +1,180 @@ + + + + + + + +TinyXML-2: tinyxml2.h Source File + + + + + + + + + +
+
+ + + + + + +
+
TinyXML-2 +  5.0.1 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
tinyxml2.h
+
+
+
1 /*
2 Original code by Lee Thomason (www.grinninglizard.com)
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any
6 damages arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any
9 purpose, including commercial applications, and to alter it and
10 redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must
13 not claim that you wrote the original software. If you use this
14 software in a product, an acknowledgment in the product documentation
15 would be appreciated but is not required.
16 
17 2. Altered source versions must be plainly marked as such, and
18 must not be misrepresented as being the original software.
19 
20 3. This notice may not be removed or altered from any source
21 distribution.
22 */
23 
24 #ifndef TINYXML2_INCLUDED
25 #define TINYXML2_INCLUDED
26 
27 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
28 # include <ctype.h>
29 # include <limits.h>
30 # include <stdio.h>
31 # include <stdlib.h>
32 # include <string.h>
33 # if defined(__PS3__)
34 # include <stddef.h>
35 # endif
36 #else
37 # include <cctype>
38 # include <climits>
39 # include <cstdio>
40 # include <cstdlib>
41 # include <cstring>
42 #endif
43 #include <stdint.h>
44 
45 /*
46  TODO: intern strings instead of allocation.
47 */
48 /*
49  gcc:
50  g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
51 
52  Formatting, Artistic Style:
53  AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
54 */
55 
56 #if defined( _DEBUG ) || defined (__DEBUG__)
57 # ifndef DEBUG
58 # define DEBUG
59 # endif
60 #endif
61 
62 #ifdef _MSC_VER
63 # pragma warning(push)
64 # pragma warning(disable: 4251)
65 #endif
66 
67 #ifdef _WIN32
68 # ifdef TINYXML2_EXPORT
69 # define TINYXML2_LIB __declspec(dllexport)
70 # elif defined(TINYXML2_IMPORT)
71 # define TINYXML2_LIB __declspec(dllimport)
72 # else
73 # define TINYXML2_LIB
74 # endif
75 #elif __GNUC__ >= 4
76 # define TINYXML2_LIB __attribute__((visibility("default")))
77 #else
78 # define TINYXML2_LIB
79 #endif
80 
81 
82 #if defined(DEBUG)
83 # if defined(_MSC_VER)
84 # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
85 # define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); }
86 # elif defined (ANDROID_NDK)
87 # include <android/log.h>
88 # define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
89 # else
90 # include <assert.h>
91 # define TIXMLASSERT assert
92 # endif
93 #else
94 # define TIXMLASSERT( x ) {}
95 #endif
96 
97 
98 /* Versioning, past 1.0.14:
99  http://semver.org/
100 */
101 static const int TIXML2_MAJOR_VERSION = 5;
102 static const int TIXML2_MINOR_VERSION = 0;
103 static const int TIXML2_PATCH_VERSION = 1;
104 
105 namespace tinyxml2
106 {
107 class XMLDocument;
108 class XMLElement;
109 class XMLAttribute;
110 class XMLComment;
111 class XMLText;
112 class XMLDeclaration;
113 class XMLUnknown;
114 class XMLPrinter;
115 
116 /*
117  A class that wraps strings. Normally stores the start and end
118  pointers into the XML file itself, and will apply normalization
119  and entity translation if actually read. Can also store (and memory
120  manage) a traditional char[]
121 */
122 class StrPair
123 {
124 public:
125  enum {
126  NEEDS_ENTITY_PROCESSING = 0x01,
127  NEEDS_NEWLINE_NORMALIZATION = 0x02,
128  NEEDS_WHITESPACE_COLLAPSING = 0x04,
129 
130  TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
131  TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
132  ATTRIBUTE_NAME = 0,
133  ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
134  ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
135  COMMENT = NEEDS_NEWLINE_NORMALIZATION
136  };
137 
138  StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
139  ~StrPair();
140 
141  void Set( char* start, char* end, int flags ) {
142  TIXMLASSERT( start );
143  TIXMLASSERT( end );
144  Reset();
145  _start = start;
146  _end = end;
147  _flags = flags | NEEDS_FLUSH;
148  }
149 
150  const char* GetStr();
151 
152  bool Empty() const {
153  return _start == _end;
154  }
155 
156  void SetInternedStr( const char* str ) {
157  Reset();
158  _start = const_cast<char*>(str);
159  }
160 
161  void SetStr( const char* str, int flags=0 );
162 
163  char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );
164  char* ParseName( char* in );
165 
166  void TransferTo( StrPair* other );
167  void Reset();
168 
169 private:
170  void CollapseWhitespace();
171 
172  enum {
173  NEEDS_FLUSH = 0x100,
174  NEEDS_DELETE = 0x200
175  };
176 
177  int _flags;
178  char* _start;
179  char* _end;
180 
181  StrPair( const StrPair& other ); // not supported
182  void operator=( StrPair& other ); // not supported, use TransferTo()
183 };
184 
185 
186 /*
187  A dynamic array of Plain Old Data. Doesn't support constructors, etc.
188  Has a small initial memory pool, so that low or no usage will not
189  cause a call to new/delete
190 */
191 template <class T, int INITIAL_SIZE>
192 class DynArray
193 {
194 public:
195  DynArray() {
196  _mem = _pool;
197  _allocated = INITIAL_SIZE;
198  _size = 0;
199  }
200 
201  ~DynArray() {
202  if ( _mem != _pool ) {
203  delete [] _mem;
204  }
205  }
206 
207  void Clear() {
208  _size = 0;
209  }
210 
211  void Push( T t ) {
212  TIXMLASSERT( _size < INT_MAX );
213  EnsureCapacity( _size+1 );
214  _mem[_size] = t;
215  ++_size;
216  }
217 
218  T* PushArr( int count ) {
219  TIXMLASSERT( count >= 0 );
220  TIXMLASSERT( _size <= INT_MAX - count );
221  EnsureCapacity( _size+count );
222  T* ret = &_mem[_size];
223  _size += count;
224  return ret;
225  }
226 
227  T Pop() {
228  TIXMLASSERT( _size > 0 );
229  --_size;
230  return _mem[_size];
231  }
232 
233  void PopArr( int count ) {
234  TIXMLASSERT( _size >= count );
235  _size -= count;
236  }
237 
238  bool Empty() const {
239  return _size == 0;
240  }
241 
242  T& operator[](int i) {
243  TIXMLASSERT( i>= 0 && i < _size );
244  return _mem[i];
245  }
246 
247  const T& operator[](int i) const {
248  TIXMLASSERT( i>= 0 && i < _size );
249  return _mem[i];
250  }
251 
252  const T& PeekTop() const {
253  TIXMLASSERT( _size > 0 );
254  return _mem[ _size - 1];
255  }
256 
257  int Size() const {
258  TIXMLASSERT( _size >= 0 );
259  return _size;
260  }
261 
262  int Capacity() const {
263  TIXMLASSERT( _allocated >= INITIAL_SIZE );
264  return _allocated;
265  }
266 
267  void SwapRemove(int i) {
268  TIXMLASSERT(i >= 0 && i < _size);
269  TIXMLASSERT(_size > 0);
270  _mem[i] = _mem[_size - 1];
271  --_size;
272  }
273 
274  const T* Mem() const {
275  TIXMLASSERT( _mem );
276  return _mem;
277  }
278 
279  T* Mem() {
280  TIXMLASSERT( _mem );
281  return _mem;
282  }
283 
284 private:
285  DynArray( const DynArray& ); // not supported
286  void operator=( const DynArray& ); // not supported
287 
288  void EnsureCapacity( int cap ) {
289  TIXMLASSERT( cap > 0 );
290  if ( cap > _allocated ) {
291  TIXMLASSERT( cap <= INT_MAX / 2 );
292  int newAllocated = cap * 2;
293  T* newMem = new T[newAllocated];
294  TIXMLASSERT( newAllocated >= _size );
295  memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
296  if ( _mem != _pool ) {
297  delete [] _mem;
298  }
299  _mem = newMem;
300  _allocated = newAllocated;
301  }
302  }
303 
304  T* _mem;
305  T _pool[INITIAL_SIZE];
306  int _allocated; // objects allocated
307  int _size; // number objects in use
308 };
309 
310 
311 /*
312  Parent virtual class of a pool for fast allocation
313  and deallocation of objects.
314 */
315 class MemPool
316 {
317 public:
318  MemPool() {}
319  virtual ~MemPool() {}
320 
321  virtual int ItemSize() const = 0;
322  virtual void* Alloc() = 0;
323  virtual void Free( void* ) = 0;
324  virtual void SetTracked() = 0;
325  virtual void Clear() = 0;
326 };
327 
328 
329 /*
330  Template child class to create pools of the correct type.
331 */
332 template< int ITEM_SIZE >
333 class MemPoolT : public MemPool
334 {
335 public:
336  MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
337  ~MemPoolT() {
338  Clear();
339  }
340 
341  void Clear() {
342  // Delete the blocks.
343  while( !_blockPtrs.Empty()) {
344  Block* b = _blockPtrs.Pop();
345  delete b;
346  }
347  _root = 0;
348  _currentAllocs = 0;
349  _nAllocs = 0;
350  _maxAllocs = 0;
351  _nUntracked = 0;
352  }
353 
354  virtual int ItemSize() const {
355  return ITEM_SIZE;
356  }
357  int CurrentAllocs() const {
358  return _currentAllocs;
359  }
360 
361  virtual void* Alloc() {
362  if ( !_root ) {
363  // Need a new block.
364  Block* block = new Block();
365  _blockPtrs.Push( block );
366 
367  Item* blockItems = block->items;
368  for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
369  blockItems[i].next = &(blockItems[i + 1]);
370  }
371  blockItems[ITEMS_PER_BLOCK - 1].next = 0;
372  _root = blockItems;
373  }
374  Item* const result = _root;
375  TIXMLASSERT( result != 0 );
376  _root = _root->next;
377 
378  ++_currentAllocs;
379  if ( _currentAllocs > _maxAllocs ) {
380  _maxAllocs = _currentAllocs;
381  }
382  ++_nAllocs;
383  ++_nUntracked;
384  return result;
385  }
386 
387  virtual void Free( void* mem ) {
388  if ( !mem ) {
389  return;
390  }
391  --_currentAllocs;
392  Item* item = static_cast<Item*>( mem );
393 #ifdef DEBUG
394  memset( item, 0xfe, sizeof( *item ) );
395 #endif
396  item->next = _root;
397  _root = item;
398  }
399  void Trace( const char* name ) {
400  printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
401  name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
402  ITEM_SIZE, _nAllocs, _blockPtrs.Size() );
403  }
404 
405  void SetTracked() {
406  --_nUntracked;
407  }
408 
409  int Untracked() const {
410  return _nUntracked;
411  }
412 
413  // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
414  // The test file is large, 170k.
415  // Release: VS2010 gcc(no opt)
416  // 1k: 4000
417  // 2k: 4000
418  // 4k: 3900 21000
419  // 16k: 5200
420  // 32k: 4300
421  // 64k: 4000 21000
422  // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
423  // in private part if ITEMS_PER_BLOCK is private
424  enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
425 
426 private:
427  MemPoolT( const MemPoolT& ); // not supported
428  void operator=( const MemPoolT& ); // not supported
429 
430  union Item {
431  Item* next;
432  char itemData[ITEM_SIZE];
433  };
434  struct Block {
435  Item items[ITEMS_PER_BLOCK];
436  };
437  DynArray< Block*, 10 > _blockPtrs;
438  Item* _root;
439 
440  int _currentAllocs;
441  int _nAllocs;
442  int _maxAllocs;
443  int _nUntracked;
444 };
445 
446 
447 
467 class TINYXML2_LIB XMLVisitor
468 {
469 public:
470  virtual ~XMLVisitor() {}
471 
473  virtual bool VisitEnter( const XMLDocument& /*doc*/ ) {
474  return true;
475  }
477  virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
478  return true;
479  }
480 
482  virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) {
483  return true;
484  }
486  virtual bool VisitExit( const XMLElement& /*element*/ ) {
487  return true;
488  }
489 
491  virtual bool Visit( const XMLDeclaration& /*declaration*/ ) {
492  return true;
493  }
495  virtual bool Visit( const XMLText& /*text*/ ) {
496  return true;
497  }
499  virtual bool Visit( const XMLComment& /*comment*/ ) {
500  return true;
501  }
503  virtual bool Visit( const XMLUnknown& /*unknown*/ ) {
504  return true;
505  }
506 };
507 
508 // WARNING: must match XMLDocument::_errorNames[]
509 enum XMLError {
510  XML_SUCCESS = 0,
511  XML_NO_ATTRIBUTE,
512  XML_WRONG_ATTRIBUTE_TYPE,
513  XML_ERROR_FILE_NOT_FOUND,
514  XML_ERROR_FILE_COULD_NOT_BE_OPENED,
515  XML_ERROR_FILE_READ_ERROR,
516  UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version
517  XML_ERROR_PARSING_ELEMENT,
518  XML_ERROR_PARSING_ATTRIBUTE,
519  UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version
520  XML_ERROR_PARSING_TEXT,
521  XML_ERROR_PARSING_CDATA,
522  XML_ERROR_PARSING_COMMENT,
523  XML_ERROR_PARSING_DECLARATION,
524  XML_ERROR_PARSING_UNKNOWN,
525  XML_ERROR_EMPTY_DOCUMENT,
526  XML_ERROR_MISMATCHED_ELEMENT,
527  XML_ERROR_PARSING,
528  XML_CAN_NOT_CONVERT_TEXT,
529  XML_NO_TEXT_NODE,
530 
531  XML_ERROR_COUNT
532 };
533 
534 
535 /*
536  Utility functionality.
537 */
538 class TINYXML2_LIB XMLUtil
539 {
540 public:
541  static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) {
542  TIXMLASSERT( p );
543 
544  while( IsWhiteSpace(*p) ) {
545  if (curLineNumPtr && *p == '\n') {
546  ++(*curLineNumPtr);
547  }
548  ++p;
549  }
550  TIXMLASSERT( p );
551  return p;
552  }
553  static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) {
554  return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );
555  }
556 
557  // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
558  // correct, but simple, and usually works.
559  static bool IsWhiteSpace( char p ) {
560  return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
561  }
562 
563  inline static bool IsNameStartChar( unsigned char ch ) {
564  if ( ch >= 128 ) {
565  // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
566  return true;
567  }
568  if ( isalpha( ch ) ) {
569  return true;
570  }
571  return ch == ':' || ch == '_';
572  }
573 
574  inline static bool IsNameChar( unsigned char ch ) {
575  return IsNameStartChar( ch )
576  || isdigit( ch )
577  || ch == '.'
578  || ch == '-';
579  }
580 
581  inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
582  if ( p == q ) {
583  return true;
584  }
585  TIXMLASSERT( p );
586  TIXMLASSERT( q );
587  TIXMLASSERT( nChar >= 0 );
588  return strncmp( p, q, nChar ) == 0;
589  }
590 
591  inline static bool IsUTF8Continuation( char p ) {
592  return ( p & 0x80 ) != 0;
593  }
594 
595  static const char* ReadBOM( const char* p, bool* hasBOM );
596  // p is the starting location,
597  // the UTF-8 value of the entity will be placed in value, and length filled in.
598  static const char* GetCharacterRef( const char* p, char* value, int* length );
599  static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
600 
601  // converts primitive types to strings
602  static void ToStr( int v, char* buffer, int bufferSize );
603  static void ToStr( unsigned v, char* buffer, int bufferSize );
604  static void ToStr( bool v, char* buffer, int bufferSize );
605  static void ToStr( float v, char* buffer, int bufferSize );
606  static void ToStr( double v, char* buffer, int bufferSize );
607  static void ToStr(int64_t v, char* buffer, int bufferSize);
608 
609  // converts strings to primitive types
610  static bool ToInt( const char* str, int* value );
611  static bool ToUnsigned( const char* str, unsigned* value );
612  static bool ToBool( const char* str, bool* value );
613  static bool ToFloat( const char* str, float* value );
614  static bool ToDouble( const char* str, double* value );
615  static bool ToInt64(const char* str, int64_t* value);
616 
617  // Changes what is serialized for a boolean value.
618  // Default to "true" and "false". Shouldn't be changed
619  // unless you have a special testing or compatibility need.
620  // Be careful: static, global, & not thread safe.
621  // Be sure to set static const memory as parameters.
622  static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
623 
624 private:
625  static const char* writeBoolTrue;
626  static const char* writeBoolFalse;
627 };
628 
629 
655 class TINYXML2_LIB XMLNode
656 {
657  friend class XMLDocument;
658  friend class XMLElement;
659 public:
660 
662  const XMLDocument* GetDocument() const {
663  TIXMLASSERT( _document );
664  return _document;
665  }
668  TIXMLASSERT( _document );
669  return _document;
670  }
671 
673  virtual XMLElement* ToElement() {
674  return 0;
675  }
677  virtual XMLText* ToText() {
678  return 0;
679  }
681  virtual XMLComment* ToComment() {
682  return 0;
683  }
685  virtual XMLDocument* ToDocument() {
686  return 0;
687  }
690  return 0;
691  }
693  virtual XMLUnknown* ToUnknown() {
694  return 0;
695  }
696 
697  virtual const XMLElement* ToElement() const {
698  return 0;
699  }
700  virtual const XMLText* ToText() const {
701  return 0;
702  }
703  virtual const XMLComment* ToComment() const {
704  return 0;
705  }
706  virtual const XMLDocument* ToDocument() const {
707  return 0;
708  }
709  virtual const XMLDeclaration* ToDeclaration() const {
710  return 0;
711  }
712  virtual const XMLUnknown* ToUnknown() const {
713  return 0;
714  }
715 
725  const char* Value() const;
726 
730  void SetValue( const char* val, bool staticMem=false );
731 
733  int GetLineNum() const { return _parseLineNum; }
734 
736  const XMLNode* Parent() const {
737  return _parent;
738  }
739 
740  XMLNode* Parent() {
741  return _parent;
742  }
743 
745  bool NoChildren() const {
746  return !_firstChild;
747  }
748 
750  const XMLNode* FirstChild() const {
751  return _firstChild;
752  }
753 
754  XMLNode* FirstChild() {
755  return _firstChild;
756  }
757 
761  const XMLElement* FirstChildElement( const char* name = 0 ) const;
762 
763  XMLElement* FirstChildElement( const char* name = 0 ) {
764  return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
765  }
766 
768  const XMLNode* LastChild() const {
769  return _lastChild;
770  }
771 
772  XMLNode* LastChild() {
773  return _lastChild;
774  }
775 
779  const XMLElement* LastChildElement( const char* name = 0 ) const;
780 
781  XMLElement* LastChildElement( const char* name = 0 ) {
782  return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
783  }
784 
786  const XMLNode* PreviousSibling() const {
787  return _prev;
788  }
789 
790  XMLNode* PreviousSibling() {
791  return _prev;
792  }
793 
795  const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
796 
797  XMLElement* PreviousSiblingElement( const char* name = 0 ) {
798  return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
799  }
800 
802  const XMLNode* NextSibling() const {
803  return _next;
804  }
805 
806  XMLNode* NextSibling() {
807  return _next;
808  }
809 
811  const XMLElement* NextSiblingElement( const char* name = 0 ) const;
812 
813  XMLElement* NextSiblingElement( const char* name = 0 ) {
814  return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
815  }
816 
824  XMLNode* InsertEndChild( XMLNode* addThis );
825 
826  XMLNode* LinkEndChild( XMLNode* addThis ) {
827  return InsertEndChild( addThis );
828  }
836  XMLNode* InsertFirstChild( XMLNode* addThis );
845  XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
846 
850  void DeleteChildren();
851 
855  void DeleteChild( XMLNode* node );
856 
866  virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
867 
881  XMLNode* DeepClone( XMLDocument* target ) const;
882 
889  virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
890 
913  virtual bool Accept( XMLVisitor* visitor ) const = 0;
914 
920  void SetUserData(void* userData) { _userData = userData; }
921 
927  void* GetUserData() const { return _userData; }
928 
929 protected:
930  XMLNode( XMLDocument* );
931  virtual ~XMLNode();
932 
933  virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
934 
935  XMLDocument* _document;
936  XMLNode* _parent;
937  mutable StrPair _value;
938  int _parseLineNum;
939 
940  XMLNode* _firstChild;
941  XMLNode* _lastChild;
942 
943  XMLNode* _prev;
944  XMLNode* _next;
945 
946  void* _userData;
947 
948 private:
949  MemPool* _memPool;
950  void Unlink( XMLNode* child );
951  static void DeleteNode( XMLNode* node );
952  void InsertChildPreamble( XMLNode* insertThis ) const;
953  const XMLElement* ToElementWithName( const char* name ) const;
954 
955  XMLNode( const XMLNode& ); // not supported
956  XMLNode& operator=( const XMLNode& ); // not supported
957 };
958 
959 
972 class TINYXML2_LIB XMLText : public XMLNode
973 {
974  friend class XMLDocument;
975 public:
976  virtual bool Accept( XMLVisitor* visitor ) const;
977 
978  virtual XMLText* ToText() {
979  return this;
980  }
981  virtual const XMLText* ToText() const {
982  return this;
983  }
984 
986  void SetCData( bool isCData ) {
987  _isCData = isCData;
988  }
990  bool CData() const {
991  return _isCData;
992  }
993 
994  virtual XMLNode* ShallowClone( XMLDocument* document ) const;
995  virtual bool ShallowEqual( const XMLNode* compare ) const;
996 
997 protected:
998  XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
999  virtual ~XMLText() {}
1000 
1001  char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1002 
1003 private:
1004  bool _isCData;
1005 
1006  XMLText( const XMLText& ); // not supported
1007  XMLText& operator=( const XMLText& ); // not supported
1008 };
1009 
1010 
1012 class TINYXML2_LIB XMLComment : public XMLNode
1013 {
1014  friend class XMLDocument;
1015 public:
1016  virtual XMLComment* ToComment() {
1017  return this;
1018  }
1019  virtual const XMLComment* ToComment() const {
1020  return this;
1021  }
1022 
1023  virtual bool Accept( XMLVisitor* visitor ) const;
1024 
1025  virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1026  virtual bool ShallowEqual( const XMLNode* compare ) const;
1027 
1028 protected:
1029  XMLComment( XMLDocument* doc );
1030  virtual ~XMLComment();
1031 
1032  char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
1033 
1034 private:
1035  XMLComment( const XMLComment& ); // not supported
1036  XMLComment& operator=( const XMLComment& ); // not supported
1037 };
1038 
1039 
1051 class TINYXML2_LIB XMLDeclaration : public XMLNode
1052 {
1053  friend class XMLDocument;
1054 public:
1056  return this;
1057  }
1058  virtual const XMLDeclaration* ToDeclaration() const {
1059  return this;
1060  }
1061 
1062  virtual bool Accept( XMLVisitor* visitor ) const;
1063 
1064  virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1065  virtual bool ShallowEqual( const XMLNode* compare ) const;
1066 
1067 protected:
1068  XMLDeclaration( XMLDocument* doc );
1069  virtual ~XMLDeclaration();
1070 
1071  char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1072 
1073 private:
1074  XMLDeclaration( const XMLDeclaration& ); // not supported
1075  XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
1076 };
1077 
1078 
1086 class TINYXML2_LIB XMLUnknown : public XMLNode
1087 {
1088  friend class XMLDocument;
1089 public:
1090  virtual XMLUnknown* ToUnknown() {
1091  return this;
1092  }
1093  virtual const XMLUnknown* ToUnknown() const {
1094  return this;
1095  }
1096 
1097  virtual bool Accept( XMLVisitor* visitor ) const;
1098 
1099  virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1100  virtual bool ShallowEqual( const XMLNode* compare ) const;
1101 
1102 protected:
1103  XMLUnknown( XMLDocument* doc );
1104  virtual ~XMLUnknown();
1105 
1106  char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1107 
1108 private:
1109  XMLUnknown( const XMLUnknown& ); // not supported
1110  XMLUnknown& operator=( const XMLUnknown& ); // not supported
1111 };
1112 
1113 
1114 
1121 class TINYXML2_LIB XMLAttribute
1122 {
1123  friend class XMLElement;
1124 public:
1126  const char* Name() const;
1127 
1129  const char* Value() const;
1130 
1132  int GetLineNum() const { return _parseLineNum; }
1133 
1135  const XMLAttribute* Next() const {
1136  return _next;
1137  }
1138 
1143  int IntValue() const {
1144  int i = 0;
1145  QueryIntValue(&i);
1146  return i;
1147  }
1148 
1149  int64_t Int64Value() const {
1150  int64_t i = 0;
1151  QueryInt64Value(&i);
1152  return i;
1153  }
1154 
1156  unsigned UnsignedValue() const {
1157  unsigned i=0;
1158  QueryUnsignedValue( &i );
1159  return i;
1160  }
1162  bool BoolValue() const {
1163  bool b=false;
1164  QueryBoolValue( &b );
1165  return b;
1166  }
1168  double DoubleValue() const {
1169  double d=0;
1170  QueryDoubleValue( &d );
1171  return d;
1172  }
1174  float FloatValue() const {
1175  float f=0;
1176  QueryFloatValue( &f );
1177  return f;
1178  }
1179 
1184  XMLError QueryIntValue( int* value ) const;
1186  XMLError QueryUnsignedValue( unsigned int* value ) const;
1188  XMLError QueryInt64Value(int64_t* value) const;
1190  XMLError QueryBoolValue( bool* value ) const;
1192  XMLError QueryDoubleValue( double* value ) const;
1194  XMLError QueryFloatValue( float* value ) const;
1195 
1197  void SetAttribute( const char* value );
1199  void SetAttribute( int value );
1201  void SetAttribute( unsigned value );
1203  void SetAttribute(int64_t value);
1205  void SetAttribute( bool value );
1207  void SetAttribute( double value );
1209  void SetAttribute( float value );
1210 
1211 private:
1212  enum { BUF_SIZE = 200 };
1213 
1214  XMLAttribute() : _parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
1215  virtual ~XMLAttribute() {}
1216 
1217  XMLAttribute( const XMLAttribute& ); // not supported
1218  void operator=( const XMLAttribute& ); // not supported
1219  void SetName( const char* name );
1220 
1221  char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
1222 
1223  mutable StrPair _name;
1224  mutable StrPair _value;
1225  int _parseLineNum;
1226  XMLAttribute* _next;
1227  MemPool* _memPool;
1228 };
1229 
1230 
1235 class TINYXML2_LIB XMLElement : public XMLNode
1236 {
1237  friend class XMLDocument;
1238 public:
1240  const char* Name() const {
1241  return Value();
1242  }
1244  void SetName( const char* str, bool staticMem=false ) {
1245  SetValue( str, staticMem );
1246  }
1247 
1248  virtual XMLElement* ToElement() {
1249  return this;
1250  }
1251  virtual const XMLElement* ToElement() const {
1252  return this;
1253  }
1254  virtual bool Accept( XMLVisitor* visitor ) const;
1255 
1279  const char* Attribute( const char* name, const char* value=0 ) const;
1280 
1287  int IntAttribute(const char* name, int defaultValue = 0) const;
1289  unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
1291  int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
1293  bool BoolAttribute(const char* name, bool defaultValue = false) const;
1295  double DoubleAttribute(const char* name, double defaultValue = 0) const;
1297  float FloatAttribute(const char* name, float defaultValue = 0) const;
1298 
1312  XMLError QueryIntAttribute( const char* name, int* value ) const {
1313  const XMLAttribute* a = FindAttribute( name );
1314  if ( !a ) {
1315  return XML_NO_ATTRIBUTE;
1316  }
1317  return a->QueryIntValue( value );
1318  }
1319 
1321  XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
1322  const XMLAttribute* a = FindAttribute( name );
1323  if ( !a ) {
1324  return XML_NO_ATTRIBUTE;
1325  }
1326  return a->QueryUnsignedValue( value );
1327  }
1328 
1330  XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
1331  const XMLAttribute* a = FindAttribute(name);
1332  if (!a) {
1333  return XML_NO_ATTRIBUTE;
1334  }
1335  return a->QueryInt64Value(value);
1336  }
1337 
1339  XMLError QueryBoolAttribute( const char* name, bool* value ) const {
1340  const XMLAttribute* a = FindAttribute( name );
1341  if ( !a ) {
1342  return XML_NO_ATTRIBUTE;
1343  }
1344  return a->QueryBoolValue( value );
1345  }
1347  XMLError QueryDoubleAttribute( const char* name, double* value ) const {
1348  const XMLAttribute* a = FindAttribute( name );
1349  if ( !a ) {
1350  return XML_NO_ATTRIBUTE;
1351  }
1352  return a->QueryDoubleValue( value );
1353  }
1355  XMLError QueryFloatAttribute( const char* name, float* value ) const {
1356  const XMLAttribute* a = FindAttribute( name );
1357  if ( !a ) {
1358  return XML_NO_ATTRIBUTE;
1359  }
1360  return a->QueryFloatValue( value );
1361  }
1362 
1363 
1381  int QueryAttribute( const char* name, int* value ) const {
1382  return QueryIntAttribute( name, value );
1383  }
1384 
1385  int QueryAttribute( const char* name, unsigned int* value ) const {
1386  return QueryUnsignedAttribute( name, value );
1387  }
1388 
1389  int QueryAttribute(const char* name, int64_t* value) const {
1390  return QueryInt64Attribute(name, value);
1391  }
1392 
1393  int QueryAttribute( const char* name, bool* value ) const {
1394  return QueryBoolAttribute( name, value );
1395  }
1396 
1397  int QueryAttribute( const char* name, double* value ) const {
1398  return QueryDoubleAttribute( name, value );
1399  }
1400 
1401  int QueryAttribute( const char* name, float* value ) const {
1402  return QueryFloatAttribute( name, value );
1403  }
1404 
1406  void SetAttribute( const char* name, const char* value ) {
1407  XMLAttribute* a = FindOrCreateAttribute( name );
1408  a->SetAttribute( value );
1409  }
1411  void SetAttribute( const char* name, int value ) {
1412  XMLAttribute* a = FindOrCreateAttribute( name );
1413  a->SetAttribute( value );
1414  }
1416  void SetAttribute( const char* name, unsigned value ) {
1417  XMLAttribute* a = FindOrCreateAttribute( name );
1418  a->SetAttribute( value );
1419  }
1420 
1422  void SetAttribute(const char* name, int64_t value) {
1423  XMLAttribute* a = FindOrCreateAttribute(name);
1424  a->SetAttribute(value);
1425  }
1426 
1428  void SetAttribute( const char* name, bool value ) {
1429  XMLAttribute* a = FindOrCreateAttribute( name );
1430  a->SetAttribute( value );
1431  }
1433  void SetAttribute( const char* name, double value ) {
1434  XMLAttribute* a = FindOrCreateAttribute( name );
1435  a->SetAttribute( value );
1436  }
1438  void SetAttribute( const char* name, float value ) {
1439  XMLAttribute* a = FindOrCreateAttribute( name );
1440  a->SetAttribute( value );
1441  }
1442 
1446  void DeleteAttribute( const char* name );
1447 
1449  const XMLAttribute* FirstAttribute() const {
1450  return _rootAttribute;
1451  }
1453  const XMLAttribute* FindAttribute( const char* name ) const;
1454 
1483  const char* GetText() const;
1484 
1519  void SetText( const char* inText );
1521  void SetText( int value );
1523  void SetText( unsigned value );
1525  void SetText(int64_t value);
1527  void SetText( bool value );
1529  void SetText( double value );
1531  void SetText( float value );
1532 
1559  XMLError QueryIntText( int* ival ) const;
1561  XMLError QueryUnsignedText( unsigned* uval ) const;
1563  XMLError QueryInt64Text(int64_t* uval) const;
1565  XMLError QueryBoolText( bool* bval ) const;
1567  XMLError QueryDoubleText( double* dval ) const;
1569  XMLError QueryFloatText( float* fval ) const;
1570 
1571  int IntText(int defaultValue = 0) const;
1572 
1574  unsigned UnsignedText(unsigned defaultValue = 0) const;
1576  int64_t Int64Text(int64_t defaultValue = 0) const;
1578  bool BoolText(bool defaultValue = false) const;
1580  double DoubleText(double defaultValue = 0) const;
1582  float FloatText(float defaultValue = 0) const;
1583 
1584  // internal:
1585  enum ElementClosingType {
1586  OPEN, // <foo>
1587  CLOSED, // <foo/>
1588  CLOSING // </foo>
1589  };
1590  ElementClosingType ClosingType() const {
1591  return _closingType;
1592  }
1593  virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1594  virtual bool ShallowEqual( const XMLNode* compare ) const;
1595 
1596 protected:
1597  char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1598 
1599 private:
1600  XMLElement( XMLDocument* doc );
1601  virtual ~XMLElement();
1602  XMLElement( const XMLElement& ); // not supported
1603  void operator=( const XMLElement& ); // not supported
1604 
1605  XMLAttribute* FindAttribute( const char* name ) {
1606  return const_cast<XMLAttribute*>(const_cast<const XMLElement*>(this)->FindAttribute( name ));
1607  }
1608  XMLAttribute* FindOrCreateAttribute( const char* name );
1609  //void LinkAttribute( XMLAttribute* attrib );
1610  char* ParseAttributes( char* p, int* curLineNumPtr );
1611  static void DeleteAttribute( XMLAttribute* attribute );
1612  XMLAttribute* CreateAttribute();
1613 
1614  enum { BUF_SIZE = 200 };
1615  ElementClosingType _closingType;
1616  // The attribute list is ordered; there is no 'lastAttribute'
1617  // because the list needs to be scanned for dupes before adding
1618  // a new attribute.
1619  XMLAttribute* _rootAttribute;
1620 };
1621 
1622 
1623 enum Whitespace {
1624  PRESERVE_WHITESPACE,
1625  COLLAPSE_WHITESPACE
1626 };
1627 
1628 
1634 class TINYXML2_LIB XMLDocument : public XMLNode
1635 {
1636  friend class XMLElement;
1637 public:
1639  XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );
1640  ~XMLDocument();
1641 
1643  TIXMLASSERT( this == _document );
1644  return this;
1645  }
1646  virtual const XMLDocument* ToDocument() const {
1647  TIXMLASSERT( this == _document );
1648  return this;
1649  }
1650 
1661  XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) );
1662 
1668  XMLError LoadFile( const char* filename );
1669 
1681  XMLError LoadFile( FILE* );
1682 
1688  XMLError SaveFile( const char* filename, bool compact = false );
1689 
1697  XMLError SaveFile( FILE* fp, bool compact = false );
1698 
1699  bool ProcessEntities() const {
1700  return _processEntities;
1701  }
1702  Whitespace WhitespaceMode() const {
1703  return _whitespaceMode;
1704  }
1705 
1709  bool HasBOM() const {
1710  return _writeBOM;
1711  }
1714  void SetBOM( bool useBOM ) {
1715  _writeBOM = useBOM;
1716  }
1717 
1722  return FirstChildElement();
1723  }
1724  const XMLElement* RootElement() const {
1725  return FirstChildElement();
1726  }
1727 
1742  void Print( XMLPrinter* streamer=0 ) const;
1743  virtual bool Accept( XMLVisitor* visitor ) const;
1744 
1750  XMLElement* NewElement( const char* name );
1756  XMLComment* NewComment( const char* comment );
1762  XMLText* NewText( const char* text );
1774  XMLDeclaration* NewDeclaration( const char* text=0 );
1780  XMLUnknown* NewUnknown( const char* text );
1781 
1786  void DeleteNode( XMLNode* node );
1787 
1788  void SetError( XMLError error, const char* str1, const char* str2, int lineNum );
1789 
1790  void ClearError() {
1791  SetError(XML_SUCCESS, 0, 0, 0);
1792  }
1793 
1795  bool Error() const {
1796  return _errorID != XML_SUCCESS;
1797  }
1799  XMLError ErrorID() const {
1800  return _errorID;
1801  }
1802  const char* ErrorName() const;
1803  static const char* ErrorIDToName(XMLError errorID);
1804 
1806  const char* GetErrorStr1() const;
1807 
1809  const char* GetErrorStr2() const;
1810 
1812  int GetErrorLineNum() const
1813  {
1814  return _errorLineNum;
1815  }
1817  void PrintError() const;
1818 
1820  void Clear();
1821 
1829  void DeepCopy(XMLDocument* target);
1830 
1831  // internal
1832  char* Identify( char* p, XMLNode** node );
1833 
1834  // internal
1835  void MarkInUse(XMLNode*);
1836 
1837  virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
1838  return 0;
1839  }
1840  virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
1841  return false;
1842  }
1843 
1844 private:
1845  XMLDocument( const XMLDocument& ); // not supported
1846  void operator=( const XMLDocument& ); // not supported
1847 
1848  bool _writeBOM;
1849  bool _processEntities;
1850  XMLError _errorID;
1851  Whitespace _whitespaceMode;
1852  mutable StrPair _errorStr1;
1853  mutable StrPair _errorStr2;
1854  int _errorLineNum;
1855  char* _charBuffer;
1856  int _parseCurLineNum;
1857  // Memory tracking does add some overhead.
1858  // However, the code assumes that you don't
1859  // have a bunch of unlinked nodes around.
1860  // Therefore it takes less memory to track
1861  // in the document vs. a linked list in the XMLNode,
1862  // and the performance is the same.
1863  DynArray<XMLNode*, 10> _unlinked;
1864 
1865  MemPoolT< sizeof(XMLElement) > _elementPool;
1866  MemPoolT< sizeof(XMLAttribute) > _attributePool;
1867  MemPoolT< sizeof(XMLText) > _textPool;
1868  MemPoolT< sizeof(XMLComment) > _commentPool;
1869 
1870  static const char* _errorNames[XML_ERROR_COUNT];
1871 
1872  void Parse();
1873 
1874  template<class NodeType, int PoolElementSize>
1875  NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
1876 };
1877 
1878 template<class NodeType, int PoolElementSize>
1879 inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
1880 {
1881  TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
1882  TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );
1883  NodeType* returnNode = new (pool.Alloc()) NodeType( this );
1884  TIXMLASSERT( returnNode );
1885  returnNode->_memPool = &pool;
1886 
1887  _unlinked.Push(returnNode);
1888  return returnNode;
1889 }
1890 
1946 class TINYXML2_LIB XMLHandle
1947 {
1948 public:
1950  XMLHandle( XMLNode* node ) {
1951  _node = node;
1952  }
1954  XMLHandle( XMLNode& node ) {
1955  _node = &node;
1956  }
1958  XMLHandle( const XMLHandle& ref ) {
1959  _node = ref._node;
1960  }
1962  XMLHandle& operator=( const XMLHandle& ref ) {
1963  _node = ref._node;
1964  return *this;
1965  }
1966 
1969  return XMLHandle( _node ? _node->FirstChild() : 0 );
1970  }
1972  XMLHandle FirstChildElement( const char* name = 0 ) {
1973  return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
1974  }
1977  return XMLHandle( _node ? _node->LastChild() : 0 );
1978  }
1980  XMLHandle LastChildElement( const char* name = 0 ) {
1981  return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
1982  }
1985  return XMLHandle( _node ? _node->PreviousSibling() : 0 );
1986  }
1988  XMLHandle PreviousSiblingElement( const char* name = 0 ) {
1989  return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
1990  }
1993  return XMLHandle( _node ? _node->NextSibling() : 0 );
1994  }
1996  XMLHandle NextSiblingElement( const char* name = 0 ) {
1997  return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
1998  }
1999 
2002  return _node;
2003  }
2006  return ( _node ? _node->ToElement() : 0 );
2007  }
2010  return ( _node ? _node->ToText() : 0 );
2011  }
2014  return ( _node ? _node->ToUnknown() : 0 );
2015  }
2018  return ( _node ? _node->ToDeclaration() : 0 );
2019  }
2020 
2021 private:
2022  XMLNode* _node;
2023 };
2024 
2025 
2030 class TINYXML2_LIB XMLConstHandle
2031 {
2032 public:
2033  XMLConstHandle( const XMLNode* node ) {
2034  _node = node;
2035  }
2036  XMLConstHandle( const XMLNode& node ) {
2037  _node = &node;
2038  }
2039  XMLConstHandle( const XMLConstHandle& ref ) {
2040  _node = ref._node;
2041  }
2042 
2043  XMLConstHandle& operator=( const XMLConstHandle& ref ) {
2044  _node = ref._node;
2045  return *this;
2046  }
2047 
2048  const XMLConstHandle FirstChild() const {
2049  return XMLConstHandle( _node ? _node->FirstChild() : 0 );
2050  }
2051  const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
2052  return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
2053  }
2054  const XMLConstHandle LastChild() const {
2055  return XMLConstHandle( _node ? _node->LastChild() : 0 );
2056  }
2057  const XMLConstHandle LastChildElement( const char* name = 0 ) const {
2058  return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
2059  }
2060  const XMLConstHandle PreviousSibling() const {
2061  return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
2062  }
2063  const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
2064  return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
2065  }
2066  const XMLConstHandle NextSibling() const {
2067  return XMLConstHandle( _node ? _node->NextSibling() : 0 );
2068  }
2069  const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
2070  return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
2071  }
2072 
2073 
2074  const XMLNode* ToNode() const {
2075  return _node;
2076  }
2077  const XMLElement* ToElement() const {
2078  return ( _node ? _node->ToElement() : 0 );
2079  }
2080  const XMLText* ToText() const {
2081  return ( _node ? _node->ToText() : 0 );
2082  }
2083  const XMLUnknown* ToUnknown() const {
2084  return ( _node ? _node->ToUnknown() : 0 );
2085  }
2086  const XMLDeclaration* ToDeclaration() const {
2087  return ( _node ? _node->ToDeclaration() : 0 );
2088  }
2089 
2090 private:
2091  const XMLNode* _node;
2092 };
2093 
2094 
2137 class TINYXML2_LIB XMLPrinter : public XMLVisitor
2138 {
2139 public:
2146  XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
2147  virtual ~XMLPrinter() {}
2148 
2150  void PushHeader( bool writeBOM, bool writeDeclaration );
2154  void OpenElement( const char* name, bool compactMode=false );
2156  void PushAttribute( const char* name, const char* value );
2157  void PushAttribute( const char* name, int value );
2158  void PushAttribute( const char* name, unsigned value );
2159  void PushAttribute(const char* name, int64_t value);
2160  void PushAttribute( const char* name, bool value );
2161  void PushAttribute( const char* name, double value );
2163  virtual void CloseElement( bool compactMode=false );
2164 
2166  void PushText( const char* text, bool cdata=false );
2168  void PushText( int value );
2170  void PushText( unsigned value );
2172  void PushText(int64_t value);
2174  void PushText( bool value );
2176  void PushText( float value );
2178  void PushText( double value );
2179 
2181  void PushComment( const char* comment );
2182 
2183  void PushDeclaration( const char* value );
2184  void PushUnknown( const char* value );
2185 
2186  virtual bool VisitEnter( const XMLDocument& /*doc*/ );
2187  virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
2188  return true;
2189  }
2190 
2191  virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
2192  virtual bool VisitExit( const XMLElement& element );
2193 
2194  virtual bool Visit( const XMLText& text );
2195  virtual bool Visit( const XMLComment& comment );
2196  virtual bool Visit( const XMLDeclaration& declaration );
2197  virtual bool Visit( const XMLUnknown& unknown );
2198 
2203  const char* CStr() const {
2204  return _buffer.Mem();
2205  }
2211  int CStrSize() const {
2212  return _buffer.Size();
2213  }
2218  void ClearBuffer() {
2219  _buffer.Clear();
2220  _buffer.Push(0);
2221  _firstElement = true;
2222  }
2223 
2224 protected:
2225  virtual bool CompactMode( const XMLElement& ) { return _compactMode; }
2226 
2230  virtual void PrintSpace( int depth );
2231  void Print( const char* format, ... );
2232 
2233  void SealElementIfJustOpened();
2234  bool _elementJustOpened;
2235  DynArray< const char*, 10 > _stack;
2236 
2237 private:
2238  void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
2239 
2240  bool _firstElement;
2241  FILE* _fp;
2242  int _depth;
2243  int _textDepth;
2244  bool _processEntities;
2245  bool _compactMode;
2246 
2247  enum {
2248  ENTITY_RANGE = 64,
2249  BUF_SIZE = 200
2250  };
2251  bool _entityFlag[ENTITY_RANGE];
2252  bool _restrictedEntityFlag[ENTITY_RANGE];
2253 
2254  DynArray< char, 20 > _buffer;
2255 };
2256 
2257 
2258 } // tinyxml2
2259 
2260 #if defined(_MSC_VER)
2261 # pragma warning(pop)
2262 #endif
2263 
2264 #endif // TINYXML2_INCLUDED
XMLError QueryInt64Attribute(const char *name, int64_t *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1330
+
XMLError QueryIntValue(int *value) const
+
XMLError QueryBoolAttribute(const char *name, bool *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1339
+
virtual bool VisitExit(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:477
+
virtual XMLNode * ShallowClone(XMLDocument *) const
Definition: tinyxml2.h:1837
+
virtual bool ShallowEqual(const XMLNode *) const
Definition: tinyxml2.h:1840
+
XMLHandle FirstChildElement(const char *name=0)
Get the first child element of this handle.
Definition: tinyxml2.h:1972
+
XMLText * ToText()
Safe cast to XMLText. This can return null.
Definition: tinyxml2.h:2009
+
XMLError QueryFloatValue(float *value) const
See QueryIntValue.
+
const char * CStr() const
Definition: tinyxml2.h:2203
+
XMLError ErrorID() const
Return the errorID.
Definition: tinyxml2.h:1799
+
XMLElement * ToElement()
Safe cast to XMLElement. This can return null.
Definition: tinyxml2.h:2005
+
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:673
+
virtual XMLText * ToText()
Safely cast to Text, or null.
Definition: tinyxml2.h:677
+
XMLError QueryUnsignedAttribute(const char *name, unsigned int *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1321
+
int CStrSize() const
Definition: tinyxml2.h:2211
+
float FloatValue() const
Query as a float. See IntValue()
Definition: tinyxml2.h:1174
+
virtual XMLDocument * ToDocument()
Safely cast to a Document, or null.
Definition: tinyxml2.h:1642
+
XMLUnknown * ToUnknown()
Safe cast to XMLUnknown. This can return null.
Definition: tinyxml2.h:2013
+
const char * Name() const
Get the name of an element (which is the Value() of the node.)
Definition: tinyxml2.h:1240
+
XMLHandle(const XMLHandle &ref)
Copy constructor.
Definition: tinyxml2.h:1958
+
XMLHandle FirstChild()
Get the first child of this handle.
Definition: tinyxml2.h:1968
+
void SetCData(bool isCData)
Declare whether this should be CDATA or standard text.
Definition: tinyxml2.h:986
+
void SetUserData(void *userData)
Definition: tinyxml2.h:920
+
const XMLNode * NextSibling() const
Get the next (right) sibling node of this node.
Definition: tinyxml2.h:802
+
unsigned UnsignedValue() const
Query as an unsigned integer. See IntValue()
Definition: tinyxml2.h:1156
+
XMLHandle LastChildElement(const char *name=0)
Get the last child element of this handle.
Definition: tinyxml2.h:1980
+
XMLHandle LastChild()
Get the last child of this handle.
Definition: tinyxml2.h:1976
+
Definition: tinyxml2.h:1946
+
Definition: tinyxml2.h:1051
+
XMLElement * RootElement()
Definition: tinyxml2.h:1721
+
int QueryAttribute(const char *name, int *value) const
Definition: tinyxml2.h:1381
+
virtual XMLText * ToText()
Safely cast to Text, or null.
Definition: tinyxml2.h:978
+
XMLHandle(XMLNode &node)
Create a handle from a node.
Definition: tinyxml2.h:1954
+
void SetName(const char *str, bool staticMem=false)
Set the name of the element.
Definition: tinyxml2.h:1244
+
void SetBOM(bool useBOM)
Definition: tinyxml2.h:1714
+
XMLHandle(XMLNode *node)
Create a handle from any node (at any depth of the tree.) This can be a null pointer.
Definition: tinyxml2.h:1950
+
void ClearBuffer()
Definition: tinyxml2.h:2218
+
virtual XMLComment * ToComment()
Safely cast to a Comment, or null.
Definition: tinyxml2.h:1016
+
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:1248
+
bool HasBOM() const
Definition: tinyxml2.h:1709
+
Definition: tinyxml2.h:105
+
XMLError QueryFloatAttribute(const char *name, float *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1355
+
XMLError QueryUnsignedValue(unsigned int *value) const
See QueryIntValue.
+
XMLNode * ToNode()
Safe cast to XMLNode. This can return null.
Definition: tinyxml2.h:2001
+
bool BoolValue() const
Query as a boolean. See IntValue()
Definition: tinyxml2.h:1162
+
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:750
+
Definition: tinyxml2.h:1012
+
virtual XMLDeclaration * ToDeclaration()
Safely cast to a Declaration, or null.
Definition: tinyxml2.h:1055
+
virtual bool Visit(const XMLDeclaration &)
Visit a declaration.
Definition: tinyxml2.h:491
+
virtual bool Visit(const XMLUnknown &)
Visit an unknown node.
Definition: tinyxml2.h:503
+
void SetAttribute(const char *name, unsigned value)
Sets the named attribute to value.
Definition: tinyxml2.h:1416
+
XMLError QueryDoubleAttribute(const char *name, double *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1347
+
Definition: tinyxml2.h:1235
+
XMLError QueryInt64Value(int64_t *value) const
See QueryIntValue.
+
XMLHandle NextSibling()
Get the next sibling of this handle.
Definition: tinyxml2.h:1992
+
int GetLineNum() const
Gets the line number the attribute is in, if the document was parsed from a file. ...
Definition: tinyxml2.h:1132
+
int IntValue() const
Definition: tinyxml2.h:1143
+
virtual XMLUnknown * ToUnknown()
Safely cast to an Unknown, or null.
Definition: tinyxml2.h:1090
+
bool CData() const
Returns true if this is a CDATA text element.
Definition: tinyxml2.h:990
+
XMLHandle PreviousSibling()
Get the previous sibling of this handle.
Definition: tinyxml2.h:1984
+
Definition: tinyxml2.h:2030
+
XMLHandle & operator=(const XMLHandle &ref)
Assignment.
Definition: tinyxml2.h:1962
+
virtual bool VisitExit(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:2187
+
virtual bool VisitEnter(const XMLElement &, const XMLAttribute *)
Visit an element.
Definition: tinyxml2.h:482
+
bool Error() const
Return true if there was an error parsing the document.
Definition: tinyxml2.h:1795
+
virtual bool VisitEnter(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:473
+
Definition: tinyxml2.h:1086
+
virtual XMLDocument * ToDocument()
Safely cast to a Document, or null.
Definition: tinyxml2.h:685
+
const XMLNode * LastChild() const
Get the last child node, or null if none exists.
Definition: tinyxml2.h:768
+
Definition: tinyxml2.h:1121
+
void SetAttribute(const char *name, bool value)
Sets the named attribute to value.
Definition: tinyxml2.h:1428
+
XMLDeclaration * ToDeclaration()
Safe cast to XMLDeclaration. This can return null.
Definition: tinyxml2.h:2017
+
void SetAttribute(const char *value)
Set the attribute to a string value.
+
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
Definition: tinyxml2.h:1406
+
virtual bool VisitExit(const XMLElement &)
Visit an element.
Definition: tinyxml2.h:486
+
Definition: tinyxml2.h:2137
+
Definition: tinyxml2.h:1634
+
void * GetUserData() const
Definition: tinyxml2.h:927
+
int GetErrorLineNum() const
Return the line where the error occured, or zero if unknown.
Definition: tinyxml2.h:1812
+
void SetAttribute(const char *name, int64_t value)
Sets the named attribute to value.
Definition: tinyxml2.h:1422
+
void SetAttribute(const char *name, double value)
Sets the named attribute to value.
Definition: tinyxml2.h:1433
+
XMLError QueryDoubleValue(double *value) const
See QueryIntValue.
+
const XMLNode * Parent() const
Get the parent of this node on the DOM.
Definition: tinyxml2.h:736
+
virtual bool Visit(const XMLComment &)
Visit a comment node.
Definition: tinyxml2.h:499
+
XMLError QueryBoolValue(bool *value) const
See QueryIntValue.
+
const XMLNode * PreviousSibling() const
Get the previous (left) sibling node of this node.
Definition: tinyxml2.h:786
+
XMLHandle NextSiblingElement(const char *name=0)
Get the next sibling element of this handle.
Definition: tinyxml2.h:1996
+
Definition: tinyxml2.h:655
+
XMLError QueryIntAttribute(const char *name, int *value) const
Definition: tinyxml2.h:1312
+
int GetLineNum() const
Gets the line number the node is in, if the document was parsed from a file.
Definition: tinyxml2.h:733
+
virtual bool Visit(const XMLText &)
Visit a text node.
Definition: tinyxml2.h:495
+
Definition: tinyxml2.h:972
+
Definition: tinyxml2.h:467
+
XMLDocument * GetDocument()
Get the XMLDocument that owns this XMLNode.
Definition: tinyxml2.h:667
+
virtual XMLUnknown * ToUnknown()
Safely cast to an Unknown, or null.
Definition: tinyxml2.h:693
+
void SetAttribute(const char *name, float value)
Sets the named attribute to value.
Definition: tinyxml2.h:1438
+
const XMLAttribute * Next() const
The next attribute in the list.
Definition: tinyxml2.h:1135
+
bool NoChildren() const
Returns true if this node has no children.
Definition: tinyxml2.h:745
+
double DoubleValue() const
Query as a double. See IntValue()
Definition: tinyxml2.h:1168
+
virtual XMLDeclaration * ToDeclaration()
Safely cast to a Declaration, or null.
Definition: tinyxml2.h:689
+
const XMLDocument * GetDocument() const
Get the XMLDocument that owns this XMLNode.
Definition: tinyxml2.h:662
+
XMLHandle PreviousSiblingElement(const char *name=0)
Get the previous sibling element of this handle.
Definition: tinyxml2.h:1988
+
void SetAttribute(const char *name, int value)
Sets the named attribute to value.
Definition: tinyxml2.h:1411
+
const XMLAttribute * FirstAttribute() const
Return the first attribute in the list.
Definition: tinyxml2.h:1449
+
virtual XMLComment * ToComment()
Safely cast to a Comment, or null.
Definition: tinyxml2.h:681
+
+ + + + diff --git a/dox b/dox new file mode 100644 index 0000000..a4c6686 --- /dev/null +++ b/dox @@ -0,0 +1,2441 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "TinyXML-2" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 5.0.1 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = tinyxml2.h \ + xmltest.cpp \ + readme.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = . + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = readme.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = docs + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /
\n" + "...since I make symbolic puns" + "]]>" + ""; + XMLDocument doc; + doc.Parse( str ); + XMLTest( "CDATA symbolic puns round 2", false, doc.Error() ); + doc.Print(); + + XMLTest( "CDATA parse. [ tixml1:1480107 ]", + "I am > the rules!\n...since I make symbolic puns", + doc.FirstChildElement()->FirstChild()->Value(), + false ); + } + + // InsertAfterChild causes crash. + { + // InsertBeforeChild and InsertAfterChild causes crash. + XMLDocument doc; + XMLElement* parent = doc.NewElement( "Parent" ); + doc.InsertFirstChild( parent ); + + XMLElement* childText0 = doc.NewElement( "childText0" ); + XMLElement* childText1 = doc.NewElement( "childText1" ); + + XMLNode* childNode0 = parent->InsertEndChild( childText0 ); + XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 ); + + XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) ); + } + + { + // Entities not being written correctly. + // From Lynn Allen + + const char* passages = + "" + "" + " " + ""; + + XMLDocument doc; + doc.Parse( passages ); + XMLTest( "Entity transformation parse round 1", false, doc.Error() ); + XMLElement* psg = doc.RootElement()->FirstChildElement(); + const char* context = psg->Attribute( "context" ); + const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; + + XMLTest( "Entity transformation: read. ", expected, context, true ); + + FILE* textfile = fopen( "resources/out/textfile.txt", "w" ); + if ( textfile ) + { + XMLPrinter streamer( textfile ); + psg->Accept( &streamer ); + fclose( textfile ); + } + + textfile = fopen( "resources/out/textfile.txt", "r" ); + TIXMLASSERT( textfile ); + if ( textfile ) + { + char buf[ 1024 ]; + fgets( buf, 1024, textfile ); + XMLTest( "Entity transformation: write. ", + "\n", + buf, false ); + fclose( textfile ); + } + } + + { + // Suppress entities. + const char* passages = + "" + "" + "Crazy &ttk;" + ""; + + XMLDocument doc( false ); + doc.Parse( passages ); + XMLTest( "Entity transformation parse round 2", false, doc.Error() ); + + XMLTest( "No entity parsing.", + "Line 5 has "quotation marks" and 'apostrophe marks'.", + doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) ); + XMLTest( "No entity parsing.", "Crazy &ttk;", + doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() ); + doc.Print(); + } + + { + const char* test = ""; + + XMLDocument doc; + doc.Parse( test ); + XMLTest( "dot in names", false, doc.Error() ); + XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() ); + XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) ); + } + + { + const char* test = "1.1 Start easy ignore fin thickness "; + + XMLDocument doc; + doc.Parse( test ); + XMLTest( "fin thickness", false, doc.Error() ); + + XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); + XMLTest( "Entity with one digit.", + "1.1 Start easy ignore fin thickness\n", text->Value(), + false ); + } + + { + // DOCTYPE not preserved (950171) + // + const char* doctype = + "" + "" + "" + "" + ""; + + XMLDocument doc; + doc.Parse( doctype ); + XMLTest( "PLAY SYSTEM parse", false, doc.Error() ); + doc.SaveFile( "resources/out/test7.xml" ); + XMLTest( "PLAY SYSTEM save", false, doc.Error() ); + doc.DeleteChild( doc.RootElement() ); + doc.LoadFile( "resources/out/test7.xml" ); + XMLTest( "PLAY SYSTEM load", false, doc.Error() ); + doc.Print(); + + const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown(); + XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() ); + + } + + { + // Comments do not stream out correctly. + const char* doctype = + ""; + XMLDocument doc; + doc.Parse( doctype ); + XMLTest( "Comment somewhat evil", false, doc.Error() ); + + XMLComment* comment = doc.FirstChild()->ToComment(); + + XMLTest( "Comment formatting.", " Somewhat ", comment->Value() ); + } + { + // Double attributes + const char* doctype = ""; + + XMLDocument doc; + doc.Parse( doctype ); + + XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues) + doc.PrintError(); + } + + { + // Embedded null in stream. + const char* doctype = ""; + + XMLDocument doc; + doc.Parse( doctype ); + XMLTest( "Embedded null throws error.", true, doc.Error() ); + } + + { + // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717 + const char* str = ""; + XMLDocument doc; + doc.Parse( str ); + XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() ); + } + + { + // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717 + const char* str = " "; + XMLDocument doc; + doc.Parse( str ); + XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() ); + } + + { + // Low entities + XMLDocument doc; + doc.Parse( "" ); + XMLTest( "Hex values", false, doc.Error() ); + const char result[] = { 0x0e, 0 }; + XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() ); + doc.Print(); + } + + { + // Attribute values with trailing quotes not handled correctly + XMLDocument doc; + doc.Parse( "" ); + XMLTest( "Throw error with bad end quotes.", true, doc.Error() ); + } + + { + // [ 1663758 ] Failure to report error on bad XML + XMLDocument xml; + xml.Parse(""); + XMLTest("Missing end tag at end of input", true, xml.Error()); + xml.Parse(" "); + XMLTest("Missing end tag with trailing whitespace", true, xml.Error()); + xml.Parse(""); + XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() ); + } + + + { + // [ 1475201 ] TinyXML parses entities in comments + XMLDocument xml; + xml.Parse("" + "" ); + XMLTest( "Declarations for head and body", false, xml.Error() ); + + XMLNode* e0 = xml.FirstChild(); + XMLNode* e1 = e0->NextSibling(); + XMLComment* c0 = e0->ToComment(); + XMLComment* c1 = e1->ToComment(); + + XMLTest( "Comments ignore entities.", " declarations for & ", c0->Value(), true ); + XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); + } + + { + XMLDocument xml; + xml.Parse( "" + "" + "" + "" + "" ); + XMLTest( "Comments iteration", false, xml.Error() ); + xml.Print(); + + int count = 0; + + for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild(); + ele; + ele = ele->NextSibling() ) + { + ++count; + } + + XMLTest( "Comments iterate correctly.", 3, count ); + } + + { + // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well. + unsigned char buf[] = " " ); + XMLTest( "Handle end tag whitespace", false, xml.Error() ); + } + + { + // This one must not result in an infinite loop + XMLDocument xml; + xml.Parse( "loop" ); + XMLTest( "No closing element", true, xml.Error() ); + XMLTest( "Infinite loop test.", true, true ); + } +#endif + { + const char* pub = " "; + XMLDocument doc; + doc.Parse( pub ); + XMLTest( "Trailing DOCTYPE", false, doc.Error() ); + + XMLDocument clone; + for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) { + XMLNode* copy = node->ShallowClone( &clone ); + clone.InsertEndChild( copy ); + } + + clone.Print(); + + int count=0; + const XMLNode* a=clone.FirstChild(); + const XMLNode* b=doc.FirstChild(); + for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) { + ++count; + XMLTest( "Clone and Equal", true, a->ShallowEqual( b )); + } + XMLTest( "Clone and Equal", 4, count ); + } + + { + // Deep Cloning of root element. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + " " + " " + " Text" + ""; + XMLDocument doc; + doc.Parse(xml); + XMLTest( "Parse before deep cloning root element", false, doc.Error() ); + + doc.Print(&printer1); + XMLNode* root = doc.RootElement()->DeepClone(&doc2); + doc2.InsertFirstChild(root); + } + XMLPrinter printer2; + doc2.Print(&printer2); + + XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true); + } + + { + // Deep Cloning of sub element. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + "" + " " + " " + " Text" + ""; + XMLDocument doc; + doc.Parse(xml); + XMLTest( "Parse before deep cloning sub element", false, doc.Error() ); + + const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2"); + subElement->Accept(&printer1); + + XMLNode* clonedSubElement = subElement->DeepClone(&doc2); + doc2.InsertFirstChild(clonedSubElement); + } + XMLPrinter printer2; + doc2.Print(&printer2); + + XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true); + } + + { + // Deep cloning of document. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + "" + "" + " " + " " + " Text" + ""; + XMLDocument doc; + doc.Parse(xml); + XMLTest( "Parse before deep cloning document", false, doc.Error() ); + doc.Print(&printer1); + + doc.DeepCopy(&doc2); + } + XMLPrinter printer2; + doc2.Print(&printer2); + + XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true); + } + + + { + // This shouldn't crash. + XMLDocument doc; + if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" )) + { + doc.PrintError(); + } + XMLTest( "Error in snprinf handling.", true, doc.Error() ); + } + + { + // Attribute ordering. + static const char* xml = ""; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse for attribute ordering", false, doc.Error() ); + XMLElement* ele = doc.FirstChildElement(); + + const XMLAttribute* a = ele->FirstAttribute(); + XMLTest( "Attribute order", "1", a->Value() ); + a = a->Next(); + XMLTest( "Attribute order", "2", a->Value() ); + a = a->Next(); + XMLTest( "Attribute order", "3", a->Value() ); + XMLTest( "Attribute order", "attrib3", a->Name() ); + + ele->DeleteAttribute( "attrib2" ); + a = ele->FirstAttribute(); + XMLTest( "Attribute order", "1", a->Value() ); + a = a->Next(); + XMLTest( "Attribute order", "3", a->Value() ); + + ele->DeleteAttribute( "attrib1" ); + ele->DeleteAttribute( "attrib3" ); + XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false ); + } + + { + // Make sure an attribute with a space in it succeeds. + static const char* xml0 = ""; + static const char* xml1 = ""; + static const char* xml2 = ""; + XMLDocument doc0; + doc0.Parse( xml0 ); + XMLTest( "Parse attribute with space 1", false, doc0.Error() ); + XMLDocument doc1; + doc1.Parse( xml1 ); + XMLTest( "Parse attribute with space 2", false, doc1.Error() ); + XMLDocument doc2; + doc2.Parse( xml2 ); + XMLTest( "Parse attribute with space 3", false, doc2.Error() ); + + XMLElement* ele = 0; + ele = doc0.FirstChildElement(); + XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) ); + ele = doc1.FirstChildElement(); + XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) ); + ele = doc2.FirstChildElement(); + XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) ); + } + + { + // Make sure we don't go into an infinite loop. + static const char* xml = ""; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse two elements with attribute", false, doc.Error() ); + XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement(); + XMLElement* ele1 = ele0->NextSiblingElement(); + bool equal = ele0->ShallowEqual( ele1 ); + + XMLTest( "Infinite loop in shallow equal.", true, equal ); + } + + // -------- Handles ------------ + { + static const char* xml = "Text"; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() ); + + XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement(); + XMLTest( "Handle, success, mutable", "sub", ele->Value() ); + + XMLHandle docH( doc ); + ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement(); + XMLTest( "Handle, dne, mutable", false, ele != 0 ); + } + + { + static const char* xml = "Text"; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() ); + XMLConstHandle docH( doc ); + + const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement(); + XMLTest( "Handle, success, const", ele->Value(), "sub" ); + + ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement(); + XMLTest( "Handle, dne, const", false, ele != 0 ); + } + { + // Default Declaration & BOM + XMLDocument doc; + doc.InsertEndChild( doc.NewDeclaration() ); + doc.SetBOM( true ); + + XMLPrinter printer; + doc.Print( &printer ); + + static const char* result = "\xef\xbb\xbf"; + XMLTest( "BOM and default declaration", result, printer.CStr(), false ); + XMLTest( "CStrSize", 42, printer.CStrSize(), false ); + } + { + const char* xml = " This \nis ' text ' " + " This is ' text ' \n" + "This is ' \n\n text '" + ""; + XMLDocument doc( true, COLLAPSE_WHITESPACE ); + doc.Parse( xml ); + XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() ); + + const XMLElement* element = doc.FirstChildElement(); + for( const XMLElement* parent = element->FirstChildElement(); + parent; + parent = parent->NextSiblingElement() ) + { + XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() ); + } + } + +#if 0 + { + // Passes if assert doesn't fire. + XMLDocument xmlDoc; + + xmlDoc.NewDeclaration(); + xmlDoc.NewComment("Configuration file"); + + XMLElement *root = xmlDoc.NewElement("settings"); + root->SetAttribute("version", 2); + } +#endif + + { + const char* xml = " "; + XMLDocument doc( true, COLLAPSE_WHITESPACE ); + doc.Parse( xml ); + XMLTest( "Parse with all whitespaces", false, doc.Error() ); + XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() ); + } + + { + // An assert should not fire. + const char* xml = ""; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse with self-closed element", false, doc.Error() ); + XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope. + XMLTest( "Tracking unused elements", true, ele != 0, false ); + } + + + { + const char* xml = "abc"; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse for printing of sub-element", false, doc.Error() ); + XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child"); + + XMLPrinter printer; + ele->Accept( &printer ); + XMLTest( "Printing of sub-element", "abc\n", printer.CStr(), false ); + } + + + { + XMLDocument doc; + XMLError error = doc.LoadFile( "resources/empty.xml" ); + XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error ); + XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() ); + doc.PrintError(); + } + + { + // BOM preservation + static const char* xml_bom_preservation = "\xef\xbb\xbf\n"; + { + XMLDocument doc; + XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false ); + XMLPrinter printer; + doc.Print( &printer ); + + XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); + doc.SaveFile( "resources/bomtest.xml" ); + XMLTest( "Save bomtest.xml", false, doc.Error() ); + } + { + XMLDocument doc; + doc.LoadFile( "resources/bomtest.xml" ); + XMLTest( "Load bomtest.xml", false, doc.Error() ); + XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false ); + + XMLPrinter printer; + doc.Print( &printer ); + XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); + } + } + + { + // Insertion with Removal + const char* xml = "" + "" + "" + "" + "element 1text" + "" + "" + "" + ""; + const char* xmlInsideTwo = "" + "" + "" + "" + "" + "element 1text" + "" + "" + ""; + const char* xmlAfterOne = "" + "" + "" + "" + "element 1text" + "" + "" + ""; + const char* xmlAfterTwo = "" + "" + "" + "" + "" + "element 1text" + "" + ""; + + XMLDocument doc; + doc.Parse(xml); + XMLTest( "Insertion with removal parse round 1", false, doc.Error() ); + XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); + XMLElement* two = doc.RootElement()->FirstChildElement("two"); + two->InsertFirstChild(subtree); + XMLPrinter printer1(0, true); + doc.Accept(&printer1); + XMLTest("Move node from within to ", xmlInsideTwo, printer1.CStr()); + + doc.Parse(xml); + XMLTest( "Insertion with removal parse round 2", false, doc.Error() ); + subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); + two = doc.RootElement()->FirstChildElement("two"); + doc.RootElement()->InsertAfterChild(two, subtree); + XMLPrinter printer2(0, true); + doc.Accept(&printer2); + XMLTest("Move node from within after ", xmlAfterTwo, printer2.CStr(), false); + + doc.Parse(xml); + XMLTest( "Insertion with removal parse round 3", false, doc.Error() ); + XMLNode* one = doc.RootElement()->FirstChildElement("one"); + subtree = one->FirstChildElement("subtree"); + doc.RootElement()->InsertAfterChild(one, subtree); + XMLPrinter printer3(0, true); + doc.Accept(&printer3); + XMLTest("Move node from within after ", xmlAfterOne, printer3.CStr(), false); + + doc.Parse(xml); + XMLTest( "Insertion with removal parse round 4", false, doc.Error() ); + subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); + two = doc.RootElement()->FirstChildElement("two"); + doc.RootElement()->InsertEndChild(subtree); + XMLPrinter printer4(0, true); + doc.Accept(&printer4); + XMLTest("Move node from within after ", xmlAfterTwo, printer4.CStr(), false); + } + + { + const char* xml = "" + " " + ""; + XMLDocument doc; + doc.Parse(xml); + XMLTest( "Parse svg with text", false, doc.Error() ); + doc.Print(); + } + + { + // Test that it doesn't crash. + const char* xml = "<12"; + XMLDocument doc; + doc.Parse(xml); + XMLTest( "Parse root-sample-field0", true, doc.Error() ); + doc.PrintError(); + } + +#if 1 + // the question being explored is what kind of print to use: + // https://github.com/leethomason/tinyxml2/issues/63 + { + //const char* xml = ""; + const char* xml = ""; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse self-closed empty element", false, doc.Error() ); + doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 ); + doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 ); + doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 ); + doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 ); + doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 ); + doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 ); + + doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f ); + doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f ); + doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f ); + doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f ); + doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f ); + doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f ); + + doc.Print(); + + /* The result of this test is platform, compiler, and library version dependent. :(" + XMLPrinter printer; + doc.Print( &printer ); + XMLTest( "Float and double formatting.", + "\n", + printer.CStr(), + true ); + */ + } +#endif + + { + // Issue #184 + // If it doesn't assert, it passes. Caused by objects + // getting created during parsing which are then + // inaccessible in the memory pools. + const char* xmlText = ""; + { + XMLDocument doc; + doc.Parse(xmlText); + XMLTest( "Parse hex no closing tag round 1", true, doc.Error() ); + } + { + XMLDocument doc; + doc.Parse(xmlText); + XMLTest( "Parse hex no closing tag round 2", true, doc.Error() ); + doc.Clear(); + } + } + + { + // If this doesn't assert in DEBUG, all is well. + tinyxml2::XMLDocument doc; + tinyxml2::XMLElement *pRoot = doc.NewElement("Root"); + doc.DeleteNode(pRoot); + } + + { + XMLDocument doc; + XMLElement* root = doc.NewElement( "Root" ); + XMLTest( "Node document before insertion", true, &doc == root->GetDocument() ); + doc.InsertEndChild( root ); + XMLTest( "Node document after insertion", true, &doc == root->GetDocument() ); + } + + { + // If this doesn't assert in DEBUG, all is well. + XMLDocument doc; + XMLElement* unlinkedRoot = doc.NewElement( "Root" ); + XMLElement* linkedRoot = doc.NewElement( "Root" ); + doc.InsertFirstChild( linkedRoot ); + unlinkedRoot->GetDocument()->DeleteNode( linkedRoot ); + unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot ); + } + + { + // Should not assert in DEBUG + XMLPrinter printer; + } + + { + // Issue 291. Should not crash + const char* xml = "�"; + XMLDocument doc; + doc.Parse( xml ); + XMLTest( "Parse hex with closing tag", false, doc.Error() ); + + XMLPrinter printer; + doc.Print( &printer ); + } + { + // Issue 299. Can print elements that are not linked in. + // Will crash if issue not fixed. + XMLDocument doc; + XMLElement* newElement = doc.NewElement( "printme" ); + XMLPrinter printer; + newElement->Accept( &printer ); + // Delete the node to avoid possible memory leak report in debug output + doc.DeleteNode( newElement ); + } + { + // Issue 302. Clear errors from LoadFile/SaveFile + XMLDocument doc; + XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() ); + doc.SaveFile( "./no/such/path/pretty.xml" ); + XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() ); + doc.SaveFile( "./resources/out/compact.xml", true ); + XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() ); + } + + { + // If a document fails to load then subsequent + // successful loads should clear the error + XMLDocument doc; + XMLTest( "Should be no error initially", false, doc.Error() ); + doc.LoadFile( "resources/no-such-file.xml" ); + XMLTest( "No such file - should fail", true, doc.Error() ); + + doc.LoadFile( "resources/dream.xml" ); + XMLTest( "Error should be cleared", false, doc.Error() ); + } + + { + // Check that declarations are allowed only at beginning of document + const char* xml0 = "" + " " + ""; + const char* xml1 = "" + "" + ""; + const char* xml2 = "" + ""; + const char* xml3 = "" + ""; + + const char* xml4 = ""; + + XMLDocument doc; + doc.Parse(xml0); + XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() ); + doc.Parse(xml1); + XMLTest("Test that the second declaration is allowed", false, doc.Error() ); + doc.Parse(xml2); + XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() ); + doc.Parse(xml3); + XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() ); + doc.Parse(xml4); + XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() ); + } + + { + // No matter - before or after successfully parsing a text - + // calling XMLDocument::Value() causes an assert in debug. + const char* validXml = "" + "" + ""; + XMLDocument* doc = new XMLDocument(); + XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() ); + doc->Parse( validXml ); + XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error()); + XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() ); + delete doc; + } + + { + XMLDocument doc; + for( int i = 0; i < XML_ERROR_COUNT; i++ ) { + doc.SetError( (XMLError)i, 0, 0, 0 ); + doc.ErrorName(); + } + } + + { + // Evil memory leaks. + // If an XMLElement (etc) is allocated via NewElement() (etc.) + // and NOT added to the XMLDocument, what happens? + // + // Previously (buggy): + // The memory would be free'd when the XMLDocument is + // destructed. But the destructor wasn't called, so that + // memory allocated by the XMLElement would not be free'd. + // In practice this meant strings allocated by the XMLElement + // would leak. An edge case, but annoying. + // Now: + // The destructor is called. But the list of unlinked nodes + // has to be tracked. This has a minor performance impact + // that can become significant if you have a lot. (But why + // would you do that?) + // The only way to see this bug is in a leak tracker. This + // is compiled in by default on Windows Debug. + { + XMLDocument doc; + doc.NewElement("LEAK 1"); + } + { + XMLDocument doc; + XMLElement* ele = doc.NewElement("LEAK 2"); + doc.DeleteNode(ele); + } + } + + { + // Crashing reported via email. + const char* xml = + "" + "voice" + "1" + "" + "" + "" + "" + "" + "" + "" + ""; + + // It's not a good idea to delete elements as you walk the + // list. I'm not sure this technically should work; but it's + // an interesting test case. + XMLDocument doc; + XMLError err = doc.Parse(xml); + XMLTest("Crash bug parsing", XML_SUCCESS, err ); + + XMLElement* playlist = doc.FirstChildElement("playlist"); + XMLTest("Crash bug parsing", true, playlist != 0); + + tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry"); + XMLTest("Crash bug parsing", true, entry != 0); + while (entry) { + tinyxml2::XMLElement* todelete = entry; + entry = entry->NextSiblingElement("entry"); + playlist->DeleteChild(todelete); + }; + tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank"); + while (blank) { + tinyxml2::XMLElement* todelete = blank; + blank = blank->NextSiblingElement("blank"); + playlist->DeleteChild(todelete); + }; + + tinyxml2::XMLPrinter printer; + playlist->Accept(&printer); + printf("%s\n", printer.CStr()); + + // No test; it only need to not crash. + // Still, wrap it up with a sanity check + int nProperty = 0; + for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) { + nProperty++; + } + XMLTest("Crash bug parsing", 2, nProperty); + } + + // ----------- Line Number Tracking -------------- + { + struct TestUtil: XMLVisitor + { + void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine) + { + XMLDocument doc; + XMLError err = doc.Parse(docStr); + + XMLTest(testString, true, doc.Error()); + XMLTest(testString, expected_error, err); + XMLTest(testString, expectedLine, doc.GetErrorLineNum()); + }; + + void TestStringLines(const char *testString, const char *docStr, const char *expectedLines) + { + XMLDocument doc; + doc.Parse(docStr); + XMLTest(testString, false, doc.Error()); + TestDocLines(testString, doc, expectedLines); + } + + void TestFileLines(const char *testString, const char *file_name, const char *expectedLines) + { + XMLDocument doc; + doc.LoadFile(file_name); + XMLTest(testString, false, doc.Error()); + TestDocLines(testString, doc, expectedLines); + } + + private: + DynArray str; + + void Push(char type, int lineNum) + { + str.Push(type); + str.Push(char('0' + (lineNum / 10))); + str.Push(char('0' + (lineNum % 10))); + } + + bool VisitEnter(const XMLDocument& doc) + { + Push('D', doc.GetLineNum()); + return true; + } + bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute) + { + Push('E', element.GetLineNum()); + for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next()) + Push('A', attr->GetLineNum()); + return true; + } + bool Visit(const XMLDeclaration& declaration) + { + Push('L', declaration.GetLineNum()); + return true; + } + bool Visit(const XMLText& text) + { + Push('T', text.GetLineNum()); + return true; + } + bool Visit(const XMLComment& comment) + { + Push('C', comment.GetLineNum()); + return true; + } + bool Visit(const XMLUnknown& unknown) + { + Push('U', unknown.GetLineNum()); + return true; + } + + void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines) + { + str.Clear(); + doc.Accept(this); + str.Push(0); + XMLTest(testString, expectedLines, str.Mem()); + } + } tester; + + tester.TestParseError("ErrorLine-Parsing", "\n\n foo \n", XML_ERROR_PARSING, 2); + tester.TestParseError("ErrorLine-Declaration", "\n", XML_ERROR_PARSING_DECLARATION, 2); + tester.TestParseError("ErrorLine-Mismatch", "\n\n", XML_ERROR_MISMATCHED_ELEMENT, 2); + tester.TestParseError("ErrorLine-CData", "\n\n foo bar \n", XML_ERROR_PARSING_TEXT, 3); + tester.TestParseError("ErrorLine-Comment", "\n\n\n" // 6 Comment + "", // 7 Unknown + + "D01L01E02A02A03T03E03T04E05T05C06U07"); + + tester.TestStringLines( + "LineNumbers-CRLF", + + "\r\n" // 1 Doc (arguably should be line 2) + "\n" // 2 DecL + "\r\n" // 3 Element + "\n" // 4 + "text contining new line \n" // 5 Text + " and also containing crlf \r\n" // 6 + "", // 10 Element + + "D01L02E03T05E07T07E10"); + + tester.TestFileLines( + "LineNumbers-File", + "resources/utf8test.xml", + "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10"); + } + + // ----------- Performance tracking -------------- + { +#if defined( _MSC_VER ) + __int64 start, end, freq; + QueryPerformanceFrequency((LARGE_INTEGER*)&freq); +#endif + + FILE* perfFP = fopen("resources/dream.xml", "r"); + XMLTest("Open dream.xml", true, perfFP != 0); + fseek(perfFP, 0, SEEK_END); + long size = ftell(perfFP); + fseek(perfFP, 0, SEEK_SET); + + char* mem = new char[size + 1]; + memset(mem, 0xfe, size); + size_t bytesRead = fread(mem, 1, size, perfFP); + XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead)); + fclose(perfFP); + mem[size] = 0; + +#if defined( _MSC_VER ) + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#else + clock_t cstart = clock(); +#endif + bool parseDreamXmlFailed = false; + static const int COUNT = 10; + for (int i = 0; i < COUNT; ++i) { + XMLDocument doc; + doc.Parse(mem); + parseDreamXmlFailed = parseDreamXmlFailed || doc.Error(); + } + XMLTest( "Parse dream.xml", false, parseDreamXmlFailed ); +#if defined( _MSC_VER ) + QueryPerformanceCounter((LARGE_INTEGER*)&end); +#else + clock_t cend = clock(); +#endif + + delete[] mem; + + static const char* note = +#ifdef DEBUG + "DEBUG"; +#else + "Release"; +#endif + +#if defined( _MSC_VER ) + const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT); +#else + const double duration = (double)(cend - cstart) / (double)COUNT; +#endif + printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration); + } + +#if defined( _MSC_VER ) && defined( DEBUG ) + { + _CrtMemCheckpoint( &endMemState ); + + _CrtMemState diffMemState; + _CrtMemDifference( &diffMemState, &startMemState, &endMemState ); + _CrtMemDumpStatistics( &diffMemState ); + + { + int leaksBeforeExit = _CrtDumpMemoryLeaks(); + XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit ); + } + } +#endif + + printf ("\nPass %d, Fail %d\n", gPass, gFail); + + return gFail; +} From 59d74aea1f11cd1fb0df3e1dea97f731bfd21dd0 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 5 Aug 2017 23:23:41 -0700 Subject: [PATCH 09/25] Squashed 'vendor/github.com/muflihun/easyloggingpp/' content from commit 850ea2a9 git-subtree-dir: vendor/github.com/muflihun/easyloggingpp git-subtree-split: 850ea2a9f151ed648a989dda1cf44e503e45831f --- .gitignore | 9 + .travis.yml | 35 + CHANGELOG.md | 45 + CMakeLists.txt | 87 + LICENCE | 24 + PULL_REQUEST_TEMPLATE.md | 12 + README.md | 1435 + cmake/FindEASYLOGGINGPP.cmake | 38 + cmake/Findgtest.cmake | 159 + doc/RELEASE-NOTES-v9.00 | 58 + doc/RELEASE-NOTES-v9.01 | 22 + doc/RELEASE-NOTES-v9.02 | 15 + doc/RELEASE-NOTES-v9.03 | 15 + doc/RELEASE-NOTES-v9.04 | 10 + doc/RELEASE-NOTES-v9.05 | 22 + doc/RELEASE-NOTES-v9.06 | 22 + doc/RELEASE-NOTES-v9.07 | 20 + doc/RELEASE-NOTES-v9.08 | 16 + doc/RELEASE-NOTES-v9.09 | 28 + doc/RELEASE-NOTES-v9.10 | 16 + doc/RELEASE-NOTES-v9.11 | 25 + doc/RELEASE-NOTES-v9.12 | 25 + doc/RELEASE-NOTES-v9.13 | 22 + doc/RELEASE-NOTES-v9.14 | 16 + doc/RELEASE-NOTES-v9.15 | 16 + doc/RELEASE-NOTES-v9.16 | 17 + doc/RELEASE-NOTES-v9.17 | 22 + doc/RELEASE-NOTES-v9.18 | 27 + doc/RELEASE-NOTES-v9.19 | 17 + doc/RELEASE-NOTES-v9.20 | 18 + doc/RELEASE-NOTES-v9.21 | 29 + doc/RELEASE-NOTES-v9.22 | 15 + doc/RELEASE-NOTES-v9.23 | 27 + doc/RELEASE-NOTES-v9.24 | 23 + doc/RELEASE-NOTES-v9.25 | 39 + doc/RELEASE-NOTES-v9.26 | 25 + doc/RELEASE-NOTES-v9.27 | 15 + doc/RELEASE-NOTES-v9.28 | 15 + doc/RELEASE-NOTES-v9.29 | 15 + doc/RELEASE-NOTES-v9.30 | 21 + doc/RELEASE-NOTES-v9.31 | 15 + doc/RELEASE-NOTES-v9.32 | 21 + doc/RELEASE-NOTES-v9.33 | 15 + doc/RELEASE-NOTES-v9.34 | 16 + doc/RELEASE-NOTES-v9.35 | 15 + doc/RELEASE-NOTES-v9.36 | 22 + doc/RELEASE-NOTES-v9.37 | 15 + doc/RELEASE-NOTES-v9.38 | 15 + doc/RELEASE-NOTES-v9.39 | 15 + doc/RELEASE-NOTES-v9.40 | 23 + doc/RELEASE-NOTES-v9.41 | 15 + doc/RELEASE-NOTES-v9.42 | 16 + doc/RELEASE-NOTES-v9.43 | 21 + doc/RELEASE-NOTES-v9.44 | 15 + doc/RELEASE-NOTES-v9.45 | 15 + doc/RELEASE-NOTES-v9.46 | 15 + doc/RELEASE-NOTES-v9.47 | 22 + doc/RELEASE-NOTES-v9.48 | 11 + doc/RELEASE-NOTES-v9.49 | 15 + doc/RELEASE-NOTES-v9.50 | 15 + doc/RELEASE-NOTES-v9.51 | 15 + doc/RELEASE-NOTES-v9.52 | 15 + doc/RELEASE-NOTES-v9.53 | 15 + doc/RELEASE-NOTES-v9.54 | 15 + doc/RELEASE-NOTES-v9.55 | 15 + doc/RELEASE-NOTES-v9.56 | 24 + doc/RELEASE-NOTES-v9.57 | 15 + doc/RELEASE-NOTES-v9.58 | 24 + doc/RELEASE-NOTES-v9.59 | 33 + doc/RELEASE-NOTES-v9.60 | 32 + doc/RELEASE-NOTES-v9.61 | 24 + doc/RELEASE-NOTES-v9.62 | 18 + doc/RELEASE-NOTES-v9.63 | 18 + doc/RELEASE-NOTES-v9.64 | 56 + doc/RELEASE-NOTES-v9.65 | 19 + doc/RELEASE-NOTES-v9.66 | 25 + doc/RELEASE-NOTES-v9.67 | 20 + doc/RELEASE-NOTES-v9.68 | 19 + doc/RELEASE-NOTES-v9.69 | 20 + doc/RELEASE-NOTES-v9.70 | 28 + doc/RELEASE-NOTES-v9.71 | 19 + doc/RELEASE-NOTES-v9.72 | 19 + doc/RELEASE-NOTES-v9.73 | 19 + doc/RELEASE-NOTES-v9.74 | 27 + doc/RELEASE-NOTES-v9.75 | 22 + doc/RELEASE-NOTES-v9.76 | 27 + doc/RELEASE-NOTES-v9.77 | 33 + doc/RELEASE-NOTES-v9.78 | 36 + doc/RELEASE-NOTES-v9.79 | 71 + doc/RELEASE-NOTES-v9.80 | 15 + doc/RELEASE-NOTES-v9.81 | 37 + doc/RELEASE-NOTES-v9.82 | 19 + doc/RELEASE-NOTES-v9.83 | 14 + doc/RELEASE-NOTES-v9.84 | 14 + doc/RELEASE-NOTES-v9.85 | 32 + doc/RELEASE-NOTES-v9.86 | 29 + doc/RELEASE-NOTES-v9.87 | 20 + doc/RELEASE-NOTES-v9.88 | 21 + doc/RELEASE-NOTES-v9.89 | 20 + doc/RELEASE-NOTES-v9.90 | 34 + doc/RELEASE-NOTES-v9.91 | 21 + doc/RELEASE-NOTES-v9.92 | 15 + doc/RELEASE-NOTES-v9.93 | 28 + doc/RELEASE-NOTES-v9.94 | 29 + samples/.gitignore | 1 + samples/API/.gitignore | 2 + samples/API/build_all.sh | 15 + samples/API/compile.sh | 35 + samples/API/easylogging++.cc | 1 + samples/API/easylogging++.h | 5 + samples/API/logbuilder.cpp | 33 + samples/API/run.sh | 4 + samples/API/run_all.sh | 3 + samples/MinGW/.gitignore | 2 + samples/MinGW/compile.bat | 5 + samples/MinGW/easylogging++.cc | 1 + samples/MinGW/easylogging++.h | 5 + samples/MinGW/prog.cpp | 21 + samples/OpenGL/.gitignore | 2 + samples/OpenGL/Cube/.gitignore | 2 + samples/OpenGL/Cube/LICENCE | 21 + samples/OpenGL/Cube/Makefile | 19 + samples/OpenGL/Cube/imageloader.cpp | 188 + samples/OpenGL/Cube/imageloader.h | 23 + samples/OpenGL/Cube/main.cpp | 193 + samples/OpenGL/Cube/vtr.bmp | Bin 0 -> 196662 bytes samples/OpenGL/basic.cpp | 12 + samples/OpenGL/build_all.sh | 15 + samples/OpenGL/compile.sh | 36 + samples/OpenGL/easylogging++.cc | 1 + samples/OpenGL/easylogging++.h | 5 + samples/OpenGL/run.sh | 4 + samples/OpenGL/run_all.sh | 3 + samples/Qt/.gitignore | 2 + samples/Qt/basic/README.md | 5 + samples/Qt/basic/easylogging++.h | 5 + samples/Qt/basic/main.cpp | 120 + samples/Qt/basic/mythread.h | 41 + samples/Qt/basic/qt-sample.pro | 21 + samples/Qt/basic/test_conf.conf | 13 + samples/Qt/fast-dictionary/.gitignore | 4 + samples/Qt/fast-dictionary/README.md | 5 + .../Qt/fast-dictionary/fast-dictionary.pro | 30 + samples/Qt/fast-dictionary/listwithsearch.cc | 98 + samples/Qt/fast-dictionary/listwithsearch.hh | 51 + samples/Qt/fast-dictionary/main.cc | 20 + samples/Qt/fast-dictionary/mainwindow.cc | 98 + samples/Qt/fast-dictionary/mainwindow.hh | 37 + samples/Qt/fast-dictionary/mainwindow.ui | 98 + .../Qt/fast-dictionary/moc_listwithsearch.cpp | 95 + samples/Qt/fast-dictionary/moc_mainwindow.cpp | 82 + samples/Qt/fast-dictionary/sample.gif | Bin 0 -> 374369 bytes samples/Qt/fast-dictionary/ui_mainwindow.h | 91 + samples/Qt/fast-dictionary/words.txt | 79768 ++++++++++++++++ samples/Qt/file-splitter-joiner/.gitignore | 25 + samples/Qt/file-splitter-joiner/README.md | 25 + samples/Qt/file-splitter-joiner/about.cpp | 20 + samples/Qt/file-splitter-joiner/about.h | 25 + samples/Qt/file-splitter-joiner/about.ui | 120 + .../addsplittedfiledialog.cpp | 116 + .../addsplittedfiledialog.h | 37 + .../addsplittedfiledialog.ui | 133 + .../Qt/file-splitter-joiner/easylogging++.h | 5 + .../file-splitter-and-joiner.pro | 55 + .../Qt/file-splitter-joiner/joinercore.cpp | 34 + samples/Qt/file-splitter-joiner/joinercore.h | 23 + .../Qt/file-splitter-joiner/joinerwidget.cpp | 54 + .../Qt/file-splitter-joiner/joinerwidget.h | 34 + .../Qt/file-splitter-joiner/joinerwidget.ui | 99 + samples/Qt/file-splitter-joiner/main.cpp | 99 + .../Qt/file-splitter-joiner/mainwindow.cpp | 45 + samples/Qt/file-splitter-joiner/mainwindow.h | 29 + .../Qt/file-splitter-joiner/partprocessor.cpp | 225 + .../Qt/file-splitter-joiner/partprocessor.h | 76 + .../splitablefiledelegate.cpp | 72 + .../splitablefiledelegate.h | 25 + .../Qt/file-splitter-joiner/splittercore.cpp | 95 + .../Qt/file-splitter-joiner/splittercore.h | 35 + .../file-splitter-joiner/splitterwidget.cpp | 243 + .../Qt/file-splitter-joiner/splitterwidget.h | 59 + .../Qt/file-splitter-joiner/splitterwidget.ui | 84 + samples/Qt/shared-lib/README.md | 8 + samples/Qt/shared-lib/myapp/easylogging++.h | 4 + samples/Qt/shared-lib/myapp/main.cc | 21 + samples/Qt/shared-lib/myapp/myapp.pro | 26 + samples/Qt/shared-lib/mylib/easylogging++.h | 4 + samples/Qt/shared-lib/mylib/mylib.cc | 40 + samples/Qt/shared-lib/mylib/mylib.hh | 18 + samples/Qt/shared-lib/mylib/mylib.pro | 29 + samples/Qt/shared-lib/mylib/mylib_global.hh | 12 + samples/STL/.gitignore | 2 + samples/STL/.travis_build.sh | 9 + samples/STL/all-logs.cpp | 62 + samples/STL/autospace.cpp | 35 + samples/STL/build_all.sh | 15 + samples/STL/check-macros.cpp | 73 + samples/STL/compile.sh | 38 + samples/STL/conditional.cpp | 24 + samples/STL/configurator.cpp | 29 + samples/STL/containers.cpp | 97 + samples/STL/crash.cpp | 48 + samples/STL/custom-class.cpp | 60 + samples/STL/custom-crash-handler.cpp | 33 + samples/STL/custom-format-spec.cpp | 86 + samples/STL/custom-performance-output.cpp | 58 + samples/STL/default-configurations.cpp | 34 + samples/STL/default-log-file-from-arg.cpp | 20 + samples/STL/del-logger.cpp | 23 + samples/STL/different-output.cpp | 31 + samples/STL/easylogging++.cc | 1 + samples/STL/easylogging++.h | 5 + samples/STL/flags.cpp | 20 + samples/STL/global-configuration.cpp | 24 + samples/STL/helpers.cpp | 35 + samples/STL/locale.cpp | 22 + samples/STL/log-dispatch-callback.cpp | 42 + samples/STL/loggable.cpp | 32 + samples/STL/logger-log-functions.cpp | 31 + samples/STL/logrotate-pthread.cpp | 44 + samples/STL/logrotate.conf | 8 + samples/STL/logrotate.cpp | 48 + samples/STL/make-loggable.cpp | 41 + samples/STL/manipulators.cpp | 29 + samples/STL/multiple-loggers.cpp | 31 + .../STL/new-logger-registration-callback.cpp | 38 + samples/STL/no-default-log-file.cpp | 25 + samples/STL/occasional.cpp | 27 + samples/STL/plog.cpp | 25 + .../STL/post-performance-tracking-handler.cpp | 46 + samples/STL/pthread.cpp | 153 + samples/STL/roll-out.cpp | 38 + samples/STL/run.sh | 4 + samples/STL/run_all.sh | 3 + samples/STL/shared-static-libs/.gitignore | 10 + samples/STL/shared-static-libs/README.md | 15 + .../STL/shared-static-libs/compile_shared.sh | 13 + .../STL/shared-static-libs/compile_static.sh | 12 + .../STL/shared-static-libs/easylogging++.h | 6 + .../lib/include/easylogging++.h | 6 + .../shared-static-libs/lib/include/mylib.hpp | 9 + samples/STL/shared-static-libs/lib/mylib.cpp | 24 + samples/STL/shared-static-libs/myapp.cpp | 17 + samples/STL/smart-pointer-null-check.cpp | 22 + samples/STL/std-array.cpp | 27 + samples/STL/syslog.cpp | 25 + samples/STL/thread-names.cpp | 45 + samples/STL/timed-block.cpp | 29 + samples/STL/timed-scope.cpp | 24 + samples/STL/verbose.cpp | 25 + samples/STL/very-basic.cpp | 21 + .../.vs/VCPP2015_Win32/v14/.suo | Bin 0 -> 45056 bytes .../VC++/VCPP2015_Win32/VCPP2015_Win32.sln | 28 + .../VCPP2015_Win32/VCPP2015_Win32.vcxproj | 154 + .../VCPP2015_Win32.vcxproj.filters | 30 + .../VCPP2015_Win32.vcxproj.user | 4 + .../VCPP2015_Win32/easylogging++.cpp | 1 + .../VCPP2015_Win32/easylogging++.h | 5 + .../VCPP2015_Win32/VCPP2015_Win32/main.cpp | 29 + .../.vs/VCPP2015_Win32/v14/.suo | Bin 0 -> 34816 bytes .../VCPP2015_Win32.sln | 28 + .../VCPP2015_Win32/VCPP2015_Win32.vcxproj | 154 + .../VCPP2015_Win32.vcxproj.filters | 30 + .../VCPP2015_Win32/easylogging++.cc | 1 + .../VCPP2015_Win32/easylogging++.h | 5 + .../VCPP2015_Win32/main.cpp | 63 + samples/async/.gitignore | 2 + samples/async/build.sh | 8 + samples/async/easylogging++.cc | 1 + samples/async/easylogging++.h | 5 + samples/async/mymath.h | 9 + samples/async/prog.cpp | 28 + samples/boost/.gitignore | 2 + samples/boost/build_all.sh | 15 + samples/boost/compile.sh | 34 + samples/boost/deque.cpp | 12 + samples/boost/easylogging++.cc | 1 + samples/boost/easylogging++.h | 5 + samples/boost/list.cpp | 11 + samples/boost/map.cpp | 18 + samples/boost/run.sh | 4 + samples/boost/run_all.sh | 3 + samples/boost/set.cpp | 18 + samples/boost/string.cpp | 10 + samples/boost/vector.cpp | 16 + samples/console.conf | 9 + samples/default-logger.conf | 25 + samples/file.conf | 9 + samples/global.conf | 7 + samples/gtkmm/.gitignore | 2 + samples/gtkmm/build_all.sh | 15 + samples/gtkmm/compile.sh | 32 + samples/gtkmm/easylogging++.cc | 1 + samples/gtkmm/easylogging++.h | 5 + samples/gtkmm/hello_gtkmm/.gitignore | 3 + samples/gtkmm/hello_gtkmm/compile.sh | 21 + samples/gtkmm/hello_gtkmm/easylogging++.h | 5 + samples/gtkmm/hello_gtkmm/main.cc | 17 + samples/gtkmm/hello_gtkmm/window.cc | 25 + samples/gtkmm/hello_gtkmm/window.h | 22 + samples/gtkmm/run.sh | 4 + samples/gtkmm/run_all.sh | 3 + samples/gtkmm/sigc++.cpp | 35 + samples/gtkmm/ustring.cpp | 12 + samples/send-to-network/.gitignore | 2 + samples/send-to-network/README.md | 29 + samples/send-to-network/compile.sh | 28 + samples/send-to-network/easylogging++.cc | 1 + samples/send-to-network/easylogging++.h | 5 + samples/send-to-network/network-logger.cpp | 83 + samples/wxWidgets/.gitignore | 2 + samples/wxWidgets/build_all.sh | 15 + samples/wxWidgets/compile.sh | 34 + samples/wxWidgets/easylogging++.cc | 1 + samples/wxWidgets/easylogging++.h | 5 + samples/wxWidgets/run.sh | 4 + samples/wxWidgets/run_all.sh | 3 + samples/wxWidgets/wxhashmap.cpp | 17 + samples/wxWidgets/wxhashset.cpp | 23 + samples/wxWidgets/wxlist.cpp | 19 + samples/wxWidgets/wxlonglong.cpp | 9 + samples/wxWidgets/wxstring.cpp | 9 + samples/wxWidgets/wxvector.cpp | 11 + src/easylogging++.cc | 2994 + src/easylogging++.h | 4599 + test/.gitignore | 2 + test/.travis_build.sh | 8 + test/build_and_run.sh | 10 + test/command-line-args-test.h | 55 + test/configurations-test.h | 142 + test/custom-format-specifier-test.h | 33 + test/date-utils-test.h | 59 + test/easylogging++.cc | 1 + test/easylogging++.h | 13 + test/enum-helper-test.h | 51 + test/file-utils-test.h | 59 + test/format-specifier-test.h | 86 + test/global-configurations-test.h | 55 + test/helpers-test.h | 18 + test/hit-counter-test.h | 118 + test/log-format-resolution-test.h | 63 + test/loggable-test.h | 66 + test/logger-test.h | 56 + test/macros-test.h | 19 + test/main.cc | 46 + test/os-utils-test.h | 18 + test/plog-test.h | 18 + test/post-log-dispatch-handler-test.h | 36 + test/registry-test.h | 99 + test/strict-file-size-check-test.h | 26 + test/string-utils-test.h | 107 + test/syslog-test.h | 83 + test/test.h | 102 + test/typed-configurations-test.h | 129 + test/utilities-test.h | 14 + test/verbose-app-arguments-test.h | 203 + test/write-all-test.h | 111 + tools/.gitignore | 2 + tools/cpplint.py | 4736 + tools/release.sh | 79 + 359 files changed, 104796 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CHANGELOG.md create mode 100644 CMakeLists.txt create mode 100644 LICENCE create mode 100644 PULL_REQUEST_TEMPLATE.md create mode 100644 README.md create mode 100644 cmake/FindEASYLOGGINGPP.cmake create mode 100644 cmake/Findgtest.cmake create mode 100644 doc/RELEASE-NOTES-v9.00 create mode 100644 doc/RELEASE-NOTES-v9.01 create mode 100644 doc/RELEASE-NOTES-v9.02 create mode 100644 doc/RELEASE-NOTES-v9.03 create mode 100644 doc/RELEASE-NOTES-v9.04 create mode 100644 doc/RELEASE-NOTES-v9.05 create mode 100644 doc/RELEASE-NOTES-v9.06 create mode 100644 doc/RELEASE-NOTES-v9.07 create mode 100644 doc/RELEASE-NOTES-v9.08 create mode 100644 doc/RELEASE-NOTES-v9.09 create mode 100644 doc/RELEASE-NOTES-v9.10 create mode 100644 doc/RELEASE-NOTES-v9.11 create mode 100644 doc/RELEASE-NOTES-v9.12 create mode 100644 doc/RELEASE-NOTES-v9.13 create mode 100644 doc/RELEASE-NOTES-v9.14 create mode 100644 doc/RELEASE-NOTES-v9.15 create mode 100644 doc/RELEASE-NOTES-v9.16 create mode 100644 doc/RELEASE-NOTES-v9.17 create mode 100644 doc/RELEASE-NOTES-v9.18 create mode 100644 doc/RELEASE-NOTES-v9.19 create mode 100644 doc/RELEASE-NOTES-v9.20 create mode 100644 doc/RELEASE-NOTES-v9.21 create mode 100644 doc/RELEASE-NOTES-v9.22 create mode 100644 doc/RELEASE-NOTES-v9.23 create mode 100644 doc/RELEASE-NOTES-v9.24 create mode 100644 doc/RELEASE-NOTES-v9.25 create mode 100644 doc/RELEASE-NOTES-v9.26 create mode 100644 doc/RELEASE-NOTES-v9.27 create mode 100644 doc/RELEASE-NOTES-v9.28 create mode 100644 doc/RELEASE-NOTES-v9.29 create mode 100644 doc/RELEASE-NOTES-v9.30 create mode 100644 doc/RELEASE-NOTES-v9.31 create mode 100644 doc/RELEASE-NOTES-v9.32 create mode 100644 doc/RELEASE-NOTES-v9.33 create mode 100644 doc/RELEASE-NOTES-v9.34 create mode 100644 doc/RELEASE-NOTES-v9.35 create mode 100644 doc/RELEASE-NOTES-v9.36 create mode 100644 doc/RELEASE-NOTES-v9.37 create mode 100644 doc/RELEASE-NOTES-v9.38 create mode 100644 doc/RELEASE-NOTES-v9.39 create mode 100644 doc/RELEASE-NOTES-v9.40 create mode 100644 doc/RELEASE-NOTES-v9.41 create mode 100644 doc/RELEASE-NOTES-v9.42 create mode 100644 doc/RELEASE-NOTES-v9.43 create mode 100644 doc/RELEASE-NOTES-v9.44 create mode 100644 doc/RELEASE-NOTES-v9.45 create mode 100644 doc/RELEASE-NOTES-v9.46 create mode 100644 doc/RELEASE-NOTES-v9.47 create mode 100644 doc/RELEASE-NOTES-v9.48 create mode 100644 doc/RELEASE-NOTES-v9.49 create mode 100644 doc/RELEASE-NOTES-v9.50 create mode 100644 doc/RELEASE-NOTES-v9.51 create mode 100644 doc/RELEASE-NOTES-v9.52 create mode 100644 doc/RELEASE-NOTES-v9.53 create mode 100644 doc/RELEASE-NOTES-v9.54 create mode 100644 doc/RELEASE-NOTES-v9.55 create mode 100644 doc/RELEASE-NOTES-v9.56 create mode 100644 doc/RELEASE-NOTES-v9.57 create mode 100644 doc/RELEASE-NOTES-v9.58 create mode 100644 doc/RELEASE-NOTES-v9.59 create mode 100644 doc/RELEASE-NOTES-v9.60 create mode 100644 doc/RELEASE-NOTES-v9.61 create mode 100644 doc/RELEASE-NOTES-v9.62 create mode 100644 doc/RELEASE-NOTES-v9.63 create mode 100644 doc/RELEASE-NOTES-v9.64 create mode 100644 doc/RELEASE-NOTES-v9.65 create mode 100644 doc/RELEASE-NOTES-v9.66 create mode 100644 doc/RELEASE-NOTES-v9.67 create mode 100644 doc/RELEASE-NOTES-v9.68 create mode 100644 doc/RELEASE-NOTES-v9.69 create mode 100644 doc/RELEASE-NOTES-v9.70 create mode 100644 doc/RELEASE-NOTES-v9.71 create mode 100644 doc/RELEASE-NOTES-v9.72 create mode 100644 doc/RELEASE-NOTES-v9.73 create mode 100644 doc/RELEASE-NOTES-v9.74 create mode 100644 doc/RELEASE-NOTES-v9.75 create mode 100644 doc/RELEASE-NOTES-v9.76 create mode 100644 doc/RELEASE-NOTES-v9.77 create mode 100644 doc/RELEASE-NOTES-v9.78 create mode 100644 doc/RELEASE-NOTES-v9.79 create mode 100644 doc/RELEASE-NOTES-v9.80 create mode 100644 doc/RELEASE-NOTES-v9.81 create mode 100644 doc/RELEASE-NOTES-v9.82 create mode 100644 doc/RELEASE-NOTES-v9.83 create mode 100644 doc/RELEASE-NOTES-v9.84 create mode 100644 doc/RELEASE-NOTES-v9.85 create mode 100644 doc/RELEASE-NOTES-v9.86 create mode 100644 doc/RELEASE-NOTES-v9.87 create mode 100644 doc/RELEASE-NOTES-v9.88 create mode 100644 doc/RELEASE-NOTES-v9.89 create mode 100644 doc/RELEASE-NOTES-v9.90 create mode 100644 doc/RELEASE-NOTES-v9.91 create mode 100644 doc/RELEASE-NOTES-v9.92 create mode 100644 doc/RELEASE-NOTES-v9.93 create mode 100644 doc/RELEASE-NOTES-v9.94 create mode 100644 samples/.gitignore create mode 100644 samples/API/.gitignore create mode 100755 samples/API/build_all.sh create mode 100755 samples/API/compile.sh create mode 100644 samples/API/easylogging++.cc create mode 100644 samples/API/easylogging++.h create mode 100644 samples/API/logbuilder.cpp create mode 100755 samples/API/run.sh create mode 100755 samples/API/run_all.sh create mode 100644 samples/MinGW/.gitignore create mode 100644 samples/MinGW/compile.bat create mode 100644 samples/MinGW/easylogging++.cc create mode 100644 samples/MinGW/easylogging++.h create mode 100644 samples/MinGW/prog.cpp create mode 100644 samples/OpenGL/.gitignore create mode 100644 samples/OpenGL/Cube/.gitignore create mode 100644 samples/OpenGL/Cube/LICENCE create mode 100644 samples/OpenGL/Cube/Makefile create mode 100644 samples/OpenGL/Cube/imageloader.cpp create mode 100644 samples/OpenGL/Cube/imageloader.h create mode 100644 samples/OpenGL/Cube/main.cpp create mode 100644 samples/OpenGL/Cube/vtr.bmp create mode 100644 samples/OpenGL/basic.cpp create mode 100755 samples/OpenGL/build_all.sh create mode 100755 samples/OpenGL/compile.sh create mode 100644 samples/OpenGL/easylogging++.cc create mode 100644 samples/OpenGL/easylogging++.h create mode 100755 samples/OpenGL/run.sh create mode 100755 samples/OpenGL/run_all.sh create mode 100644 samples/Qt/.gitignore create mode 100644 samples/Qt/basic/README.md create mode 100644 samples/Qt/basic/easylogging++.h create mode 100644 samples/Qt/basic/main.cpp create mode 100644 samples/Qt/basic/mythread.h create mode 100644 samples/Qt/basic/qt-sample.pro create mode 100644 samples/Qt/basic/test_conf.conf create mode 100644 samples/Qt/fast-dictionary/.gitignore create mode 100644 samples/Qt/fast-dictionary/README.md create mode 100644 samples/Qt/fast-dictionary/fast-dictionary.pro create mode 100644 samples/Qt/fast-dictionary/listwithsearch.cc create mode 100644 samples/Qt/fast-dictionary/listwithsearch.hh create mode 100644 samples/Qt/fast-dictionary/main.cc create mode 100644 samples/Qt/fast-dictionary/mainwindow.cc create mode 100644 samples/Qt/fast-dictionary/mainwindow.hh create mode 100644 samples/Qt/fast-dictionary/mainwindow.ui create mode 100644 samples/Qt/fast-dictionary/moc_listwithsearch.cpp create mode 100644 samples/Qt/fast-dictionary/moc_mainwindow.cpp create mode 100644 samples/Qt/fast-dictionary/sample.gif create mode 100644 samples/Qt/fast-dictionary/ui_mainwindow.h create mode 100644 samples/Qt/fast-dictionary/words.txt create mode 100644 samples/Qt/file-splitter-joiner/.gitignore create mode 100644 samples/Qt/file-splitter-joiner/README.md create mode 100644 samples/Qt/file-splitter-joiner/about.cpp create mode 100644 samples/Qt/file-splitter-joiner/about.h create mode 100644 samples/Qt/file-splitter-joiner/about.ui create mode 100644 samples/Qt/file-splitter-joiner/addsplittedfiledialog.cpp create mode 100644 samples/Qt/file-splitter-joiner/addsplittedfiledialog.h create mode 100644 samples/Qt/file-splitter-joiner/addsplittedfiledialog.ui create mode 100644 samples/Qt/file-splitter-joiner/easylogging++.h create mode 100644 samples/Qt/file-splitter-joiner/file-splitter-and-joiner.pro create mode 100644 samples/Qt/file-splitter-joiner/joinercore.cpp create mode 100644 samples/Qt/file-splitter-joiner/joinercore.h create mode 100644 samples/Qt/file-splitter-joiner/joinerwidget.cpp create mode 100644 samples/Qt/file-splitter-joiner/joinerwidget.h create mode 100644 samples/Qt/file-splitter-joiner/joinerwidget.ui create mode 100644 samples/Qt/file-splitter-joiner/main.cpp create mode 100644 samples/Qt/file-splitter-joiner/mainwindow.cpp create mode 100644 samples/Qt/file-splitter-joiner/mainwindow.h create mode 100644 samples/Qt/file-splitter-joiner/partprocessor.cpp create mode 100644 samples/Qt/file-splitter-joiner/partprocessor.h create mode 100644 samples/Qt/file-splitter-joiner/splitablefiledelegate.cpp create mode 100644 samples/Qt/file-splitter-joiner/splitablefiledelegate.h create mode 100644 samples/Qt/file-splitter-joiner/splittercore.cpp create mode 100644 samples/Qt/file-splitter-joiner/splittercore.h create mode 100644 samples/Qt/file-splitter-joiner/splitterwidget.cpp create mode 100644 samples/Qt/file-splitter-joiner/splitterwidget.h create mode 100644 samples/Qt/file-splitter-joiner/splitterwidget.ui create mode 100644 samples/Qt/shared-lib/README.md create mode 100644 samples/Qt/shared-lib/myapp/easylogging++.h create mode 100644 samples/Qt/shared-lib/myapp/main.cc create mode 100644 samples/Qt/shared-lib/myapp/myapp.pro create mode 100644 samples/Qt/shared-lib/mylib/easylogging++.h create mode 100644 samples/Qt/shared-lib/mylib/mylib.cc create mode 100644 samples/Qt/shared-lib/mylib/mylib.hh create mode 100644 samples/Qt/shared-lib/mylib/mylib.pro create mode 100644 samples/Qt/shared-lib/mylib/mylib_global.hh create mode 100644 samples/STL/.gitignore create mode 100755 samples/STL/.travis_build.sh create mode 100644 samples/STL/all-logs.cpp create mode 100644 samples/STL/autospace.cpp create mode 100755 samples/STL/build_all.sh create mode 100644 samples/STL/check-macros.cpp create mode 100755 samples/STL/compile.sh create mode 100644 samples/STL/conditional.cpp create mode 100644 samples/STL/configurator.cpp create mode 100644 samples/STL/containers.cpp create mode 100644 samples/STL/crash.cpp create mode 100644 samples/STL/custom-class.cpp create mode 100644 samples/STL/custom-crash-handler.cpp create mode 100644 samples/STL/custom-format-spec.cpp create mode 100644 samples/STL/custom-performance-output.cpp create mode 100644 samples/STL/default-configurations.cpp create mode 100644 samples/STL/default-log-file-from-arg.cpp create mode 100644 samples/STL/del-logger.cpp create mode 100644 samples/STL/different-output.cpp create mode 100644 samples/STL/easylogging++.cc create mode 100644 samples/STL/easylogging++.h create mode 100644 samples/STL/flags.cpp create mode 100644 samples/STL/global-configuration.cpp create mode 100644 samples/STL/helpers.cpp create mode 100644 samples/STL/locale.cpp create mode 100644 samples/STL/log-dispatch-callback.cpp create mode 100644 samples/STL/loggable.cpp create mode 100644 samples/STL/logger-log-functions.cpp create mode 100644 samples/STL/logrotate-pthread.cpp create mode 100644 samples/STL/logrotate.conf create mode 100644 samples/STL/logrotate.cpp create mode 100644 samples/STL/make-loggable.cpp create mode 100644 samples/STL/manipulators.cpp create mode 100644 samples/STL/multiple-loggers.cpp create mode 100644 samples/STL/new-logger-registration-callback.cpp create mode 100644 samples/STL/no-default-log-file.cpp create mode 100644 samples/STL/occasional.cpp create mode 100644 samples/STL/plog.cpp create mode 100644 samples/STL/post-performance-tracking-handler.cpp create mode 100644 samples/STL/pthread.cpp create mode 100644 samples/STL/roll-out.cpp create mode 100755 samples/STL/run.sh create mode 100755 samples/STL/run_all.sh create mode 100644 samples/STL/shared-static-libs/.gitignore create mode 100644 samples/STL/shared-static-libs/README.md create mode 100755 samples/STL/shared-static-libs/compile_shared.sh create mode 100755 samples/STL/shared-static-libs/compile_static.sh create mode 100644 samples/STL/shared-static-libs/easylogging++.h create mode 100644 samples/STL/shared-static-libs/lib/include/easylogging++.h create mode 100644 samples/STL/shared-static-libs/lib/include/mylib.hpp create mode 100644 samples/STL/shared-static-libs/lib/mylib.cpp create mode 100644 samples/STL/shared-static-libs/myapp.cpp create mode 100644 samples/STL/smart-pointer-null-check.cpp create mode 100644 samples/STL/std-array.cpp create mode 100644 samples/STL/syslog.cpp create mode 100644 samples/STL/thread-names.cpp create mode 100644 samples/STL/timed-block.cpp create mode 100644 samples/STL/timed-scope.cpp create mode 100644 samples/STL/verbose.cpp create mode 100644 samples/STL/very-basic.cpp create mode 100644 samples/VC++/VCPP2015_Win32/.vs/VCPP2015_Win32/v14/.suo create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32.sln create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32/VCPP2015_Win32.vcxproj create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32/VCPP2015_Win32.vcxproj.filters create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32/VCPP2015_Win32.vcxproj.user create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32/easylogging++.cpp create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32/easylogging++.h create mode 100644 samples/VC++/VCPP2015_Win32/VCPP2015_Win32/main.cpp create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/.vs/VCPP2015_Win32/v14/.suo create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/VCPP2015_Win32.sln create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/VCPP2015_Win32/VCPP2015_Win32.vcxproj create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/VCPP2015_Win32/VCPP2015_Win32.vcxproj.filters create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/VCPP2015_Win32/easylogging++.cc create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/VCPP2015_Win32/easylogging++.h create mode 100644 samples/VC++/VCPP2015_Win32_Multithreaded/VCPP2015_Win32/main.cpp create mode 100644 samples/async/.gitignore create mode 100755 samples/async/build.sh create mode 100644 samples/async/easylogging++.cc create mode 100644 samples/async/easylogging++.h create mode 100644 samples/async/mymath.h create mode 100644 samples/async/prog.cpp create mode 100644 samples/boost/.gitignore create mode 100755 samples/boost/build_all.sh create mode 100755 samples/boost/compile.sh create mode 100644 samples/boost/deque.cpp create mode 100644 samples/boost/easylogging++.cc create mode 100644 samples/boost/easylogging++.h create mode 100644 samples/boost/list.cpp create mode 100644 samples/boost/map.cpp create mode 100755 samples/boost/run.sh create mode 100755 samples/boost/run_all.sh create mode 100644 samples/boost/set.cpp create mode 100644 samples/boost/string.cpp create mode 100644 samples/boost/vector.cpp create mode 100644 samples/console.conf create mode 100644 samples/default-logger.conf create mode 100644 samples/file.conf create mode 100644 samples/global.conf create mode 100644 samples/gtkmm/.gitignore create mode 100755 samples/gtkmm/build_all.sh create mode 100755 samples/gtkmm/compile.sh create mode 100644 samples/gtkmm/easylogging++.cc create mode 100644 samples/gtkmm/easylogging++.h create mode 100644 samples/gtkmm/hello_gtkmm/.gitignore create mode 100755 samples/gtkmm/hello_gtkmm/compile.sh create mode 100644 samples/gtkmm/hello_gtkmm/easylogging++.h create mode 100644 samples/gtkmm/hello_gtkmm/main.cc create mode 100644 samples/gtkmm/hello_gtkmm/window.cc create mode 100644 samples/gtkmm/hello_gtkmm/window.h create mode 100755 samples/gtkmm/run.sh create mode 100755 samples/gtkmm/run_all.sh create mode 100644 samples/gtkmm/sigc++.cpp create mode 100644 samples/gtkmm/ustring.cpp create mode 100644 samples/send-to-network/.gitignore create mode 100644 samples/send-to-network/README.md create mode 100755 samples/send-to-network/compile.sh create mode 100644 samples/send-to-network/easylogging++.cc create mode 100644 samples/send-to-network/easylogging++.h create mode 100644 samples/send-to-network/network-logger.cpp create mode 100644 samples/wxWidgets/.gitignore create mode 100755 samples/wxWidgets/build_all.sh create mode 100755 samples/wxWidgets/compile.sh create mode 100644 samples/wxWidgets/easylogging++.cc create mode 100644 samples/wxWidgets/easylogging++.h create mode 100755 samples/wxWidgets/run.sh create mode 100755 samples/wxWidgets/run_all.sh create mode 100644 samples/wxWidgets/wxhashmap.cpp create mode 100644 samples/wxWidgets/wxhashset.cpp create mode 100644 samples/wxWidgets/wxlist.cpp create mode 100644 samples/wxWidgets/wxlonglong.cpp create mode 100644 samples/wxWidgets/wxstring.cpp create mode 100644 samples/wxWidgets/wxvector.cpp create mode 100644 src/easylogging++.cc create mode 100644 src/easylogging++.h create mode 100644 test/.gitignore create mode 100644 test/.travis_build.sh create mode 100755 test/build_and_run.sh create mode 100644 test/command-line-args-test.h create mode 100644 test/configurations-test.h create mode 100644 test/custom-format-specifier-test.h create mode 100644 test/date-utils-test.h create mode 100644 test/easylogging++.cc create mode 100644 test/easylogging++.h create mode 100644 test/enum-helper-test.h create mode 100644 test/file-utils-test.h create mode 100644 test/format-specifier-test.h create mode 100644 test/global-configurations-test.h create mode 100644 test/helpers-test.h create mode 100644 test/hit-counter-test.h create mode 100644 test/log-format-resolution-test.h create mode 100644 test/loggable-test.h create mode 100644 test/logger-test.h create mode 100644 test/macros-test.h create mode 100644 test/main.cc create mode 100644 test/os-utils-test.h create mode 100644 test/plog-test.h create mode 100644 test/post-log-dispatch-handler-test.h create mode 100644 test/registry-test.h create mode 100644 test/strict-file-size-check-test.h create mode 100644 test/string-utils-test.h create mode 100644 test/syslog-test.h create mode 100644 test/test.h create mode 100644 test/typed-configurations-test.h create mode 100644 test/utilities-test.h create mode 100644 test/verbose-app-arguments-test.h create mode 100644 test/write-all-test.h create mode 100644 tools/.gitignore create mode 100644 tools/cpplint.py create mode 100755 tools/release.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..925782b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +build/* +build-* +*.pro.user +.DS_Store +release.info +bin/* +logs/* +experiments/* +CMakeLists.txt.user diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..33569cf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +language: cpp +compiler: + - gcc +os: linux +dist: trusty +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y libgtest-dev valgrind + - sudo wget https://github.com/google/googletest/archive/release-1.7.0.tar.gz + - sudo tar xf release-1.7.0.tar.gz + - cd googletest-release-1.7.0 + - sudo cmake -DBUILD_SHARED_LIBS=ON . + - sudo make + - sudo cp -a include/gtest /usr/include + - sudo cp -a libgtest_main.so libgtest.so /usr/lib/ + - which valgrind + - cd "${TRAVIS_BUILD_DIR}" +before_script: + - cd test/ + - cmake -Dtest=ON ../ + - make + - ls -l +script: "./easyloggingpp-unit-tests -v && cd ../samples/STL && pwd && sh ./.travis_build.sh && valgrind ./bin/very-basic.cpp.bin" +branches: + only: + - master + - develop +notifications: + recipients: + - mkhan3189@gmail.com + email: + on_success: never + on_failure: change +rvm: + - 9.00 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ca09e2d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,45 @@ +# Change Log + +## [9.95.0] - 02-08-2017 +### Added + - Added NetBSD as unix [coypoop](https://github.com/muflihun/easyloggingpp/pull/548/commits) + - Ignore `NDEBUG` or `_DEBUG` to determine whether debug logs should be enabled or not. Use `ELPP_DISABLE_DEBUG_LOGS` + +### Fixes + - Fix compile when `_USE_32_BIT_TIME_T` defined [gggin](https://github.com/muflihun/easyloggingpp/pull/542/files) + - Fix invalid usage of safeDelete which can cause an error with valgrind [Touyote](https://github.com/muflihun/easyloggingpp/pull/544/files) + - Add code to ensure no nullptr references [tepperly](https://github.com/muflihun/easyloggingpp/pull/512/files) + +## [9.94.2] - 12-04-2017 +### Added + - CMake option to create static lib (thanks to @romariorios) + - Ability to use UTC time using `ELPP_UTC_DATETIME` (thanks to @romariorios) + - CMake module updated to support static lib + +### Changes + - Renamed long format specifiers to full names with padding for readbility + +### Fixes + - Fixed Android NDK build (thanks to @MoroccanMalinois) + - Fix `ELPP_DISABLE_LOGS` not working in VS (thanks to @goloap) #365 + +## [9.94.1] - 25-02-2017 +### Fixed + - Fixes for `/W4` level warnings generated in MSVC compile (Thanks to [Falconne](https://github.com/Falconne)) + - Fixed links + - Fixes removing default logger if other than `default` + +### Changes + - Changed documentation to mention `easylogging++.cc` in introduction and added links to features + +## [9.94.0] - 14-02-2017 +### Fixed + - Fixed performance tracking time unit and calculations + +### Added + - Restored `ELPP_DEFAULT_LOGGER` and `ELPP_DEFAULT_PERFORMANCE_LOGGER` + - `Helpers::getThreadName` for reading current thread name + - Custom format specifier now has to return `std::string` instead + - Merged `thread_name` with `thread` if thread name is available it's used otherwise ID is displayed + +For older versions please refer to [https://github.com/muflihun/easyloggingpp/tree/master/doc](https://github.com/muflihun/easyloggingpp/tree/master/doc) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1f7244b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(Easyloggingpp CXX) + +macro(require_cpp11) + if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0) + # CMake 3.1 has built-in CXX standard checks. + message("-- Setting C++11") + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED on) + else() + if (CMAKE_CXX_COMPILER_ID MATCHES "GCC") + message ("-- GNU CXX (-std=c++11)") + list(APPEND CMAKE_CXX_FLAGS "-std=c++11") + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message ("-- CLang CXX (-std=c++11)") + list(APPEND CMAKE_CXX_FLAGS "-std=c++11") + else() + message ("-- Easylogging++ requires C++11. Your compiler does not support it.") + endif() + endif() +endmacro() + +option(test "Build all tests" OFF) +option(build_static_lib "Build easyloggingpp as a static library" OFF) +option(lib_utc_datetime "Build library with UTC date/time logging" OFF) + +set(ELPP_MAJOR_VERSION "9") +set(ELPP_MINOR_VERSION "95") +set(ELPP_PATCH_VERSION "0") +set(ELPP_VERSION_STRING "${ELPP_MAJOR_VERSION}.${ELPP_MINOR_VERSION}.${ELPP_PATCH_VERSION}") + +set(ELPP_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The directory the headers are installed in") + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +install(FILES + src/easylogging++.h + src/easylogging++.cc + DESTINATION "${ELPP_INCLUDE_INSTALL_DIR}" + COMPONENT dev) + +if (build_static_lib) + if (lib_utc_datetime) + add_definitions(-DELPP_UTC_DATETIME) + endif() + + require_cpp11() + add_library(easyloggingpp STATIC src/easylogging++.cc) + + install(TARGETS + easyloggingpp + ARCHIVE DESTINATION lib) +endif() + +export(PACKAGE ${PROJECT_NAME}) + + +########################################## Unit Testing ################################### +if (test) + # We need C++11 + require_cpp11() + set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") + + find_package (gtest REQUIRED) + + include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) + + enable_testing() + + add_executable(easyloggingpp-unit-tests + src/easylogging++.cc + test/main.cc + ) + + target_compile_definitions(easyloggingpp-unit-tests PUBLIC + ELPP_FEATURE_ALL + ELPP_LOGGING_FLAGS_FROM_ARG + ELPP_NO_DEFAULT_LOG_FILE + ELPP_FRESH_LOG_FILE + ) + + # Standard linking to gtest stuff. + target_link_libraries(easyloggingpp-unit-tests gtest gtest_main) + + add_test(NAME easyloggingppUnitTests COMMAND easyloggingpp-unit-tests -v) +endif() diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..2c8998d --- /dev/null +++ b/LICENCE @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2017 muflihun.com + +https://github.com/muflihun/ +https://muflihun.github.io +https://muflihun.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d0d2774 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +### This is a + +- [ ] Breaking change +- [ ] New feature +- [ ] Bugfix + +### I have + +- [ ] Merged in the latest upstream changes +- [ ] Updated [`CHANGELOG.md`](CHANGELOG.md) +- [ ] Updated [`README.md`](README.md) +- [ ] [Run the tests](README.md#install-optional) diff --git a/README.md b/README.md new file mode 100644 index 0000000..abc6899 --- /dev/null +++ b/README.md @@ -0,0 +1,1435 @@ + ‫بسم الله الرَّحْمَن٠الرَّحÙيم٠+ + +![banner] + +> **Manual For v9.95.0** + +[![Build Status (Develop)](https://img.shields.io/travis/muflihun/easyloggingpp/develop.svg)](https://travis-ci.org/muflihun/easyloggingpp) (`develop`) + +[![Build Status (Master)](https://img.shields.io/travis/muflihun/easyloggingpp/master.svg)](https://travis-ci.org/muflihun/easyloggingpp) (`master`) + +[![Version](https://img.shields.io/github/release/muflihun/easyloggingpp.svg)](https://github.com/muflihun/easyloggingpp/releases/latest) + +[![Canon.io](https://img.shields.io/badge/conan.io-easyloggingpp%2F9.95.0-green.svg?logo=data:image/png;base64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAA1VBMVEUAAABhlctjlstkl8tlmMtlmMxlmcxmmcxnmsxpnMxpnM1qnc1sn85voM91oM11oc1xotB2oc56pNF6pNJ2ptJ8ptJ8ptN9ptN8p9N5qNJ9p9N9p9R8qtOBqdSAqtOAqtR%2BrNSCrNJ/rdWDrNWCsNWCsNaJs9eLs9iRvNuVvdyVv9yXwd2Zwt6axN6dxt%2Bfx%2BChyeGiyuGjyuCjyuGly%2BGlzOKmzOGozuKoz%2BKqz%2BOq0OOv1OWw1OWw1eWx1eWy1uay1%2Baz1%2Baz1%2Bez2Oe02Oe12ee22ujUGwH3AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBQkREyOxFIh/AAAAiklEQVQI12NgAAMbOwY4sLZ2NtQ1coVKWNvoc/Eq8XDr2wB5Ig62ekza9vaOqpK2TpoMzOxaFtwqZua2Bm4makIM7OzMAjoaCqYuxooSUqJALjs7o4yVpbowvzSUy87KqSwmxQfnsrPISyFzWeWAXCkpMaBVIC4bmCsOdgiUKwh3JojLgAQ4ZCE0AMm2D29tZwe6AAAAAElFTkSuQmCC)](http://www.conan.io/source/easyloggingpp/9.95.0/memsharded/testing) + +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/rwDXGcnP1IoCKXrJ) + +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/muflihun/easyloggingpp/blob/master/LICENCE) + +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/MuflihunDotCom/25) + +[![Downloads](https://img.shields.io/github/downloads/muflihun/easyloggingpp/total.svg)](https://github.com/muflihun/easyloggingpp/releases/latest) + +### Quick Links + + [![download] Latest Release](https://github.com/muflihun/easyloggingpp/releases/latest) + + [![notes] Changelog](/CHANGELOG.md) + + [![samples] Samples](/samples) + +--- + +### Table of Contents +
+Introduction
+    Why yet another library
+    Features at a glance
+Getting Started
+    Download
+    Quick Start
+    Install (Optional)
+    Setting Application Arguments
+Configuration
+    Level
+    Configure
+        Using Configuration File
+        Using el::Configurations Class
+        Using In line Configurations
+    Default Configurations
+    Global Configurations
+    Logging Format Specifiers
+    Date/Time Format Specifiers
+    Custom Format Specifiers
+    Logging Flags
+    Application Arguments
+    Configuration Macros
+    Reading Configurations
+Logging
+    Basic
+    Conditional Logging
+    Occasional Logging
+    printf Like Logging
+    Network Logging
+    Verbose Logging
+        Basic
+        Conditional and Occasional
+        Verbose Level
+        Check If Verbose Logging Is On
+        VModule
+    Registering New Loggers
+    Unregister Loggers
+    Populating Existing Logger IDs
+    Sharing Logging Repository
+Extra Features
+    Performance Tracking
+        Conditional Performance Tracking
+        Make Use of Performance Tracking Data
+    Log File Rotating
+    Crash Handling
+        Installing Custom Crash Handlers
+    Stacktrace
+    Multi-threading
+    CHECK Macros
+    Logging perror()
+    Using Syslog
+    STL Logging
+        Supported Templates
+    Qt Logging
+    Boost Logging
+    wxWidgets Logging
+    Extending Library
+        Logging Your Own Class
+        Logging Third-party Class
+    Manually Flushing and Rolling Log Files
+    Log Dispatch Callback
+    Logger Registration Callback
+    Asynchronous Logging
+    Helper Classes
+Contribution
+    Submitting Patches
+    Reporting a Bug
+Compatibility
+Licence
+Disclaimer
+
+ +# Introduction +Easylogging++ is single header efficient logging library for C++ applications. It is extremely powerful, highly extendable and configurable to user's requirements. It provides ability to [write your own sinks](https://github.com/muflihun/easyloggingpp/tree/master/samples/send-to-network) (referred to as `LogDispatchCallback`). Currently used by hundreds of open-source projects. + +This manual is for Easylogging++ v9.95.0. For other versions please refer to corresponding [release](https://github.com/muflihun/easyloggingpp/releases) on github. + + [![top] Goto Top](#table-of-contents) + +### Why yet another library +If you are working on a small utility or large project in C++, this library can be handy. Its based on single header and only requires to link to single source file. (Originally it was header-only and was changed to use source file in [issue #445](https://github.com/muflihun/easyloggingpp/issues/445). You can still use header-only in [v9.89](https://github.com/muflihun/easyloggingpp/releases/tag/9.89)). + +This library has been designed with various thoughts in mind (i.e, portability, performance, usability, features and easy to setup). + +Why yet another library? Well, answer is pretty straight forward, use it as you wrote it so you can fix issues (if any) as you go or raise them on github. In addition to that, I personally have not seen any logging library based on single-header with such a design where you can configure on the go, extend it to your needs and get fast performance. I have seen other single-header logging libraries for C++ but either they use external libraries, e.g, boost or Qt to support certain features like threading, regular expression or date etc. This library has everything built-in to prevent usage of external libraries, not that I don't like those libraries, in fact I love them, but because not all projects use these libraries, I couldn't take risk of depending on them. + + [![top] Goto Top](#table-of-contents) + +### Features at a glance +Easylogging++ is feature-rich containing many features that both typical and advanced developer will require while writing a software; + * [Highly configurable](#configuration) + * [Extendable](#log-dispatch-callback) + * Extremely fast + * [Thread](#multi-threading) and type safe + * [Cross-platform](#compatibility) + * [Custom log patterns](#logging-format-specifiers) + * [Conditional and occasional logging](#conditional-logging) + * [Performance tracking](#performance-tracking) + * [Verbose logging](#verbose-logging) + * [Crash handling](#crash-handling) + * [Helper CHECK macros](#check-macros) + * [STL logging](#stl-logging) + * [Send to Syslog](#syslog) + * [Third-party library logging (Qt, boost, wxWidgets etc)](#logging-third-party-class) + * [Extensible (Logging your own class or third-party class)](#logging-your-own-class) + * [And many more...](#extra-features) + + [![top] Goto Top](#table-of-contents) + +# Getting Started +### Download +Download latest version from [Latest Release](https://github.com/muflihun/easyloggingpp/releases/latest) + +For other releases, please visit [releases page](https://github.com/muflihun/easyloggingpp/releases). If you application does not support C++11, please consider using [v8.91](https://github.com/muflihun/easyloggingpp/tree/v8.91). This is stable version for C++98 and C++03, just lack some features. + + [![top] Goto Top](#table-of-contents) + +### Quick Start +In order to get started with Easylogging++, you can follow three easy steps: +* Download latest version +* Include into your project (`easylogging++.h` and `easylogging++.cc`) +* Initialize using single macro... and off you go! + +```c++ +#include "easylogging++.h" + +INITIALIZE_EASYLOGGINGPP + +int main(int argc, char* argv[]) { + LOG(INFO) << "My first info log using default logger"; + return 0; +} +``` + +Now compile using + +``` +g++ main.cc easylogging++.cc -o prog -std=c++11 +``` + +That simple! Please note that `INITIALIZE_EASYLOGGINGPP` should be used once and once-only otherwise you will end up getting compilation errors. This is definiting several `extern` variables. This means it can be defined only once per application. Best place to put this initialization statement is in file where `int main(int, char**)` function is defined, right after last include statement. + +### Install (Optional) +If you want to install this header system-wide, you can do so via: +``` +mkdir build +cd build +cmake -Dtest=ON ../ +make +make test +make install +``` + +Following options are supported by Easylogging++ cmake and you can turn these options on using `-D
"; XMLDocument doc; doc.Parse(xml); - XMLTest( "Parse before deep cloning root element", false, doc.Error() ); doc.Print(&printer1); XMLNode* root = doc.RootElement()->DeepClone(&doc2); @@ -1269,7 +1173,6 @@ int main( int argc, const char ** argv ) "
"; XMLDocument doc; doc.Parse(xml); - XMLTest( "Parse before deep cloning sub element", false, doc.Error() ); const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2"); subElement->Accept(&printer1); @@ -1299,7 +1202,6 @@ int main( int argc, const char ** argv ) "
"; XMLDocument doc; doc.Parse(xml); - XMLTest( "Parse before deep cloning document", false, doc.Error() ); doc.Print(&printer1); doc.DeepCopy(&doc2); @@ -1326,7 +1228,6 @@ int main( int argc, const char ** argv ) static const char* xml = ""; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse for attribute ordering", false, doc.Error() ); XMLElement* ele = doc.FirstChildElement(); const XMLAttribute* a = ele->FirstAttribute(); @@ -1355,13 +1256,10 @@ int main( int argc, const char ** argv ) static const char* xml2 = ""; XMLDocument doc0; doc0.Parse( xml0 ); - XMLTest( "Parse attribute with space 1", false, doc0.Error() ); XMLDocument doc1; doc1.Parse( xml1 ); - XMLTest( "Parse attribute with space 2", false, doc1.Error() ); XMLDocument doc2; doc2.Parse( xml2 ); - XMLTest( "Parse attribute with space 3", false, doc2.Error() ); XMLElement* ele = 0; ele = doc0.FirstChildElement(); @@ -1377,7 +1275,6 @@ int main( int argc, const char ** argv ) static const char* xml = ""; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse two elements with attribute", false, doc.Error() ); XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement(); XMLElement* ele1 = ele0->NextSiblingElement(); bool equal = ele0->ShallowEqual( ele1 ); @@ -1390,7 +1287,6 @@ int main( int argc, const char ** argv ) static const char* xml = "Text"; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() ); XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement(); XMLTest( "Handle, success, mutable", "sub", ele->Value() ); @@ -1404,7 +1300,6 @@ int main( int argc, const char ** argv ) static const char* xml = "Text"; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() ); XMLConstHandle docH( doc ); const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement(); @@ -1438,7 +1333,6 @@ int main( int argc, const char ** argv ) const char* xml = " 1.2 1 38 true "; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse points", false, doc.Error() ); const XMLElement* pointElement = doc.RootElement(); @@ -1496,7 +1390,6 @@ int main( int argc, const char ** argv ) doc.Clear(); XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() ); doc.LoadFile( "resources/dream.xml" ); - XMLTest( "Load dream.xml", false, doc.Error() ); XMLTest( "Document has something to Clear()", false, doc.NoChildren() ); doc.Clear(); XMLTest( "Document Clear()'s", true, doc.NoChildren() ); @@ -1511,7 +1404,6 @@ int main( int argc, const char ** argv ) ""; XMLDocument doc( true, COLLAPSE_WHITESPACE ); doc.Parse( xml ); - XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() ); const XMLElement* element = doc.FirstChildElement(); for( const XMLElement* parent = element->FirstChildElement(); @@ -1539,7 +1431,6 @@ int main( int argc, const char ** argv ) const char* xml = " "; XMLDocument doc( true, COLLAPSE_WHITESPACE ); doc.Parse( xml ); - XMLTest( "Parse with all whitespaces", false, doc.Error() ); XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() ); } @@ -1548,7 +1439,6 @@ int main( int argc, const char ** argv ) const char* xml = ""; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse with self-closed element", false, doc.Error() ); XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope. XMLTest( "Tracking unused elements", true, ele != 0, false ); } @@ -1558,7 +1448,6 @@ int main( int argc, const char ** argv ) const char* xml = "abc"; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse for printing of sub-element", false, doc.Error() ); XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child"); XMLPrinter printer; @@ -1586,12 +1475,10 @@ int main( int argc, const char ** argv ) XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); doc.SaveFile( "resources/bomtest.xml" ); - XMLTest( "Save bomtest.xml", false, doc.Error() ); } { XMLDocument doc; doc.LoadFile( "resources/bomtest.xml" ); - XMLTest( "Load bomtest.xml", false, doc.Error() ); XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false ); XMLPrinter printer; @@ -1639,7 +1526,6 @@ int main( int argc, const char ** argv ) XMLDocument doc; doc.Parse(xml); - XMLTest( "Insertion with removal parse round 1", false, doc.Error() ); XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); XMLElement* two = doc.RootElement()->FirstChildElement("two"); two->InsertFirstChild(subtree); @@ -1648,7 +1534,6 @@ int main( int argc, const char ** argv ) XMLTest("Move node from within to ", xmlInsideTwo, printer1.CStr()); doc.Parse(xml); - XMLTest( "Insertion with removal parse round 2", false, doc.Error() ); subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); two = doc.RootElement()->FirstChildElement("two"); doc.RootElement()->InsertAfterChild(two, subtree); @@ -1657,7 +1542,6 @@ int main( int argc, const char ** argv ) XMLTest("Move node from within after ", xmlAfterTwo, printer2.CStr(), false); doc.Parse(xml); - XMLTest( "Insertion with removal parse round 3", false, doc.Error() ); XMLNode* one = doc.RootElement()->FirstChildElement("one"); subtree = one->FirstChildElement("subtree"); doc.RootElement()->InsertAfterChild(one, subtree); @@ -1666,7 +1550,6 @@ int main( int argc, const char ** argv ) XMLTest("Move node from within after ", xmlAfterOne, printer3.CStr(), false); doc.Parse(xml); - XMLTest( "Insertion with removal parse round 4", false, doc.Error() ); subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); two = doc.RootElement()->FirstChildElement("two"); doc.RootElement()->InsertEndChild(subtree); @@ -1681,7 +1564,6 @@ int main( int argc, const char ** argv ) ""; XMLDocument doc; doc.Parse(xml); - XMLTest( "Parse svg with text", false, doc.Error() ); doc.Print(); } @@ -1690,7 +1572,6 @@ int main( int argc, const char ** argv ) const char* xml = "<12"; XMLDocument doc; doc.Parse(xml); - XMLTest( "Parse root-sample-field0", true, doc.Error() ); doc.PrintError(); } @@ -1702,7 +1583,6 @@ int main( int argc, const char ** argv ) const char* xml = ""; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse self-closed empty element", false, doc.Error() ); doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 ); doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 ); doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 ); @@ -1735,16 +1615,13 @@ int main( int argc, const char ** argv ) // If it doesn't assert, it passes. Caused by objects // getting created during parsing which are then // inaccessible in the memory pools. - const char* xmlText = ""; { XMLDocument doc; - doc.Parse(xmlText); - XMLTest( "Parse hex no closing tag round 1", true, doc.Error() ); + doc.Parse(""); } { XMLDocument doc; - doc.Parse(xmlText); - XMLTest( "Parse hex no closing tag round 2", true, doc.Error() ); + doc.Parse(""); doc.Clear(); } } @@ -1756,24 +1633,6 @@ int main( int argc, const char ** argv ) doc.DeleteNode(pRoot); } - { - XMLDocument doc; - XMLElement* root = doc.NewElement( "Root" ); - XMLTest( "Node document before insertion", true, &doc == root->GetDocument() ); - doc.InsertEndChild( root ); - XMLTest( "Node document after insertion", true, &doc == root->GetDocument() ); - } - - { - // If this doesn't assert in DEBUG, all is well. - XMLDocument doc; - XMLElement* unlinkedRoot = doc.NewElement( "Root" ); - XMLElement* linkedRoot = doc.NewElement( "Root" ); - doc.InsertFirstChild( linkedRoot ); - unlinkedRoot->GetDocument()->DeleteNode( linkedRoot ); - unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot ); - } - { // Should not assert in DEBUG XMLPrinter printer; @@ -1784,7 +1643,6 @@ int main( int argc, const char ** argv ) const char* xml = "�"; XMLDocument doc; doc.Parse( xml ); - XMLTest( "Parse hex with closing tag", false, doc.Error() ); XMLPrinter printer; doc.Print( &printer ); @@ -1858,7 +1716,6 @@ int main( int argc, const char ** argv ) XMLDocument* doc = new XMLDocument(); XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() ); doc->Parse( validXml ); - XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error()); XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() ); delete doc; } @@ -2089,15 +1946,12 @@ int main( int argc, const char ** argv ) #endif FILE* perfFP = fopen("resources/dream.xml", "r"); - XMLTest("Open dream.xml", true, perfFP != 0); fseek(perfFP, 0, SEEK_END); long size = ftell(perfFP); fseek(perfFP, 0, SEEK_SET); char* mem = new char[size + 1]; - memset(mem, 0xfe, size); - size_t bytesRead = fread(mem, 1, size, perfFP); - XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead)); + fread(mem, size, 1, perfFP); fclose(perfFP); mem[size] = 0; @@ -2106,14 +1960,11 @@ int main( int argc, const char ** argv ) #else clock_t cstart = clock(); #endif - bool parseDreamXmlFailed = false; static const int COUNT = 10; for (int i = 0; i < COUNT; ++i) { XMLDocument doc; doc.Parse(mem); - parseDreamXmlFailed = parseDreamXmlFailed || doc.Error(); } - XMLTest( "Parse dream.xml", false, parseDreamXmlFailed ); #if defined( _MSC_VER ) QueryPerformanceCounter((LARGE_INTEGER*)&end); #else @@ -2130,15 +1981,13 @@ int main( int argc, const char ** argv ) #endif #if defined( _MSC_VER ) - const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT); + printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT)); #else - const double duration = (double)(cend - cstart) / (double)COUNT; + printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT); #endif - printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration); } -#if defined( _MSC_VER ) && defined( DEBUG ) - { + #if defined( _MSC_VER ) && defined( DEBUG ) _CrtMemCheckpoint( &endMemState ); _CrtMemState diffMemState; @@ -2149,8 +1998,7 @@ int main( int argc, const char ** argv ) int leaksBeforeExit = _CrtDumpMemoryLeaks(); XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit ); } - } -#endif + #endif printf ("\nPass %d, Fail %d\n", gPass, gFail); From 6c7ad3e534a86373e28db869fc12809ca17b4ef4 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 18:10:52 -0700 Subject: [PATCH 14/25] replace most compile-time platform checks with build-time checks --- CMakeLists.txt | 10 ++++++++++ config.h.cmake | 5 +++++ encfs/DirNode.cpp | 4 ++-- encfs/FileUtils.cpp | 2 +- encfs/RawFileIO.cpp | 11 ++++++++--- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a4f72..30fa9a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,12 @@ if (APPLE) endif() endif() +if (WIN32 OR APPLE) + set(DEFAULT_CASE_INSENSITIVE TRUE) +else() + set(DEFAULT_CASE_INSENSITIVE FALSE) +endif() + # Check for FUSE. find_package (FUSE REQUIRED) include_directories (${FUSE_INCLUDE_DIR}) @@ -76,6 +82,9 @@ include (CheckIncludeFileCXX) check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) +include(CheckStructHasMember) +check_struct_has_member(dirent d_type dirent.h HAVE_DIRENT_D_TYPE LANGUAGE CXX) + # Check if xattr functions take extra arguments, as they do on OSX. include (CheckCXXSourceCompiles) check_cxx_source_compiles ("#include @@ -87,6 +96,7 @@ check_cxx_source_compiles ("#include include (CheckFuncs) check_function_exists_glibc (lchmod HAVE_LCHMOD) check_function_exists_glibc (utimensat HAVE_UTIMENSAT) +check_function_exists_glibc (fdatasync HAVE_FDATASYNC) set (CMAKE_THREAD_PREFER_PTHREAD) find_package (Threads REQUIRED) diff --git a/config.h.cmake b/config.h.cmake index 1e2fdc4..8548d70 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -6,6 +6,11 @@ #cmakedefine XATTR_LLIST #cmakedefine HAVE_LCHMOD +#cmakedefine HAVE_FDATASYNC + +#cmakedefine HAVE_DIRENT_D_TYPE + +#cmakedefine DEFAULT_CASE_INSENSITIVE /* TODO: add other thread library support. */ #cmakedefine CMAKE_USE_PTHREADS_INIT diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 2457d1c..9a3c847 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -72,7 +72,7 @@ static bool _nextName(struct dirent *&de, const std::shared_ptr &dir, if (de != nullptr) { if (fileType != nullptr) { -#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) || defined(__APPLE__) +#if defined(HAVE_DIRENT_D_TYPE) *fileType = de->d_type; #else #warning "struct dirent.d_type not supported" @@ -430,7 +430,7 @@ bool DirNode::genRenameList(list &renameList, const char *fromP, ren.newPName = string(toP) + '/' + plainName; bool isDir; -#if defined(_DIRENT_HAVE_D_TYPE) +#if defined(HAVE_DIRENT_D_TYPE) if (de->d_type != DT_UNKNOWN) { isDir = (de->d_type == DT_DIR); } else diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 5080952..3fb0c8c 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -1035,7 +1035,7 @@ RootPtr createV6Config(EncFS_Context *ctx, alg = findCipherAlgorithm("AES", keySize); // If case-insensitive system, opt for Block32 filename encoding -#if defined(__APPLE__) || defined(WIN32) +#if DEFAULT_CASE_INSENSITIVE nameIOIface = BlockNameIO::CurrentInterface(true); #else nameIOIface = BlockNameIO::CurrentInterface(); diff --git a/encfs/RawFileIO.cpp b/encfs/RawFileIO.cpp index b4373fd..fc90ba2 100644 --- a/encfs/RawFileIO.cpp +++ b/encfs/RawFileIO.cpp @@ -257,9 +257,6 @@ int RawFileIO::truncate(off_t size) { if (fd >= 0 && canWrite) { res = ::ftruncate(fd, size); -#if !defined(__FreeBSD__) && !defined(__APPLE__) - ::fdatasync(fd); -#endif } else { res = ::truncate(name.c_str(), size); } @@ -276,6 +273,14 @@ int RawFileIO::truncate(off_t size) { knownSize = true; } + if (fd >= 0 && canWrite) { +#if defined(HAVE_FDATASYNC) + ::fdatasync(fd); +#else + ::fsync(fd); +#endif + } + return res; } From d3d329fb431daadf2b90cdb6a75ff64c515580fa Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 09:16:52 -0700 Subject: [PATCH 15/25] add gtest build --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30fa9a5..ffac343 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,13 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/${EASYLOGGING_DIR}/src) link_directories(${CMAKE_BINARY_DIR}/${EASYLOGGING_DIR}) set(EASYLOGGING_LIBRARIES easyloggingpp) +# TODO: add behind TEST flag. +message("-- Including vendored googletest") +set(GOOGLETEST_DIR vendor/github.com/google/googletest) +add_subdirectory(${GOOGLETEST_DIR}) +link_directories(${CMAKE_BINARY_DIR}/${GOOGLETEST_DIR}/googletest) +set(GOOGLETEST_LIBRARIES gtest) + set(SOURCE_FILES encfs/autosprintf.cpp encfs/base64.cpp From 36a4f9c4dd2b91e3e77cd0454c3d61c8227f6898 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 09:40:44 -0700 Subject: [PATCH 16/25] add initial unit test --- CMakeLists.txt | 29 ++++++++++++++++++++--------- encfs/MemoryPool_test.cpp | 12 ++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 encfs/MemoryPool_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ffac343..0ef473a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option(IWYU "Build with IWYU analysis." OFF) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") +option (BUILD_UNIT_TESTS "build EncFS unit tests" ON) option (BUILD_SHARED_LIBS "build shared libraries" OFF) option (USE_INTERNAL_TINYXML "use built-in TinyXML2" ON) option (ENABLE_NLS "compile with Native Language Support (using gettext)" ON) @@ -173,13 +174,6 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/${EASYLOGGING_DIR}/src) link_directories(${CMAKE_BINARY_DIR}/${EASYLOGGING_DIR}) set(EASYLOGGING_LIBRARIES easyloggingpp) -# TODO: add behind TEST flag. -message("-- Including vendored googletest") -set(GOOGLETEST_DIR vendor/github.com/google/googletest) -add_subdirectory(${GOOGLETEST_DIR}) -link_directories(${CMAKE_BINARY_DIR}/${GOOGLETEST_DIR}/googletest) -set(GOOGLETEST_LIBRARIES gtest) - set(SOURCE_FILES encfs/autosprintf.cpp encfs/base64.cpp @@ -236,7 +230,6 @@ if (IWYU) endif() endif() - # Set RPATH to library install path. set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}") @@ -284,5 +277,23 @@ if (POD2MAN) DESTINATION ${MAN_DESTINATION}) endif (POD2MAN) -add_custom_target(tests COMMAND ${CMAKE_CURRENT_LIST_DIR}/test.sh) +if (BUILD_UNIT_TESTS) + message("-- Including vendored googletest") + set(GOOGLETEST_DIR vendor/github.com/google/googletest) + add_subdirectory(${GOOGLETEST_DIR}) + link_directories(${CMAKE_BINARY_DIR}/${GOOGLETEST_DIR}/googletest) + message("-- Including vendored benchmark library") + set(GOOGLEBENCH_DIR vendor/github.com/google/benchmark) + set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "benchmark tests") + add_subdirectory(${GOOGLEBENCH_DIR}) + link_directories(${CMAKE_BINARY_DIR}/${GOOGLEBENCH_DIR}) + set(GOOGLEBENCH_LIBRARIES benchmark) + + file(GLOB_RECURSE TEST_SOURCES "encfs/*_test.cpp") + + add_executable (unittests ${TEST_SOURCES}) + target_link_libraries(unittests gtest gtest_main encfs) +endif () + +add_custom_target(tests COMMAND ${CMAKE_CURRENT_LIST_DIR}/test.sh) diff --git a/encfs/MemoryPool_test.cpp b/encfs/MemoryPool_test.cpp new file mode 100644 index 0000000..bae4061 --- /dev/null +++ b/encfs/MemoryPool_test.cpp @@ -0,0 +1,12 @@ +#include "gtest/gtest.h" + +#include "MemoryPool.h" + +using namespace encfs; + +TEST(MemoryPool, Allocate) { + auto block = MemoryPool::allocate(1024); + ASSERT_TRUE(block.data != nullptr); + ASSERT_TRUE(block.internalData != nullptr); + MemoryPool::release(block); +} \ No newline at end of file From aa533186e313c9d7f4f63464130409a215eac2bb Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 09:47:33 -0700 Subject: [PATCH 17/25] add first micro benchmark --- CMakeLists.txt | 6 ++++-- encfs/MemoryPool_bench.cpp | 14 ++++++++++++++ encfs/main_bench.cpp | 3 +++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 encfs/MemoryPool_bench.cpp create mode 100644 encfs/main_bench.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ef473a..1fe770f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,12 +288,14 @@ if (BUILD_UNIT_TESTS) set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "benchmark tests") add_subdirectory(${GOOGLEBENCH_DIR}) link_directories(${CMAKE_BINARY_DIR}/${GOOGLEBENCH_DIR}) - set(GOOGLEBENCH_LIBRARIES benchmark) file(GLOB_RECURSE TEST_SOURCES "encfs/*_test.cpp") - add_executable (unittests ${TEST_SOURCES}) target_link_libraries(unittests gtest gtest_main encfs) + + file(GLOB_RECURSE BENCH_SOURCES "encfs/*_bench.cpp") + add_executable (benchmarks ${BENCH_SOURCES}) + target_link_libraries(benchmarks benchmark encfs) endif () add_custom_target(tests COMMAND ${CMAKE_CURRENT_LIST_DIR}/test.sh) diff --git a/encfs/MemoryPool_bench.cpp b/encfs/MemoryPool_bench.cpp new file mode 100644 index 0000000..9326e43 --- /dev/null +++ b/encfs/MemoryPool_bench.cpp @@ -0,0 +1,14 @@ +#include "benchmark/benchmark.h" + +#include "MemoryPool.h" + +using namespace encfs; + +static void BM_MemPoolAllocate(benchmark::State& state) { + while (state.KeepRunning()) { + auto block = MemoryPool::allocate(1024); + MemoryPool::release(block); + } +} +// Register the function as a benchmark +BENCHMARK(BM_MemPoolAllocate); diff --git a/encfs/main_bench.cpp b/encfs/main_bench.cpp new file mode 100644 index 0000000..a78145f --- /dev/null +++ b/encfs/main_bench.cpp @@ -0,0 +1,3 @@ +#include "benchmark/benchmark.h" + +BENCHMARK_MAIN(); \ No newline at end of file From e329d3fef918bba72f545d8e2f2d09bb44dacbe4 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 17:48:02 -0700 Subject: [PATCH 18/25] cleanup: uniform context handling --- encfs/encfs.cpp | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/encfs/encfs.cpp b/encfs/encfs.cpp index c8b72d6..b70083a 100644 --- a/encfs/encfs.cpp +++ b/encfs/encfs.cpp @@ -75,13 +75,7 @@ static EncFS_Context *context() { * Optionally takes a pointer to the EncFS_Context, will get it from FUSE * if the argument is NULL. */ -static bool isReadOnly(EncFS_Context *ctx) { - if (ctx == nullptr) { - ctx = (EncFS_Context *)fuse_get_context()->private_data; - } - - return ctx->opts->readOnly; -} +static bool isReadOnly(EncFS_Context *ctx) { return ctx->opts->readOnly; } // helper function -- apply a functor to a cipher path, given the plain path static int withCipherPath(const char *opName, const char *path, @@ -366,7 +360,6 @@ int encfs_mkdir(const char *path, mode_t mode) { int encfs_unlink(const char *path) { EncFS_Context *ctx = context(); - if (isReadOnly(ctx)) { return -EROFS; } @@ -392,7 +385,8 @@ int _do_rmdir(EncFS_Context *, const string &cipherPath) { } int encfs_rmdir(const char *path) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withCipherPath("rmdir", path, bind(_do_rmdir, _1, _2)); @@ -533,7 +527,8 @@ int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) { } int encfs_chmod(const char *path, mode_t mode) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withCipherPath("chmod", path, bind(_do_chmod, _1, _2, mode)); @@ -545,7 +540,8 @@ int _do_chown(EncFS_Context *, const string &cyName, uid_t u, gid_t g) { } int encfs_chown(const char *path, uid_t uid, gid_t gid) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withCipherPath("chown", path, bind(_do_chown, _1, _2, uid, gid)); @@ -554,14 +550,16 @@ int encfs_chown(const char *path, uid_t uid, gid_t gid) { int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(size); } int encfs_truncate(const char *path, off_t size) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withFileNode("truncate", path, nullptr, bind(_do_truncate, _1, size)); } int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withFileNode("ftruncate", path, fi, bind(_do_truncate, _1, size)); @@ -573,7 +571,8 @@ int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) { } int encfs_utime(const char *path, struct utimbuf *buf) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withCipherPath("utime", path, bind(_do_utime, _1, _2, buf)); @@ -596,7 +595,8 @@ int _do_utimens(EncFS_Context *, const string &cyName, } int encfs_utimens(const char *path, const struct timespec ts[2]) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withCipherPath("utimens", path, bind(_do_utimens, _1, _2, ts)); @@ -705,7 +705,8 @@ int _do_fsync(FileNode *fnode, int dataSync) { } int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withFileNode("fsync", path, file, bind(_do_fsync, _1, dataSync)); @@ -720,7 +721,8 @@ int _do_write(FileNode *fnode, unsigned char *ptr, size_t size, off_t offset) { int encfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *file) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withFileNode("write", path, file, @@ -762,7 +764,10 @@ int _do_setxattr(EncFS_Context *, const string &cyName, const char *name, } int encfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) { - if (isReadOnly(NULL)) return -EROFS; + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { + return -EROFS; + } (void)flags; return withCipherPath("setxattr", path, bind(_do_setxattr, _1, _2, name, value, size, position)); @@ -774,7 +779,8 @@ int _do_setxattr(EncFS_Context *, const string &cyName, const char *name, } int encfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } return withCipherPath("setxattr", path, @@ -834,7 +840,8 @@ int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) { } int encfs_removexattr(const char *path, const char *name) { - if (isReadOnly(nullptr)) { + EncFS_Context *ctx = context(); + if (isReadOnly(ctx)) { return -EROFS; } From 0111725d48246f54cc79d64e22d3a497b08f0118 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 18:18:13 -0700 Subject: [PATCH 19/25] make cipher tests into unit tests --- encfs/Cipher_test.cpp | 195 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 encfs/Cipher_test.cpp diff --git a/encfs/Cipher_test.cpp b/encfs/Cipher_test.cpp new file mode 100644 index 0000000..00d45b0 --- /dev/null +++ b/encfs/Cipher_test.cpp @@ -0,0 +1,195 @@ +#include "gtest/gtest.h" + +#include "BlockNameIO.h" +#include "Cipher.h" +#include "CipherKey.h" +#include "DirNode.h" +#include "FSConfig.h" +#include "FileUtils.h" +#include "StreamNameIO.h" + +using namespace encfs; +using namespace testing; +using std::string; + +const int FSBlockSize = 256; +const char TEST_ROOTDIR[] = "/foo"; + +static void testNameCoding(DirNode &dirNode) { + // encrypt a name + const char *name[] = { + "1234567", "12345678", "123456789", + "123456789ABCDEF", "123456789ABCDEF0", "123456789ABCDEF01", + "test-name", "test-name2", "test", + "../test", "/foo/bar/blah", "test-name.21", + "test-name.22", "test-name.o", "1.test", + "2.test", "a/b/c/d", "a/c/d/e", + "b/c/d/e", "b/a/c/d", NULL}; + + const char **orig = name; + while (*orig) { + string encName = dirNode.relativeCipherPath(*orig); + + // decrypt name + string decName = dirNode.plainPath(encName.c_str()); + + ASSERT_EQ(decName, *orig); + orig++; + } +} + +class CipherTest : public TestWithParam { + protected: + virtual void SetUp() { + Cipher::CipherAlgorithm alg = GetParam(); + cipher = Cipher::New(alg.name, alg.keyLength.closest(256)); + } + virtual void TearDown() {} + std::shared_ptr cipher; +}; + +TEST_P(CipherTest, SaveRestoreKey) { + auto key = cipher->newRandomKey(); + + auto encodingKey = cipher->newRandomKey(); + int encodedKeySize = cipher->encodedKeySize(); + unsigned char keyBuf[encodedKeySize]; + + cipher->writeKey(key, keyBuf, encodingKey); + auto restored = cipher->readKey(keyBuf, encodingKey); + EXPECT_TRUE(restored); + EXPECT_TRUE(cipher->compareKey(key, restored)); +} + +TEST_P(CipherTest, NameStreamEncoding) { + auto key = cipher->newRandomKey(); + + FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); + fsCfg->cipher = cipher; + fsCfg->key = key; + fsCfg->config.reset(new EncFSConfig); + fsCfg->config->blockSize = FSBlockSize; + fsCfg->opts.reset(new EncFS_Opts); + fsCfg->opts->idleTracking = false; + fsCfg->config->uniqueIV = false; + + fsCfg->nameCoding.reset( + new StreamNameIO(StreamNameIO::CurrentInterface(), cipher, key)); + + { + fsCfg->nameCoding->setChainedNameIV(true); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); + testNameCoding(dirNode); + } + { + fsCfg->nameCoding->setChainedNameIV(false); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); + testNameCoding(dirNode); + } +} + +TEST_P(CipherTest, NameBlockEncoding) { + auto key = cipher->newRandomKey(); + + FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); + fsCfg->cipher = cipher; + fsCfg->key = key; + fsCfg->config.reset(new EncFSConfig); + fsCfg->config->blockSize = FSBlockSize; + fsCfg->opts.reset(new EncFS_Opts); + fsCfg->opts->idleTracking = false; + fsCfg->config->uniqueIV = false; + fsCfg->nameCoding.reset(new BlockNameIO( + BlockNameIO::CurrentInterface(), cipher, key, cipher->cipherBlockSize())); + + { + fsCfg->nameCoding->setChainedNameIV(true); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); + testNameCoding(dirNode); + } + { + fsCfg->nameCoding->setChainedNameIV(false); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); + testNameCoding(dirNode); + } +} + +TEST_P(CipherTest, NameBlockBase32Encoding) { + auto key = cipher->newRandomKey(); + + FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); + fsCfg->cipher = cipher; + fsCfg->key = key; + fsCfg->config.reset(new EncFSConfig); + fsCfg->config->blockSize = FSBlockSize; + fsCfg->opts.reset(new EncFS_Opts); + fsCfg->opts->idleTracking = false; + fsCfg->config->uniqueIV = false; + fsCfg->nameCoding.reset(new BlockNameIO(BlockNameIO::CurrentInterface(), + cipher, key, + cipher->cipherBlockSize(), true)); + + { + fsCfg->nameCoding->setChainedNameIV(true); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); + testNameCoding(dirNode); + } + + { + fsCfg->nameCoding->setChainedNameIV(false); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); + testNameCoding(dirNode); + } +} + +TEST_P(CipherTest, ConfigLoadStore) { + auto key = cipher->newRandomKey(); + CipherKey encodingKey = cipher->newRandomKey(); + int encodedKeySize = cipher->encodedKeySize(); + unsigned char keyBuf[encodedKeySize]; + + cipher->writeKey(key, keyBuf, encodingKey); + + // store in config struct.. + EncFSConfig cfg; + cfg.cipherIface = cipher->interface(); + cfg.keySize = 8 * cipher->keySize(); + cfg.blockSize = FSBlockSize; + cfg.assignKeyData(keyBuf, encodedKeySize); + + // save config + // Creation of a temporary file should be more platform independent. On + // c++17 we could use std::filesystem. + std::string name = "/tmp/encfstestXXXXXX"; + int tmpFd = mkstemp(&name[0]); + EXPECT_GE(tmpFd, 0); + // mkstemp opens the temporary file, but we only need its name -> close it + EXPECT_EQ(close(tmpFd), 0); + { + auto ok = writeV6Config(name.c_str(), &cfg); + EXPECT_TRUE(ok); + } + + // read back in and check everything.. + EncFSConfig cfg2; + { + auto ok = readV6Config(name.c_str(), &cfg2, nullptr); + EXPECT_TRUE(ok); + } + // delete the temporary file where we stored the config + EXPECT_EQ(unlink(name.c_str()), 0); + + // check.. + EXPECT_TRUE(cfg.cipherIface.implements(cfg2.cipherIface)); + EXPECT_EQ(cfg.keySize, cfg2.keySize); + EXPECT_EQ(cfg.blockSize, cfg2.blockSize); + + // try decoding key.. + + CipherKey key2 = cipher->readKey(cfg2.getKeyData(), encodingKey); + EXPECT_TRUE(key2); + EXPECT_TRUE(cipher->compareKey(key, key2)); +} + +INSTANTIATE_TEST_CASE_P(CipherKey, CipherTest, + ValuesIn(Cipher::GetAlgorithmList())); From 24ce1006965fe4ac880e0244be3567ba3b9deacf Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 22:26:58 -0400 Subject: [PATCH 20/25] run unit tests with cmake's test target --- CMakeLists.txt | 3 +++ circle.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fe770f..b349cfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,6 +278,8 @@ if (POD2MAN) endif (POD2MAN) if (BUILD_UNIT_TESTS) + enable_testing() + message("-- Including vendored googletest") set(GOOGLETEST_DIR vendor/github.com/google/googletest) add_subdirectory(${GOOGLETEST_DIR}) @@ -292,6 +294,7 @@ if (BUILD_UNIT_TESTS) file(GLOB_RECURSE TEST_SOURCES "encfs/*_test.cpp") add_executable (unittests ${TEST_SOURCES}) target_link_libraries(unittests gtest gtest_main encfs) + add_test(unit unittests) file(GLOB_RECURSE BENCH_SOURCES "encfs/*_bench.cpp") add_executable (benchmarks ${BENCH_SOURCES}) diff --git a/circle.yml b/circle.yml index 133221b..04d5f28 100644 --- a/circle.yml +++ b/circle.yml @@ -10,5 +10,5 @@ dependencies: test: override: - bash ./ci/config.sh - - cd build && make && ./checkops && make install + - cd build && make && make test && ./checkops && make install - /tmp/encfs/bin/encfsctl --version From a98123a3a7da598d2191f816fe958cdcbb319391 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 22:36:13 -0400 Subject: [PATCH 21/25] Squashed 'vendor/github.com/google/benchmark/' content from commit 163ce4af git-subtree-dir: vendor/github.com/google/benchmark git-subtree-split: 163ce4af68fd7d100e7e54ab65abd50971183009 --- .clang-format | 5 + .gitignore | 46 + .travis-libcxx-setup.sh | 28 + .travis.yml | 157 ++++ .ycm_extra_conf.py | 115 +++ AUTHORS | 40 + CMakeLists.txt | 202 +++++ CONTRIBUTING.md | 58 ++ CONTRIBUTORS | 59 ++ LICENSE | 202 +++++ README.md | 726 ++++++++++++++++ appveyor.yml | 56 ++ cmake/AddCXXCompilerFlag.cmake | 64 ++ cmake/CXXFeatureCheck.cmake | 46 + cmake/Config.cmake.in | 1 + cmake/GetGitVersion.cmake | 51 ++ cmake/gnu_posix_regex.cpp | 12 + cmake/posix_regex.cpp | 14 + cmake/std_regex.cpp | 10 + cmake/steady_clock.cpp | 7 + cmake/thread_safety_attributes.cpp | 4 + docs/tools.md | 59 ++ include/benchmark/benchmark.h | 1210 +++++++++++++++++++++++++++ include/benchmark/benchmark_api.h | 27 + include/benchmark/reporter.h | 27 + mingw.py | 320 +++++++ src/CMakeLists.txt | 78 ++ src/arraysize.h | 33 + src/benchmark.cc | 715 ++++++++++++++++ src/benchmark_api_internal.h | 46 + src/benchmark_register.cc | 467 +++++++++++ src/check.h | 79 ++ src/colorprint.cc | 188 +++++ src/colorprint.h | 33 + src/commandlineflags.cc | 218 +++++ src/commandlineflags.h | 79 ++ src/complexity.cc | 324 +++++++ src/complexity.h | 60 ++ src/console_reporter.cc | 180 ++++ src/counter.cc | 68 ++ src/counter.h | 26 + src/csv_reporter.cc | 149 ++++ src/cycleclock.h | 172 ++++ src/internal_macros.h | 57 ++ src/json_reporter.cc | 168 ++++ src/log.h | 73 ++ src/mutex.h | 155 ++++ src/re.h | 140 ++++ src/reporter.cc | 68 ++ src/sleep.cc | 51 ++ src/sleep.h | 15 + src/stat.h | 310 +++++++ src/string_util.cc | 172 ++++ src/string_util.h | 40 + src/sysinfo.cc | 355 ++++++++ src/sysinfo.h | 10 + src/timers.cc | 212 +++++ src/timers.h | 48 ++ test/CMakeLists.txt | 170 ++++ test/basic_test.cc | 99 +++ test/benchmark_test.cc | 240 ++++++ test/complexity_test.cc | 167 ++++ test/cxx03_test.cc | 48 ++ test/diagnostics_test.cc | 64 ++ test/donotoptimize_test.cc | 52 ++ test/filter_test.cc | 104 +++ test/fixture_test.cc | 49 ++ test/map_test.cc | 56 ++ test/multiple_ranges_test.cc | 74 ++ test/options_test.cc | 65 ++ test/output_test.h | 201 +++++ test/output_test_helper.cc | 423 ++++++++++ test/register_benchmark_test.cc | 182 ++++ test/reporter_output_test.cc | 256 ++++++ test/skip_with_error_test.cc | 150 ++++ test/user_counters_tabular_test.cc | 250 ++++++ test/user_counters_test.cc | 217 +++++ tools/compare_bench.py | 68 ++ tools/gbench/Inputs/test1_run1.json | 60 ++ tools/gbench/Inputs/test1_run2.json | 60 ++ tools/gbench/__init__.py | 8 + tools/gbench/report.py | 146 ++++ tools/gbench/util.py | 159 ++++ 83 files changed, 11703 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 .travis-libcxx-setup.sh create mode 100644 .travis.yml create mode 100644 .ycm_extra_conf.py create mode 100644 AUTHORS create mode 100644 CMakeLists.txt create mode 100644 CONTRIBUTING.md create mode 100644 CONTRIBUTORS create mode 100644 LICENSE create mode 100644 README.md create mode 100644 appveyor.yml create mode 100644 cmake/AddCXXCompilerFlag.cmake create mode 100644 cmake/CXXFeatureCheck.cmake create mode 100644 cmake/Config.cmake.in create mode 100644 cmake/GetGitVersion.cmake create mode 100644 cmake/gnu_posix_regex.cpp create mode 100644 cmake/posix_regex.cpp create mode 100644 cmake/std_regex.cpp create mode 100644 cmake/steady_clock.cpp create mode 100644 cmake/thread_safety_attributes.cpp create mode 100644 docs/tools.md create mode 100644 include/benchmark/benchmark.h create mode 100644 include/benchmark/benchmark_api.h create mode 100644 include/benchmark/reporter.h create mode 100644 mingw.py create mode 100644 src/CMakeLists.txt create mode 100644 src/arraysize.h create mode 100644 src/benchmark.cc create mode 100644 src/benchmark_api_internal.h create mode 100644 src/benchmark_register.cc create mode 100644 src/check.h create mode 100644 src/colorprint.cc create mode 100644 src/colorprint.h create mode 100644 src/commandlineflags.cc create mode 100644 src/commandlineflags.h create mode 100644 src/complexity.cc create mode 100644 src/complexity.h create mode 100644 src/console_reporter.cc create mode 100644 src/counter.cc create mode 100644 src/counter.h create mode 100644 src/csv_reporter.cc create mode 100644 src/cycleclock.h create mode 100644 src/internal_macros.h create mode 100644 src/json_reporter.cc create mode 100644 src/log.h create mode 100644 src/mutex.h create mode 100644 src/re.h create mode 100644 src/reporter.cc create mode 100644 src/sleep.cc create mode 100644 src/sleep.h create mode 100644 src/stat.h create mode 100644 src/string_util.cc create mode 100644 src/string_util.h create mode 100644 src/sysinfo.cc create mode 100644 src/sysinfo.h create mode 100644 src/timers.cc create mode 100644 src/timers.h create mode 100644 test/CMakeLists.txt create mode 100644 test/basic_test.cc create mode 100644 test/benchmark_test.cc create mode 100644 test/complexity_test.cc create mode 100644 test/cxx03_test.cc create mode 100644 test/diagnostics_test.cc create mode 100644 test/donotoptimize_test.cc create mode 100644 test/filter_test.cc create mode 100644 test/fixture_test.cc create mode 100644 test/map_test.cc create mode 100644 test/multiple_ranges_test.cc create mode 100644 test/options_test.cc create mode 100644 test/output_test.h create mode 100644 test/output_test_helper.cc create mode 100644 test/register_benchmark_test.cc create mode 100644 test/reporter_output_test.cc create mode 100644 test/skip_with_error_test.cc create mode 100644 test/user_counters_tabular_test.cc create mode 100644 test/user_counters_test.cc create mode 100755 tools/compare_bench.py create mode 100644 tools/gbench/Inputs/test1_run1.json create mode 100644 tools/gbench/Inputs/test1_run2.json create mode 100644 tools/gbench/__init__.py create mode 100644 tools/gbench/report.py create mode 100644 tools/gbench/util.py diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..4b3f13f --- /dev/null +++ b/.clang-format @@ -0,0 +1,5 @@ +--- +Language: Cpp +BasedOnStyle: Google +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c1b4f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +*.a +*.so +*.so.?* +*.dll +*.exe +*.dylib +*.cmake +!/cmake/*.cmake +*~ +*.pyc +__pycache__ + +# lcov +*.lcov +/lcov + +# cmake files. +/Testing +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake + +# makefiles. +Makefile + +# in-source build. +bin/ +lib/ +/test/*_test + +# exuberant ctags. +tags + +# YouCompleteMe configuration. +.ycm_extra_conf.pyc + +# ninja generated files. +.ninja_deps +.ninja_log +build.ninja +install_manifest.txt +rules.ninja + +# out-of-source build top-level folders. +build/ +_build/ diff --git a/.travis-libcxx-setup.sh b/.travis-libcxx-setup.sh new file mode 100644 index 0000000..a591743 --- /dev/null +++ b/.travis-libcxx-setup.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Install a newer CMake version +curl -sSL https://cmake.org/files/v3.6/cmake-3.6.1-Linux-x86_64.sh -o install-cmake.sh +chmod +x install-cmake.sh +sudo ./install-cmake.sh --prefix=/usr/local --skip-license + +# Checkout LLVM sources +git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm-source +git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm-source/projects/libcxx +git clone --depth=1 https://github.com/llvm-mirror/libcxxabi.git llvm-source/projects/libcxxabi + +# Setup libc++ options +if [ -z "$BUILD_32_BITS" ]; then + export BUILD_32_BITS=OFF && echo disabling 32 bit build +fi + +# Build and install libc++ (Use unstable ABI for better sanitizer coverage) +mkdir llvm-build && cd llvm-build +cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr \ + -DLIBCXX_ABI_UNSTABLE=ON \ + -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ + -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ + ../llvm-source +make cxx -j2 +sudo make install-cxxabi install-cxx +cd ../ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..36df088 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,157 @@ +sudo: required +dist: trusty +language: cpp + +env: + global: + - /usr/local/bin:$PATH + +matrix: + include: + - compiler: gcc + addons: + apt: + packages: + - lcov + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Coverage + - compiler: gcc + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Debug + - compiler: gcc + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Release + - compiler: gcc + addons: + apt: + packages: + - g++-multilib + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Debug BUILD_32_BITS=ON + - compiler: gcc + addons: + apt: + packages: + - g++-multilib + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Release BUILD_32_BITS=ON + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: + - COMPILER=g++-6 C_COMPILER=gcc-6 BUILD_TYPE=Debug + - EXTRA_FLAGS="-fno-omit-frame-pointer -g -O2 -fsanitize=undefined,address -fuse-ld=gold" + - compiler: clang + env: COMPILER=clang++ C_COMPILER=clang BUILD_TYPE=Debug + - compiler: clang + env: COMPILER=clang++ C_COMPILER=clang BUILD_TYPE=Release + # Clang w/ libc++ + - compiler: clang + addons: + apt: + packages: + clang-3.8 + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 + - EXTRA_FLAGS="-stdlib=libc++" + - compiler: clang + addons: + apt: + packages: + clang-3.8 + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release + - LIBCXX_BUILD=1 + - EXTRA_FLAGS="-stdlib=libc++" + # Clang w/ 32bit libc++ + - compiler: clang + addons: + apt: + packages: + - clang-3.8 + - g++-multilib + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-stdlib=libc++ -m32" + # Clang w/ 32bit libc++ + - compiler: clang + addons: + apt: + packages: + - clang-3.8 + - g++-multilib + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release + - LIBCXX_BUILD=1 + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-stdlib=libc++ -m32" + # Clang w/ libc++, ASAN, UBSAN + - compiler: clang + addons: + apt: + packages: + clang-3.8 + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 LIBCXX_SANITIZER="Undefined;Address" + - EXTRA_FLAGS="-stdlib=libc++ -g -O2 -fno-omit-frame-pointer -fsanitize=undefined,address -fno-sanitize-recover=all" + - UBSAN_OPTIONS=print_stacktrace=1 + # Clang w/ libc++ and MSAN + - compiler: clang + addons: + apt: + packages: + clang-3.8 + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 LIBCXX_SANITIZER=MemoryWithOrigins + - EXTRA_FLAGS="-stdlib=libc++ -g -O2 -fno-omit-frame-pointer -fsanitize=memory -fsanitize-memory-track-origins" + # Clang w/ libc++ and MSAN + - compiler: clang + addons: + apt: + packages: + clang-3.8 + env: + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=RelWithDebInfo + - LIBCXX_BUILD=1 LIBCXX_SANITIZER=Thread + - EXTRA_FLAGS="-stdlib=libc++ -g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" + + - os: osx + osx_image: xcode8.3 + compiler: clang + env: + - COMPILER=clang++ BUILD_TYPE=Debug + - os: osx + osx_image: xcode8.3 + compiler: clang + env: + - COMPILER=clang++ BUILD_TYPE=Release + +before_script: + - if [ -z "$BUILD_32_BITS" ]; then + export BUILD_32_BITS=OFF && echo disabling 32 bit build; + fi + - if [ -n "${LIBCXX_BUILD}" ]; then + source .travis-libcxx-setup.sh; + fi + - mkdir build && cd build + +install: + - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then + PATH=~/.local/bin:${PATH}; + pip install --user --upgrade pip; + pip install --user cpp-coveralls; + fi + +script: + - cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS}" -DBENCHMARK_BUILD_32_BITS=${BUILD_32_BITS} .. + - make + - ctest -C ${BUILD_TYPE} --output-on-failure + +after_success: + - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then + coveralls --include src --include include --gcov-options '\-lp' --root .. --build-root .; + fi diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 0000000..8619435 --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,115 @@ +import os +import ycm_core + +# These are the compilation flags that will be used in case there's no +# compilation database set (by default, one is not set). +# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. +flags = [ +'-Wall', +'-Werror', +'-pendantic-errors', +'-std=c++0x', +'-fno-strict-aliasing', +'-O3', +'-DNDEBUG', +# ...and the same thing goes for the magic -x option which specifies the +# language that the files to be compiled are written in. This is mostly +# relevant for c++ headers. +# For a C project, you would set this to 'c' instead of 'c++'. +'-x', 'c++', +'-I', 'include', +'-isystem', '/usr/include', +'-isystem', '/usr/local/include', +] + + +# Set this to the absolute path to the folder (NOT the file!) containing the +# compile_commands.json file to use that instead of 'flags'. See here for +# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# +# Most projects will NOT need to set this to anything; you can just change the +# 'flags' list of compilation flags. Notice that YCM itself uses that approach. +compilation_database_folder = '' + +if os.path.exists( compilation_database_folder ): + database = ycm_core.CompilationDatabase( compilation_database_folder ) +else: + database = None + +SOURCE_EXTENSIONS = [ '.cc' ] + +def DirectoryOfThisScript(): + return os.path.dirname( os.path.abspath( __file__ ) ) + + +def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): + if not working_directory: + return list( flags ) + new_flags = [] + make_next_absolute = False + path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith( '/' ): + new_flag = os.path.join( working_directory, flag ) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith( path_flag ): + path = flag[ len( path_flag ): ] + new_flag = path_flag + os.path.join( working_directory, path ) + break + + if new_flag: + new_flags.append( new_flag ) + return new_flags + + +def IsHeaderFile( filename ): + extension = os.path.splitext( filename )[ 1 ] + return extension in [ '.h', '.hxx', '.hpp', '.hh' ] + + +def GetCompilationInfoForFile( filename ): + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile( filename ): + basename = os.path.splitext( filename )[ 0 ] + for extension in SOURCE_EXTENSIONS: + replacement_file = basename + extension + if os.path.exists( replacement_file ): + compilation_info = database.GetCompilationInfoForFile( + replacement_file ) + if compilation_info.compiler_flags_: + return compilation_info + return None + return database.GetCompilationInfoForFile( filename ) + + +def FlagsForFile( filename, **kwargs ): + if database: + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile( filename ) + if not compilation_info: + return None + + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_ ) + else: + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ae278df --- /dev/null +++ b/AUTHORS @@ -0,0 +1,40 @@ +# This is the official list of benchmark authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Albert Pretorius +Arne Beer +Christopher Seymour +David Coeurjolly +Dominic Hamon +Eric Fiselier +Eugene Zhuk +Evgeny Safronov +Felix Homann +Google Inc. +International Business Machines Corporation +Ismael Jimenez Martinez +Jern-Kuan Leong +Joao Paulo Magalhaes +JianXiong Zhou +Jussi Knuuttila +Kaito Udagawa +Lei Xu +Matt Clarkson +Maxim Vafin +Nick Hutchinson +Oleksandr Sochka +Paul Redmond +Radoslav Yovchev +Shuo Chen +Yixuan Qiu +Yusuke Suzuki +Dirac Research +Zbigniew Skowron +Dominik Czarnota diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f7f1566 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,202 @@ +cmake_minimum_required (VERSION 2.8.12) + +project (benchmark) + +foreach(p + CMP0054 # CMake 3.1 + CMP0056 # export EXE_LINKER_FLAGS to try_run + ) + if(POLICY ${p}) + cmake_policy(SET ${p} NEW) + endif() +endforeach() + +option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) +option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) +option(BENCHMARK_ENABLE_LTO "Enable link time optimisation of the benchmark library." OFF) +option(BENCHMARK_USE_LIBCXX "Build and test using libc++ as the standard library." OFF) +option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library" OFF) + +# Make sure we can import out CMake functions +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +# Read the git tags to determine the project version +include(GetGitVersion) +get_git_version(GIT_VERSION) + +# Tell the user what versions we are using +string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${GIT_VERSION}) +message("-- Version: ${VERSION}") + +# The version of the libraries +set(GENERIC_LIB_VERSION ${VERSION}) +string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION) + +# Import our CMake modules +include(CheckCXXCompilerFlag) +include(AddCXXCompilerFlag) +include(CXXFeatureCheck) + +if (BENCHMARK_BUILD_32_BITS) + add_required_cxx_compiler_flag(-m32) +endif() + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # Turn compiler warnings up to 11 + string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + + if (NOT BENCHMARK_ENABLE_EXCEPTIONS) + add_cxx_compiler_flag(-EHs-) + add_cxx_compiler_flag(-EHa-) + endif() + # Link time optimisation + if (BENCHMARK_ENABLE_LTO) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL") + string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}") + set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") + string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") + set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") + string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") + + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /GL") + set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "${CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /LTCG") + set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG") + endif() +else() + # Try and enable C++11. Don't use C++14 because it doesn't work in some + # configurations. + add_cxx_compiler_flag(-std=c++11) + if (NOT HAVE_CXX_FLAG_STD_CXX11) + add_cxx_compiler_flag(-std=c++0x) + endif() + + # Turn compiler warnings up to 11 + add_cxx_compiler_flag(-Wall) + + add_cxx_compiler_flag(-Wextra) + add_cxx_compiler_flag(-Wshadow) + add_cxx_compiler_flag(-Werror RELEASE) + add_cxx_compiler_flag(-Werror RELWITHDEBINFO) + add_cxx_compiler_flag(-Werror MINSIZEREL) + add_cxx_compiler_flag(-pedantic) + add_cxx_compiler_flag(-pedantic-errors) + add_cxx_compiler_flag(-Wshorten-64-to-32) + add_cxx_compiler_flag(-Wfloat-equal) + add_cxx_compiler_flag(-fstrict-aliasing) + if (NOT BENCHMARK_ENABLE_EXCEPTIONS) + add_cxx_compiler_flag(-fno-exceptions) + endif() + if (NOT BENCHMARK_USE_LIBCXX) + add_cxx_compiler_flag(-Wzero-as-null-pointer-constant) + endif() + if (HAVE_CXX_FLAG_FSTRICT_ALIASING) + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing + add_cxx_compiler_flag(-Wstrict-aliasing) + endif() + endif() + # ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden + # (because of deprecated overload) + add_cxx_compiler_flag(-wd654) + add_cxx_compiler_flag(-Wthread-safety) + if (HAVE_CXX_FLAG_WTHREAD_SAFETY) + cxx_feature_check(THREAD_SAFETY_ATTRIBUTES) + endif() + + # On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a + # predefined macro, which turns on all of the wonderful libc extensions. + # However g++ doesn't do this in Cygwin so we have to define it ourselfs + # since we depend on GNU/POSIX/BSD extensions. + if (CYGWIN) + add_definitions(-D_GNU_SOURCE=1) + endif() + + # Link time optimisation + if (BENCHMARK_ENABLE_LTO) + add_cxx_compiler_flag(-flto) + if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + find_program(GCC_AR gcc-ar) + if (GCC_AR) + set(CMAKE_AR ${GCC_AR}) + endif() + find_program(GCC_RANLIB gcc-ranlib) + if (GCC_RANLIB) + set(CMAKE_RANLIB ${GCC_RANLIB}) + endif() + endif() + endif() + + # Coverage build type + set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING + "Flags used by the C++ compiler during coverage builds." + FORCE) + set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used for linking binaries during coverage builds." + FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used by the shared libraries linker during coverage builds." + FORCE) + mark_as_advanced( + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE) + set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage." + FORCE) + add_cxx_compiler_flag(--coverage COVERAGE) +endif() + +if (BENCHMARK_USE_LIBCXX) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_cxx_compiler_flag(-stdlib=libc++) + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + add_cxx_compiler_flag(-nostdinc++) + message("libc++ header path must be manually specified using CMAKE_CXX_FLAGS") + # Adding -nodefaultlibs directly to CMAKE__LINKER_FLAGS will break + # configuration checks such as 'find_package(Threads)' + list(APPEND BENCHMARK_CXX_LINKER_FLAGS -nodefaultlibs) + # -lc++ cannot be added directly to CMAKE__LINKER_FLAGS because + # linker flags appear before all linker inputs and -lc++ must appear after. + list(APPEND BENCHMARK_CXX_LIBRARIES c++) + else() + message(FATAL "-DBENCHMARK_USE_LIBCXX:BOOL=ON is not supported for compiler") + endif() +endif(BENCHMARK_USE_LIBCXX) + +# C++ feature checks +# Determine the correct regular expression engine to use +cxx_feature_check(STD_REGEX) +cxx_feature_check(GNU_POSIX_REGEX) +cxx_feature_check(POSIX_REGEX) +if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) + message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") +endif() +if (NOT BENCHMARK_ENABLE_EXCEPTIONS AND HAVE_STD_REGEX + AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) + message(WARNING "Using std::regex with exceptions disabled is not fully supported") +endif() +cxx_feature_check(STEADY_CLOCK) +# Ensure we have pthreads +find_package(Threads REQUIRED) + +# Set up directories +include_directories(${PROJECT_SOURCE_DIR}/include) + +# Build the targets +add_subdirectory(src) + +if (BENCHMARK_ENABLE_TESTING) + enable_testing() + add_subdirectory(test) +endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..43de4c9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# How to contribute # + +We'd love to accept your patches and contributions to this project. There are +a just a few small guidelines you need to follow. + + +## Contributor License Agreement ## + +Contributions to any Google project must be accompanied by a Contributor +License Agreement. This is not a copyright **assignment**, it simply gives +Google permission to use and redistribute your contributions as part of the +project. + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual + CLA][]. + + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA][]. + +You generally only need to submit a CLA once, so if you've already submitted +one (even if it was for a different project), you probably don't need to do it +again. + +[individual CLA]: https://developers.google.com/open-source/cla/individual +[corporate CLA]: https://developers.google.com/open-source/cla/corporate + +Once your CLA is submitted (or if you already submitted one for +another Google project), make a commit adding yourself to the +[AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part +of your first [pull request][]. + +[AUTHORS]: AUTHORS +[CONTRIBUTORS]: CONTRIBUTORS + + +## Submitting a patch ## + + 1. It's generally best to start by opening a new issue describing the bug or + feature you're intending to fix. Even if you think it's relatively minor, + it's helpful to know what people are working on. Mention in the initial + issue that you are planning to work on that bug or feature so that it can + be assigned to you. + + 1. Follow the normal process of [forking][] the project, and setup a new + branch to work in. It's important that each group of changes be done in + separate branches in order to ensure that a pull request only includes the + commits related to that bug or feature. + + 1. Do your best to have [well-formed commit messages][] for each change. + This provides consistency throughout the project, and ensures that commit + messages are able to be formatted properly by various git tools. + + 1. Finally, push the commits to your fork and submit a [pull request][]. + +[forking]: https://help.github.com/articles/fork-a-repo +[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[pull request]: https://help.github.com/articles/creating-a-pull-request diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..9abb608 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,59 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. +# +# Names should be added to this file as: +# Name +# +# Please keep the list sorted. + +Albert Pretorius +Arne Beer +Billy Robert O'Neal III +Chris Kennelly +Christopher Seymour +David Coeurjolly +Dominic Hamon +Eric Fiselier +Eugene Zhuk +Evgeny Safronov +Felix Homann +Ismael Jimenez Martinez +Jern-Kuan Leong +Joao Paulo Magalhaes +JianXiong Zhou +Jussi Knuuttila +Kaito Udagawa +Kai Wolf +Lei Xu +Matt Clarkson +Maxim Vafin +Nick Hutchinson +Oleksandr Sochka +Pascal Leroy +Paul Redmond +Pierre Phaneuf +Radoslav Yovchev +Ray Glover +Shuo Chen +Tom Madams +Yixuan Qiu +Yusuke Suzuki +Tobias Ulvgård +Zbigniew Skowron +Dominik Czarnota diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2430d93 --- /dev/null +++ b/README.md @@ -0,0 +1,726 @@ +# benchmark +[![Build Status](https://travis-ci.org/google/benchmark.svg?branch=master)](https://travis-ci.org/google/benchmark) +[![Build status](https://ci.appveyor.com/api/projects/status/u0qsyp7t1tk7cpxs/branch/master?svg=true)](https://ci.appveyor.com/project/google/benchmark/branch/master) +[![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark) + +A library to support the benchmarking of functions, similar to unit-tests. + +Discussion group: https://groups.google.com/d/forum/benchmark-discuss + +IRC channel: https://freenode.net #googlebenchmark + +[Known issues and common problems](#known-issues) + +[Additional Tooling Documentation](docs/tools.md) + +## Example usage +### Basic usage +Define a function that executes the code to be measured. + +```c++ +static void BM_StringCreation(benchmark::State& state) { + while (state.KeepRunning()) + std::string empty_string; +} +// Register the function as a benchmark +BENCHMARK(BM_StringCreation); + +// Define another benchmark +static void BM_StringCopy(benchmark::State& state) { + std::string x = "hello"; + while (state.KeepRunning()) + std::string copy(x); +} +BENCHMARK(BM_StringCopy); + +BENCHMARK_MAIN(); +``` + +### Passing arguments +Sometimes a family of benchmarks can be implemented with just one routine that +takes an extra argument to specify which one of the family of benchmarks to +run. For example, the following code defines a family of benchmarks for +measuring the speed of `memcpy()` calls of different lengths: + +```c++ +static void BM_memcpy(benchmark::State& state) { + char* src = new char[state.range(0)]; + char* dst = new char[state.range(0)]; + memset(src, 'x', state.range(0)); + while (state.KeepRunning()) + memcpy(dst, src, state.range(0)); + state.SetBytesProcessed(int64_t(state.iterations()) * + int64_t(state.range(0))); + delete[] src; + delete[] dst; +} +BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); +``` + +The preceding code is quite repetitive, and can be replaced with the following +short-hand. The following invocation will pick a few appropriate arguments in +the specified range and will generate a benchmark for each such argument. + +```c++ +BENCHMARK(BM_memcpy)->Range(8, 8<<10); +``` + +By default the arguments in the range are generated in multiples of eight and +the command above selects [ 8, 64, 512, 4k, 8k ]. In the following code the +range multiplier is changed to multiples of two. + +```c++ +BENCHMARK(BM_memcpy)->RangeMultiplier(2)->Range(8, 8<<10); +``` +Now arguments generated are [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ]. + +You might have a benchmark that depends on two or more inputs. For example, the +following code defines a family of benchmarks for measuring the speed of set +insertion. + +```c++ +static void BM_SetInsert(benchmark::State& state) { + while (state.KeepRunning()) { + state.PauseTiming(); + std::set data = ConstructRandomSet(state.range(0)); + state.ResumeTiming(); + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert) + ->Args({1<<10, 1}) + ->Args({1<<10, 8}) + ->Args({1<<10, 64}) + ->Args({1<<10, 512}) + ->Args({8<<10, 1}) + ->Args({8<<10, 8}) + ->Args({8<<10, 64}) + ->Args({8<<10, 512}); +``` + +The preceding code is quite repetitive, and can be replaced with the following +short-hand. The following macro will pick a few appropriate arguments in the +product of the two specified ranges and will generate a benchmark for each such +pair. + +```c++ +BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {1, 512}}); +``` + +For more complex patterns of inputs, passing a custom function to `Apply` allows +programmatic specification of an arbitrary set of arguments on which to run the +benchmark. The following example enumerates a dense range on one parameter, +and a sparse range on the second. + +```c++ +static void CustomArguments(benchmark::internal::Benchmark* b) { + for (int i = 0; i <= 10; ++i) + for (int j = 32; j <= 1024*1024; j *= 8) + b->Args({i, j}); +} +BENCHMARK(BM_SetInsert)->Apply(CustomArguments); +``` + +### Calculate asymptotic complexity (Big O) +Asymptotic complexity might be calculated for a family of benchmarks. The +following code will calculate the coefficient for the high-order term in the +running time and the normalized root-mean square error of string comparison. + +```c++ +static void BM_StringCompare(benchmark::State& state) { + std::string s1(state.range(0), '-'); + std::string s2(state.range(0), '-'); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(s1.compare(s2)); + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_StringCompare) + ->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(benchmark::oN); +``` + +As shown in the following invocation, asymptotic complexity might also be +calculated automatically. + +```c++ +BENCHMARK(BM_StringCompare) + ->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(); +``` + +The following code will specify asymptotic complexity with a lambda function, +that might be used to customize high-order term calculation. + +```c++ +BENCHMARK(BM_StringCompare)->RangeMultiplier(2) + ->Range(1<<10, 1<<18)->Complexity([](int n)->double{return n; }); +``` + +### Templated benchmarks +Templated benchmarks work the same way: This example produces and consumes +messages of size `sizeof(v)` `range_x` times. It also outputs throughput in the +absence of multiprogramming. + +```c++ +template int BM_Sequential(benchmark::State& state) { + Q q; + typename Q::value_type v; + while (state.KeepRunning()) { + for (int i = state.range(0); i--; ) + q.push(v); + for (int e = state.range(0); e--; ) + q.Wait(&v); + } + // actually messages, not bytes: + state.SetBytesProcessed( + static_cast(state.iterations())*state.range(0)); +} +BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); +``` + +Three macros are provided for adding benchmark templates. + +```c++ +#if __cplusplus >= 201103L // C++11 and greater. +#define BENCHMARK_TEMPLATE(func, ...) // Takes any number of parameters. +#else // C++ < C++11 +#define BENCHMARK_TEMPLATE(func, arg1) +#endif +#define BENCHMARK_TEMPLATE1(func, arg1) +#define BENCHMARK_TEMPLATE2(func, arg1, arg2) +``` + +## Passing arbitrary arguments to a benchmark +In C++11 it is possible to define a benchmark that takes an arbitrary number +of extra arguments. The `BENCHMARK_CAPTURE(func, test_case_name, ...args)` +macro creates a benchmark that invokes `func` with the `benchmark::State` as +the first argument followed by the specified `args...`. +The `test_case_name` is appended to the name of the benchmark and +should describe the values passed. + +```c++ +template ` +void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { + [...] +} +// Registers a benchmark named "BM_takes_args/int_string_test` that passes +// the specified values to `extra_args`. +BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); +``` +Note that elements of `...args` may refer to global variables. Users should +avoid modifying global state inside of a benchmark. + +## Using RegisterBenchmark(name, fn, args...) + +The `RegisterBenchmark(name, func, args...)` function provides an alternative +way to create and register benchmarks. +`RegisterBenchmark(name, func, args...)` creates, registers, and returns a +pointer to a new benchmark with the specified `name` that invokes +`func(st, args...)` where `st` is a `benchmark::State` object. + +Unlike the `BENCHMARK` registration macros, which can only be used at the global +scope, the `RegisterBenchmark` can be called anywhere. This allows for +benchmark tests to be registered programmatically. + +Additionally `RegisterBenchmark` allows any callable object to be registered +as a benchmark. Including capturing lambdas and function objects. This +allows the creation + +For Example: +```c++ +auto BM_test = [](benchmark::State& st, auto Inputs) { /* ... */ }; + +int main(int argc, char** argv) { + for (auto& test_input : { /* ... */ }) + benchmark::RegisterBenchmark(test_input.name(), BM_test, test_input); + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} +``` + +### Multithreaded benchmarks +In a multithreaded test (benchmark invoked by multiple threads simultaneously), +it is guaranteed that none of the threads will start until all have called +`KeepRunning`, and all will have finished before KeepRunning returns false. As +such, any global setup or teardown can be wrapped in a check against the thread +index: + +```c++ +static void BM_MultiThreaded(benchmark::State& state) { + if (state.thread_index == 0) { + // Setup code here. + } + while (state.KeepRunning()) { + // Run the test as normal. + } + if (state.thread_index == 0) { + // Teardown code here. + } +} +BENCHMARK(BM_MultiThreaded)->Threads(2); +``` + +If the benchmarked code itself uses threads and you want to compare it to +single-threaded code, you may want to use real-time ("wallclock") measurements +for latency comparisons: + +```c++ +BENCHMARK(BM_test)->Range(8, 8<<10)->UseRealTime(); +``` + +Without `UseRealTime`, CPU time is used by default. + + +## Manual timing +For benchmarking something for which neither CPU time nor real-time are +correct or accurate enough, completely manual timing is supported using +the `UseManualTime` function. + +When `UseManualTime` is used, the benchmarked code must call +`SetIterationTime` once per iteration of the `KeepRunning` loop to +report the manually measured time. + +An example use case for this is benchmarking GPU execution (e.g. OpenCL +or CUDA kernels, OpenGL or Vulkan or Direct3D draw calls), which cannot +be accurately measured using CPU time or real-time. Instead, they can be +measured accurately using a dedicated API, and these measurement results +can be reported back with `SetIterationTime`. + +```c++ +static void BM_ManualTiming(benchmark::State& state) { + int microseconds = state.range(0); + std::chrono::duration sleep_duration { + static_cast(microseconds) + }; + + while (state.KeepRunning()) { + auto start = std::chrono::high_resolution_clock::now(); + // Simulate some useful workload with a sleep + std::this_thread::sleep_for(sleep_duration); + auto end = std::chrono::high_resolution_clock::now(); + + auto elapsed_seconds = + std::chrono::duration_cast>( + end - start); + + state.SetIterationTime(elapsed_seconds.count()); + } +} +BENCHMARK(BM_ManualTiming)->Range(1, 1<<17)->UseManualTime(); +``` + +### Preventing optimisation +To prevent a value or expression from being optimized away by the compiler +the `benchmark::DoNotOptimize(...)` and `benchmark::ClobberMemory()` +functions can be used. + +```c++ +static void BM_test(benchmark::State& state) { + while (state.KeepRunning()) { + int x = 0; + for (int i=0; i < 64; ++i) { + benchmark::DoNotOptimize(x += i); + } + } +} +``` + +`DoNotOptimize()` forces the *result* of `` to be stored in either +memory or a register. For GNU based compilers it acts as read/write barrier +for global memory. More specifically it forces the compiler to flush pending +writes to memory and reload any other values as necessary. + +Note that `DoNotOptimize()` does not prevent optimizations on `` +in any way. `` may even be removed entirely when the result is already +known. For example: + +```c++ + /* Example 1: `` is removed entirely. */ + int foo(int x) { return x + 42; } + while (...) DoNotOptimize(foo(0)); // Optimized to DoNotOptimize(42); + + /* Example 2: Result of '' is only reused */ + int bar(int) __attribute__((const)); + while (...) DoNotOptimize(bar(0)); // Optimized to: + // int __result__ = bar(0); + // while (...) DoNotOptimize(__result__); +``` + +The second tool for preventing optimizations is `ClobberMemory()`. In essence +`ClobberMemory()` forces the compiler to perform all pending writes to global +memory. Memory managed by block scope objects must be "escaped" using +`DoNotOptimize(...)` before it can be clobbered. In the below example +`ClobberMemory()` prevents the call to `v.push_back(42)` from being optimized +away. + +```c++ +static void BM_vector_push_back(benchmark::State& state) { + while (state.KeepRunning()) { + std::vector v; + v.reserve(1); + benchmark::DoNotOptimize(v.data()); // Allow v.data() to be clobbered. + v.push_back(42); + benchmark::ClobberMemory(); // Force 42 to be written to memory. + } +} +``` + +Note that `ClobberMemory()` is only available for GNU or MSVC based compilers. + +### Set time unit manually +If a benchmark runs a few milliseconds it may be hard to visually compare the +measured times, since the output data is given in nanoseconds per default. In +order to manually set the time unit, you can specify it manually: + +```c++ +BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); +``` + +## Controlling number of iterations +In all cases, the number of iterations for which the benchmark is run is +governed by the amount of time the benchmark takes. Concretely, the number of +iterations is at least one, not more than 1e9, until CPU time is greater than +the minimum time, or the wallclock time is 5x minimum time. The minimum time is +set as a flag `--benchmark_min_time` or per benchmark by calling `MinTime` on +the registered benchmark object. + +## Reporting the mean and standard devation by repeated benchmarks +By default each benchmark is run once and that single result is reported. +However benchmarks are often noisy and a single result may not be representative +of the overall behavior. For this reason it's possible to repeatedly rerun the +benchmark. + +The number of runs of each benchmark is specified globally by the +`--benchmark_repetitions` flag or on a per benchmark basis by calling +`Repetitions` on the registered benchmark object. When a benchmark is run +more than once the mean and standard deviation of the runs will be reported. + +Additionally the `--benchmark_report_aggregates_only={true|false}` flag or +`ReportAggregatesOnly(bool)` function can be used to change how repeated tests +are reported. By default the result of each repeated run is reported. When this +option is 'true' only the mean and standard deviation of the runs is reported. +Calling `ReportAggregatesOnly(bool)` on a registered benchmark object overrides +the value of the flag for that benchmark. + +## Fixtures +Fixture tests are created by +first defining a type that derives from ::benchmark::Fixture and then +creating/registering the tests using the following macros: + +* `BENCHMARK_F(ClassName, Method)` +* `BENCHMARK_DEFINE_F(ClassName, Method)` +* `BENCHMARK_REGISTER_F(ClassName, Method)` + +For Example: + +```c++ +class MyFixture : public benchmark::Fixture {}; + +BENCHMARK_F(MyFixture, FooTest)(benchmark::State& st) { + while (st.KeepRunning()) { + ... + } +} + +BENCHMARK_DEFINE_F(MyFixture, BarTest)(benchmark::State& st) { + while (st.KeepRunning()) { + ... + } +} +/* BarTest is NOT registered */ +BENCHMARK_REGISTER_F(MyFixture, BarTest)->Threads(2); +/* BarTest is now registered */ +``` + + +## User-defined counters + +You can add your own counters with user-defined names. The example below +will add columns "Foo", "Bar" and "Baz" in its output: + +```c++ +static void UserCountersExample1(benchmark::State& state) { + double numFoos = 0, numBars = 0, numBazs = 0; + while (state.KeepRunning()) { + // ... count Foo,Bar,Baz events + } + state.counters["Foo"] = numFoos; + state.counters["Bar"] = numBars; + state.counters["Baz"] = numBazs; +} +``` + +The `state.counters` object is a `std::map` with `std::string` keys +and `Counter` values. The latter is a `double`-like class, via an implicit +conversion to `double&`. Thus you can use all of the standard arithmetic +assignment operators (`=,+=,-=,*=,/=`) to change the value of each counter. + +In multithreaded benchmarks, each counter is set on the calling thread only. +When the benchmark finishes, the counters from each thread will be summed; +the resulting sum is the value which will be shown for the benchmark. + +The `Counter` constructor accepts two parameters: the value as a `double` +and a bit flag which allows you to show counters as rates and/or as +per-thread averages: + +```c++ + // sets a simple counter + state.counters["Foo"] = numFoos; + + // Set the counter as a rate. It will be presented divided + // by the duration of the benchmark. + state.counters["FooRate"] = Counter(numFoos, benchmark::Counter::kIsRate); + + // Set the counter as a thread-average quantity. It will + // be presented divided by the number of threads. + state.counters["FooAvg"] = Counter(numFoos, benchmark::Counter::kAvgThreads); + + // There's also a combined flag: + state.counters["FooAvgRate"] = Counter(numFoos,benchmark::Counter::kAvgThreadsRate); +``` + +When you're compiling in C++11 mode or later you can use `insert()` with +`std::initializer_list`: + +```c++ + // With C++11, this can be done: + state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}}); + // ... instead of: + state.counters["Foo"] = numFoos; + state.counters["Bar"] = numBars; + state.counters["Baz"] = numBazs; +``` + +### Counter reporting + +When using the console reporter, by default, user counters are are printed at +the end after the table, the same way as ``bytes_processed`` and +``items_processed``. This is best for cases in which there are few counters, +or where there are only a couple of lines per benchmark. Here's an example of +the default output: + +``` +------------------------------------------------------------------------------ +Benchmark Time CPU Iterations UserCounters... +------------------------------------------------------------------------------ +BM_UserCounter/threads:8 2248 ns 10277 ns 68808 Bar=16 Bat=40 Baz=24 Foo=8 +BM_UserCounter/threads:1 9797 ns 9788 ns 71523 Bar=2 Bat=5 Baz=3 Foo=1024m +BM_UserCounter/threads:2 4924 ns 9842 ns 71036 Bar=4 Bat=10 Baz=6 Foo=2 +BM_UserCounter/threads:4 2589 ns 10284 ns 68012 Bar=8 Bat=20 Baz=12 Foo=4 +BM_UserCounter/threads:8 2212 ns 10287 ns 68040 Bar=16 Bat=40 Baz=24 Foo=8 +BM_UserCounter/threads:16 1782 ns 10278 ns 68144 Bar=32 Bat=80 Baz=48 Foo=16 +BM_UserCounter/threads:32 1291 ns 10296 ns 68256 Bar=64 Bat=160 Baz=96 Foo=32 +BM_UserCounter/threads:4 2615 ns 10307 ns 68040 Bar=8 Bat=20 Baz=12 Foo=4 +BM_Factorial 26 ns 26 ns 26608979 40320 +BM_Factorial/real_time 26 ns 26 ns 26587936 40320 +BM_CalculatePiRange/1 16 ns 16 ns 45704255 0 +BM_CalculatePiRange/8 73 ns 73 ns 9520927 3.28374 +BM_CalculatePiRange/64 609 ns 609 ns 1140647 3.15746 +BM_CalculatePiRange/512 4900 ns 4901 ns 142696 3.14355 +``` + +If this doesn't suit you, you can print each counter as a table column by +passing the flag `--benchmark_counters_tabular=true` to the benchmark +application. This is best for cases in which there are a lot of counters, or +a lot of lines per individual benchmark. Note that this will trigger a +reprinting of the table header any time the counter set changes between +individual benchmarks. Here's an example of corresponding output when +`--benchmark_counters_tabular=true` is passed: + +``` +--------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations Bar Bat Baz Foo +--------------------------------------------------------------------------------------- +BM_UserCounter/threads:8 2198 ns 9953 ns 70688 16 40 24 8 +BM_UserCounter/threads:1 9504 ns 9504 ns 73787 2 5 3 1 +BM_UserCounter/threads:2 4775 ns 9550 ns 72606 4 10 6 2 +BM_UserCounter/threads:4 2508 ns 9951 ns 70332 8 20 12 4 +BM_UserCounter/threads:8 2055 ns 9933 ns 70344 16 40 24 8 +BM_UserCounter/threads:16 1610 ns 9946 ns 70720 32 80 48 16 +BM_UserCounter/threads:32 1192 ns 9948 ns 70496 64 160 96 32 +BM_UserCounter/threads:4 2506 ns 9949 ns 70332 8 20 12 4 +-------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------- +BM_Factorial 26 ns 26 ns 26392245 40320 +BM_Factorial/real_time 26 ns 26 ns 26494107 40320 +BM_CalculatePiRange/1 15 ns 15 ns 45571597 0 +BM_CalculatePiRange/8 74 ns 74 ns 9450212 3.28374 +BM_CalculatePiRange/64 595 ns 595 ns 1173901 3.15746 +BM_CalculatePiRange/512 4752 ns 4752 ns 147380 3.14355 +BM_CalculatePiRange/4k 37970 ns 37972 ns 18453 3.14184 +BM_CalculatePiRange/32k 303733 ns 303744 ns 2305 3.14162 +BM_CalculatePiRange/256k 2434095 ns 2434186 ns 288 3.1416 +BM_CalculatePiRange/1024k 9721140 ns 9721413 ns 71 3.14159 +BM_CalculatePi/threads:8 2255 ns 9943 ns 70936 +``` +Note above the additional header printed when the benchmark changes from +``BM_UserCounter`` to ``BM_Factorial``. This is because ``BM_Factorial`` does +not have the same counter set as ``BM_UserCounter``. + +## Exiting Benchmarks in Error + +When errors caused by external influences, such as file I/O and network +communication, occur within a benchmark the +`State::SkipWithError(const char* msg)` function can be used to skip that run +of benchmark and report the error. Note that only future iterations of the +`KeepRunning()` are skipped. Users may explicitly return to exit the +benchmark immediately. + +The `SkipWithError(...)` function may be used at any point within the benchmark, +including before and after the `KeepRunning()` loop. + +For example: + +```c++ +static void BM_test(benchmark::State& state) { + auto resource = GetResource(); + if (!resource.good()) { + state.SkipWithError("Resource is not good!"); + // KeepRunning() loop will not be entered. + } + while (state.KeepRunning()) { + auto data = resource.read_data(); + if (!resource.good()) { + state.SkipWithError("Failed to read data!"); + break; // Needed to skip the rest of the iteration. + } + do_stuff(data); + } +} +``` + +## Running a subset of the benchmarks + +The `--benchmark_filter=` option can be used to only run the benchmarks +which match the specified ``. For example: + +```bash +$ ./run_benchmarks.x --benchmark_filter=BM_memcpy/32 +Run on (1 X 2300 MHz CPU ) +2016-06-25 19:34:24 +Benchmark Time CPU Iterations +---------------------------------------------------- +BM_memcpy/32 11 ns 11 ns 79545455 +BM_memcpy/32k 2181 ns 2185 ns 324074 +BM_memcpy/32 12 ns 12 ns 54687500 +BM_memcpy/32k 1834 ns 1837 ns 357143 +``` + + +## Output Formats +The library supports multiple output formats. Use the +`--benchmark_format=` flag to set the format type. `console` +is the default format. + +The Console format is intended to be a human readable format. By default +the format generates color output. Context is output on stderr and the +tabular data on stdout. Example tabular output looks like: +``` +Benchmark Time(ns) CPU(ns) Iterations +---------------------------------------------------------------------- +BM_SetInsert/1024/1 28928 29349 23853 133.097kB/s 33.2742k items/s +BM_SetInsert/1024/8 32065 32913 21375 949.487kB/s 237.372k items/s +BM_SetInsert/1024/10 33157 33648 21431 1.13369MB/s 290.225k items/s +``` + +The JSON format outputs human readable json split into two top level attributes. +The `context` attribute contains information about the run in general, including +information about the CPU and the date. +The `benchmarks` attribute contains a list of ever benchmark run. Example json +output looks like: +```json +{ + "context": { + "date": "2015/03/17-18:40:25", + "num_cpus": 40, + "mhz_per_cpu": 2801, + "cpu_scaling_enabled": false, + "build_type": "debug" + }, + "benchmarks": [ + { + "name": "BM_SetInsert/1024/1", + "iterations": 94877, + "real_time": 29275, + "cpu_time": 29836, + "bytes_per_second": 134066, + "items_per_second": 33516 + }, + { + "name": "BM_SetInsert/1024/8", + "iterations": 21609, + "real_time": 32317, + "cpu_time": 32429, + "bytes_per_second": 986770, + "items_per_second": 246693 + }, + { + "name": "BM_SetInsert/1024/10", + "iterations": 21393, + "real_time": 32724, + "cpu_time": 33355, + "bytes_per_second": 1199226, + "items_per_second": 299807 + } + ] +} +``` + +The CSV format outputs comma-separated values. The `context` is output on stderr +and the CSV itself on stdout. Example CSV output looks like: +``` +name,iterations,real_time,cpu_time,bytes_per_second,items_per_second,label +"BM_SetInsert/1024/1",65465,17890.7,8407.45,475768,118942, +"BM_SetInsert/1024/8",116606,18810.1,9766.64,3.27646e+06,819115, +"BM_SetInsert/1024/10",106365,17238.4,8421.53,4.74973e+06,1.18743e+06, +``` + +## Output Files +The library supports writing the output of the benchmark to a file specified +by `--benchmark_out=`. The format of the output can be specified +using `--benchmark_out_format={json|console|csv}`. Specifying +`--benchmark_out` does not suppress the console output. + +## Debug vs Release +By default, benchmark builds as a debug library. You will see a warning in the output when this is the case. To build it as a release library instead, use: + +``` +cmake -DCMAKE_BUILD_TYPE=Release +``` + +To enable link-time optimisation, use + +``` +cmake -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_LTO=true +``` + +## Linking against the library +When using gcc, it is necessary to link against pthread to avoid runtime exceptions. +This is due to how gcc implements std::thread. +See [issue #67](https://github.com/google/benchmark/issues/67) for more details. + +## Compiler Support + +Google Benchmark uses C++11 when building the library. As such we require +a modern C++ toolchain, both compiler and standard library. + +The following minimum versions are strongly recommended build the library: + +* GCC 4.8 +* Clang 3.4 +* Visual Studio 2013 +* Intel 2015 Update 1 + +Anything older *may* work. + +Note: Using the library and its headers in C++03 is supported. C++11 is only +required to build the library. + +# Known Issues + +### Windows + +* Users must manually link `shlwapi.lib`. Failure to do so may result +in unresolved symbols. + diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..e084f38 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,56 @@ +version: '{build}' + +image: Visual Studio 2017 + +configuration: + - Debug + - Release + +environment: + matrix: + - compiler: msvc-15-seh + generator: "Visual Studio 15 2017" + + - compiler: msvc-15-seh + generator: "Visual Studio 15 2017 Win64" + + - compiler: msvc-14-seh + generator: "Visual Studio 14 2015" + + - compiler: msvc-14-seh + generator: "Visual Studio 14 2015 Win64" + + - compiler: msvc-12-seh + generator: "Visual Studio 12 2013" + + - compiler: msvc-12-seh + generator: "Visual Studio 12 2013 Win64" + + - compiler: gcc-5.3.0-posix + generator: "MinGW Makefiles" + cxx_path: 'C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin' + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + +matrix: + fast_finish: true + +install: + # git bash conflicts with MinGW makefiles + - if "%generator%"=="MinGW Makefiles" (set "PATH=%PATH:C:\Program Files\Git\usr\bin;=%") + - if not "%cxx_path%"=="" (set "PATH=%PATH%;%cxx_path%") + +build_script: + - md _build -Force + - cd _build + - echo %configuration% + - cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" .. + - cmake --build . --config %configuration% + +test_script: + - ctest -c %configuration% --timeout 300 --output-on-failure + +artifacts: + - path: '_build/CMakeFiles/*.log' + name: logs + - path: '_build/Testing/**/*.xml' + name: test_results diff --git a/cmake/AddCXXCompilerFlag.cmake b/cmake/AddCXXCompilerFlag.cmake new file mode 100644 index 0000000..0b176ba --- /dev/null +++ b/cmake/AddCXXCompilerFlag.cmake @@ -0,0 +1,64 @@ +# - Adds a compiler flag if it is supported by the compiler +# +# This function checks that the supplied compiler flag is supported and then +# adds it to the corresponding compiler flags +# +# add_cxx_compiler_flag( []) +# +# - Example +# +# include(AddCXXCompilerFlag) +# add_cxx_compiler_flag(-Wall) +# add_cxx_compiler_flag(-no-strict-aliasing RELEASE) +# Requires CMake 2.6+ + +if(__add_cxx_compiler_flag) + return() +endif() +set(__add_cxx_compiler_flag INCLUDED) + +include(CheckCXXCompilerFlag) + +function(mangle_compiler_flag FLAG OUTPUT) + string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG) + string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG}) + string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) + string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) + set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE) +endfunction(mangle_compiler_flag) + +function(add_cxx_compiler_flag FLAG) + mangle_compiler_flag("${FLAG}" MANGLED_FLAG) + set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}") + check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG}) + set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") + if(${MANGLED_FLAG}) + set(VARIANT ${ARGV1}) + if(ARGV1) + string(TOUPPER "_${VARIANT}" VARIANT) + endif() + set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) + endif() +endfunction() + +function(add_required_cxx_compiler_flag FLAG) + mangle_compiler_flag("${FLAG}" MANGLED_FLAG) + set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}") + check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG}) + set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") + if(${MANGLED_FLAG}) + set(VARIANT ${ARGV1}) + if(ARGV1) + string(TOUPPER "_${VARIANT}" VARIANT) + endif() + set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE) + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE) + else() + message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler") + endif() +endfunction() diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake new file mode 100644 index 0000000..2c4460f --- /dev/null +++ b/cmake/CXXFeatureCheck.cmake @@ -0,0 +1,46 @@ +# - Compile and run code to check for C++ features +# +# This functions compiles a source file under the `cmake` folder +# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake +# environment +# +# cxx_feature_check( []) +# +# - Example +# +# include(CXXFeatureCheck) +# cxx_feature_check(STD_REGEX) +# Requires CMake 2.8.12+ + +if(__cxx_feature_check) + return() +endif() +set(__cxx_feature_check INCLUDED) + +function(cxx_feature_check FILE) + string(TOLOWER ${FILE} FILE) + string(TOUPPER ${FILE} VAR) + string(TOUPPER "HAVE_${VAR}" FEATURE) + if (DEFINED HAVE_${VAR}) + set(HAVE_${VAR} 1 CACHE INTERNAL "Feature test for ${FILE}" PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) + return() + endif() + message("-- Performing Test ${FEATURE}") + try_run(RUN_${FEATURE} COMPILE_${FEATURE} + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES}) + if(RUN_${FEATURE} EQUAL 0) + message("-- Performing Test ${FEATURE} -- success") + set(HAVE_${VAR} 1 CACHE INTERNAL "Feature test for ${FILE}" PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) + else() + if(NOT COMPILE_${FEATURE}) + message("-- Performing Test ${FEATURE} -- failed to compile") + else() + message("-- Performing Test ${FEATURE} -- compiled but failed to run") + endif() + endif() +endfunction() + diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 0000000..6e9256e --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") diff --git a/cmake/GetGitVersion.cmake b/cmake/GetGitVersion.cmake new file mode 100644 index 0000000..8dd9480 --- /dev/null +++ b/cmake/GetGitVersion.cmake @@ -0,0 +1,51 @@ +# - Returns a version string from Git tags +# +# This function inspects the annotated git tags for the project and returns a string +# into a CMake variable +# +# get_git_version() +# +# - Example +# +# include(GetGitVersion) +# get_git_version(GIT_VERSION) +# +# Requires CMake 2.8.11+ +find_package(Git) + +if(__get_git_version) + return() +endif() +set(__get_git_version INCLUDED) + +function(get_git_version var) + if(GIT_EXECUTABLE) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 + RESULT_VARIABLE status + OUTPUT_VARIABLE GIT_VERSION + ERROR_QUIET) + if(${status}) + set(GIT_VERSION "v0.0.0") + else() + string(STRIP ${GIT_VERSION} GIT_VERSION) + string(REGEX REPLACE "-[0-9]+-g" "-" GIT_VERSION ${GIT_VERSION}) + endif() + + # Work out if the repository is dirty + execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh + OUTPUT_QUIET + ERROR_QUIET) + execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD -- + OUTPUT_VARIABLE GIT_DIFF_INDEX + ERROR_QUIET) + string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY) + if (${GIT_DIRTY}) + set(GIT_VERSION "${GIT_VERSION}-dirty") + endif() + else() + set(GIT_VERSION "v0.0.0") + endif() + + message("-- git Version: ${GIT_VERSION}") + set(${var} ${GIT_VERSION} PARENT_SCOPE) +endfunction() diff --git a/cmake/gnu_posix_regex.cpp b/cmake/gnu_posix_regex.cpp new file mode 100644 index 0000000..b5b91cd --- /dev/null +++ b/cmake/gnu_posix_regex.cpp @@ -0,0 +1,12 @@ +#include +#include +int main() { + std::string str = "test0159"; + regex_t re; + int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + return ec; + } + return regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0; +} + diff --git a/cmake/posix_regex.cpp b/cmake/posix_regex.cpp new file mode 100644 index 0000000..466dc62 --- /dev/null +++ b/cmake/posix_regex.cpp @@ -0,0 +1,14 @@ +#include +#include +int main() { + std::string str = "test0159"; + regex_t re; + int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + return ec; + } + int ret = regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0; + regfree(&re); + return ret; +} + diff --git a/cmake/std_regex.cpp b/cmake/std_regex.cpp new file mode 100644 index 0000000..696f2a2 --- /dev/null +++ b/cmake/std_regex.cpp @@ -0,0 +1,10 @@ +#include +#include +int main() { + const std::string str = "test0159"; + std::regex re; + re = std::regex("^[a-z]+[0-9]+$", + std::regex_constants::extended | std::regex_constants::nosubs); + return std::regex_search(str, re) ? 0 : -1; +} + diff --git a/cmake/steady_clock.cpp b/cmake/steady_clock.cpp new file mode 100644 index 0000000..66d50d1 --- /dev/null +++ b/cmake/steady_clock.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + typedef std::chrono::steady_clock Clock; + Clock::time_point tp = Clock::now(); + ((void)tp); +} diff --git a/cmake/thread_safety_attributes.cpp b/cmake/thread_safety_attributes.cpp new file mode 100644 index 0000000..46161ba --- /dev/null +++ b/cmake/thread_safety_attributes.cpp @@ -0,0 +1,4 @@ +#define HAVE_THREAD_SAFETY_ATTRIBUTES +#include "../src/mutex.h" + +int main() {} diff --git a/docs/tools.md b/docs/tools.md new file mode 100644 index 0000000..f176f74 --- /dev/null +++ b/docs/tools.md @@ -0,0 +1,59 @@ +# Benchmark Tools + +## compare_bench.py + +The `compare_bench.py` utility which can be used to compare the result of benchmarks. +The program is invoked like: + +``` bash +$ compare_bench.py [benchmark options]... +``` + +Where `` and `` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. + +The sample output using the JSON test files under `Inputs/` gives: + +``` bash +$ ./compare_bench.py ./gbench/Inputs/test1_run1.json ./gbench/Inputs/test1_run2.json +Comparing ./gbench/Inputs/test1_run1.json to ./gbench/Inputs/test1_run2.json +Benchmark Time CPU +---------------------------------------------- +BM_SameTimes +0.00 +0.00 +BM_2xFaster -0.50 -0.50 +BM_2xSlower +1.00 +1.00 +BM_10PercentFaster -0.10 -0.10 +BM_10PercentSlower +0.10 +0.10 +``` + +When a benchmark executable is run, the raw output from the benchmark is printed in real time to stdout. The sample output using `benchmark/basic_test` for both arguments looks like: + +``` +./compare_bench.py test/basic_test test/basic_test --benchmark_filter=BM_empty.* +RUNNING: test/basic_test --benchmark_filter=BM_empty.* +Run on (4 X 4228.32 MHz CPU s) +2016-08-02 19:21:33 +Benchmark Time CPU Iterations +-------------------------------------------------------------------- +BM_empty 9 ns 9 ns 79545455 +BM_empty/threads:4 4 ns 9 ns 75268816 +BM_empty_stop_start 8 ns 8 ns 83333333 +BM_empty_stop_start/threads:4 3 ns 8 ns 83333332 +RUNNING: test/basic_test --benchmark_filter=BM_empty.* +Run on (4 X 4228.32 MHz CPU s) +2016-08-02 19:21:35 +Benchmark Time CPU Iterations +-------------------------------------------------------------------- +BM_empty 9 ns 9 ns 76086957 +BM_empty/threads:4 4 ns 9 ns 76086956 +BM_empty_stop_start 8 ns 8 ns 87500000 +BM_empty_stop_start/threads:4 3 ns 8 ns 88607596 +Comparing test/basic_test to test/basic_test +Benchmark Time CPU +--------------------------------------------------------- +BM_empty +0.00 +0.00 +BM_empty/threads:4 +0.00 +0.00 +BM_empty_stop_start +0.00 +0.00 +BM_empty_stop_start/threads:4 +0.00 +0.00 +``` + +Obviously this example doesn't give any useful output, but it's intended to show the output format when 'compare_bench.py' needs to run benchmarks. diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h new file mode 100644 index 0000000..bd3b0ff --- /dev/null +++ b/include/benchmark/benchmark.h @@ -0,0 +1,1210 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Support for registering benchmarks for functions. + +/* Example usage: +// Define a function that executes the code to be measured a +// specified number of times: +static void BM_StringCreation(benchmark::State& state) { + while (state.KeepRunning()) + std::string empty_string; +} + +// Register the function as a benchmark +BENCHMARK(BM_StringCreation); + +// Define another benchmark +static void BM_StringCopy(benchmark::State& state) { + std::string x = "hello"; + while (state.KeepRunning()) + std::string copy(x); +} +BENCHMARK(BM_StringCopy); + +// Augment the main() program to invoke benchmarks if specified +// via the --benchmarks command line flag. E.g., +// my_unittest --benchmark_filter=all +// my_unittest --benchmark_filter=BM_StringCreation +// my_unittest --benchmark_filter=String +// my_unittest --benchmark_filter='Copy|Creation' +int main(int argc, char** argv) { + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + return 0; +} + +// Sometimes a family of microbenchmarks can be implemented with +// just one routine that takes an extra argument to specify which +// one of the family of benchmarks to run. For example, the following +// code defines a family of microbenchmarks for measuring the speed +// of memcpy() calls of different lengths: + +static void BM_memcpy(benchmark::State& state) { + char* src = new char[state.range(0)]; char* dst = new char[state.range(0)]; + memset(src, 'x', state.range(0)); + while (state.KeepRunning()) + memcpy(dst, src, state.range(0)); + state.SetBytesProcessed(int64_t(state.iterations()) * + int64_t(state.range(0))); + delete[] src; delete[] dst; +} +BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); + +// The preceding code is quite repetitive, and can be replaced with the +// following short-hand. The following invocation will pick a few +// appropriate arguments in the specified range and will generate a +// microbenchmark for each such argument. +BENCHMARK(BM_memcpy)->Range(8, 8<<10); + +// You might have a microbenchmark that depends on two inputs. For +// example, the following code defines a family of microbenchmarks for +// measuring the speed of set insertion. +static void BM_SetInsert(benchmark::State& state) { + while (state.KeepRunning()) { + state.PauseTiming(); + set data = ConstructRandomSet(state.range(0)); + state.ResumeTiming(); + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert) + ->Args({1<<10, 1}) + ->Args({1<<10, 8}) + ->Args({1<<10, 64}) + ->Args({1<<10, 512}) + ->Args({8<<10, 1}) + ->Args({8<<10, 8}) + ->Args({8<<10, 64}) + ->Args({8<<10, 512}); + +// The preceding code is quite repetitive, and can be replaced with +// the following short-hand. The following macro will pick a few +// appropriate arguments in the product of the two specified ranges +// and will generate a microbenchmark for each such pair. +BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {1, 512}}); + +// For more complex patterns of inputs, passing a custom function +// to Apply allows programmatic specification of an +// arbitrary set of arguments to run the microbenchmark on. +// The following example enumerates a dense range on +// one parameter, and a sparse range on the second. +static void CustomArguments(benchmark::internal::Benchmark* b) { + for (int i = 0; i <= 10; ++i) + for (int j = 32; j <= 1024*1024; j *= 8) + b->Args({i, j}); +} +BENCHMARK(BM_SetInsert)->Apply(CustomArguments); + +// Templated microbenchmarks work the same way: +// Produce then consume 'size' messages 'iters' times +// Measures throughput in the absence of multiprogramming. +template int BM_Sequential(benchmark::State& state) { + Q q; + typename Q::value_type v; + while (state.KeepRunning()) { + for (int i = state.range(0); i--; ) + q.push(v); + for (int e = state.range(0); e--; ) + q.Wait(&v); + } + // actually messages, not bytes: + state.SetBytesProcessed( + static_cast(state.iterations())*state.range(0)); +} +BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); + +Use `Benchmark::MinTime(double t)` to set the minimum time used to run the +benchmark. This option overrides the `benchmark_min_time` flag. + +void BM_test(benchmark::State& state) { + ... body ... +} +BENCHMARK(BM_test)->MinTime(2.0); // Run for at least 2 seconds. + +In a multithreaded test, it is guaranteed that none of the threads will start +until all have called KeepRunning, and all will have finished before KeepRunning +returns false. As such, any global setup or teardown you want to do can be +wrapped in a check against the thread index: + +static void BM_MultiThreaded(benchmark::State& state) { + if (state.thread_index == 0) { + // Setup code here. + } + while (state.KeepRunning()) { + // Run the test as normal. + } + if (state.thread_index == 0) { + // Teardown code here. + } +} +BENCHMARK(BM_MultiThreaded)->Threads(4); + + +If a benchmark runs a few milliseconds it may be hard to visually compare the +measured times, since the output data is given in nanoseconds per default. In +order to manually set the time unit, you can specify it manually: + +BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); +*/ + +#ifndef BENCHMARK_BENCHMARK_H_ +#define BENCHMARK_BENCHMARK_H_ + + +#if __cplusplus >= 201103L +#define BENCHMARK_HAS_CXX11 +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BENCHMARK_HAS_CXX11) +#include +#include +#include +#endif + +#if defined(_MSC_VER) +#include // for _ReadWriteBarrier +#endif + +#ifndef BENCHMARK_HAS_CXX11 +#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + TypeName& operator=(const TypeName&) +#else +#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + TypeName& operator=(const TypeName&) = delete +#endif + +#if defined(__GNUC__) +#define BENCHMARK_UNUSED __attribute__((unused)) +#define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) +#define BENCHMARK_NOEXCEPT noexcept +#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) +#elif defined(_MSC_VER) && !defined(__clang__) +#define BENCHMARK_UNUSED +#define BENCHMARK_ALWAYS_INLINE __forceinline +#if _MSC_VER >= 1900 +#define BENCHMARK_NOEXCEPT noexcept +#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) +#else +#define BENCHMARK_NOEXCEPT +#define BENCHMARK_NOEXCEPT_OP(x) +#endif +#define __func__ __FUNCTION__ +#else +#define BENCHMARK_UNUSED +#define BENCHMARK_ALWAYS_INLINE +#define BENCHMARK_NOEXCEPT +#define BENCHMARK_NOEXCEPT_OP(x) +#endif + +#define BENCHMARK_INTERNAL_TOSTRING2(x) #x +#define BENCHMARK_INTERNAL_TOSTRING(x) BENCHMARK_INTERNAL_TOSTRING2(x) + +#if defined(__GNUC__) +#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) +#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#else +#define BENCHMARK_BUILTIN_EXPECT(x, y) x +#define BENCHMARK_DEPRECATED_MSG(msg) +#define BENCHMARK_WARNING_MSG(msg) __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING(__LINE__) ") : warning note: " msg)) +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#define BENCHMARK_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + + +namespace benchmark { +class BenchmarkReporter; + +void Initialize(int* argc, char** argv); + +// Report to stdout all arguments in 'argv' as unrecognized except the first. +// Returns true there is at least on unrecognized argument (i.e. 'argc' > 1). +bool ReportUnrecognizedArguments(int argc, char** argv); + +// Generate a list of benchmarks matching the specified --benchmark_filter flag +// and if --benchmark_list_tests is specified return after printing the name +// of each matching benchmark. Otherwise run each matching benchmark and +// report the results. +// +// The second and third overload use the specified 'console_reporter' and +// 'file_reporter' respectively. 'file_reporter' will write to the file +// specified +// by '--benchmark_output'. If '--benchmark_output' is not given the +// 'file_reporter' is ignored. +// +// RETURNS: The number of matching benchmarks. +size_t RunSpecifiedBenchmarks(); +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter); +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter, + BenchmarkReporter* file_reporter); + +// If this routine is called, peak memory allocation past this point in the +// benchmark is reported at the end of the benchmark report line. (It is +// computed by running the benchmark once with a single iteration and a memory +// tracer.) +// TODO(dominic) +// void MemoryUsage(); + +namespace internal { +class Benchmark; +class BenchmarkImp; +class BenchmarkFamilies; + +void UseCharPointer(char const volatile*); + +// Take ownership of the pointer and register the benchmark. Return the +// registered benchmark. +Benchmark* RegisterBenchmarkInternal(Benchmark*); + +// Ensure that the standard streams are properly initialized in every TU. +int InitializeStreams(); +BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); + +} // namespace internal + + +#if !defined(__GNUC__) || defined(__pnacl__) || defined(EMSCRIPTN) +# define BENCHMARK_HAS_NO_INLINE_ASSEMBLY +#endif + +// The DoNotOptimize(...) function can be used to prevent a value or +// expression from being optimized away by the compiler. This function is +// intended to add little to no overhead. +// See: https://youtu.be/nXaxk27zwlk?t=2441 +#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + // Clang doesn't like the 'X' constraint on `value` and certain GCC versions + // don't like the 'g' constraint. Attempt to placate them both. +#if defined(__clang__) + asm volatile("" : : "g"(value) : "memory"); +#else + asm volatile("" : : "i,r,m"(value) : "memory"); +#endif +} +// Force the compiler to flush pending writes to global memory. Acts as an +// effective read/write barrier +inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { + asm volatile("" : : : "memory"); +} +#elif defined(_MSC_VER) +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} + +inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { + _ReadWriteBarrier(); +} +#else +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + internal::UseCharPointer(&reinterpret_cast(value)); +} +// FIXME Add ClobberMemory() for non-gnu and non-msvc compilers +#endif + + + +// This class is used for user-defined counters. +class Counter { +public: + + enum Flags { + kDefaults = 0, + // Mark the counter as a rate. It will be presented divided + // by the duration of the benchmark. + kIsRate = 1, + // Mark the counter as a thread-average quantity. It will be + // presented divided by the number of threads. + kAvgThreads = 2, + // Mark the counter as a thread-average rate. See above. + kAvgThreadsRate = kIsRate|kAvgThreads + }; + + double value; + Flags flags; + + BENCHMARK_ALWAYS_INLINE + Counter(double v = 0., Flags f = kDefaults) : value(v), flags(f) {} + + BENCHMARK_ALWAYS_INLINE operator double const& () const { return value; } + BENCHMARK_ALWAYS_INLINE operator double & () { return value; } + +}; + +// This is the container for the user-defined counters. +typedef std::map UserCounters; + + +// TimeUnit is passed to a benchmark in order to specify the order of magnitude +// for the measured time. +enum TimeUnit { kNanosecond, kMicrosecond, kMillisecond }; + +// BigO is passed to a benchmark in order to specify the asymptotic +// computational +// complexity for the benchmark. In case oAuto is selected, complexity will be +// calculated automatically to the best fit. +enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda }; + +// BigOFunc is passed to a benchmark in order to specify the asymptotic +// computational complexity for the benchmark. +typedef double(BigOFunc)(int); + +namespace internal { +class ThreadTimer; +class ThreadManager; + +enum ReportMode +#if defined(BENCHMARK_HAS_CXX11) + : unsigned +#else +#endif + { + RM_Unspecified, // The mode has not been manually specified + RM_Default, // The mode is user-specified as default. + RM_ReportAggregatesOnly +}; +} // namespace internal + +// State is passed to a running Benchmark and contains state for the +// benchmark to use. +class State { + public: + // Returns true if the benchmark should continue through another iteration. + // NOTE: A benchmark may not return from the test until KeepRunning() has + // returned false. + bool KeepRunning() { + if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) { + StartKeepRunning(); + } + bool const res = total_iterations_++ < max_iterations; + if (BENCHMARK_BUILTIN_EXPECT(!res, false)) { + FinishKeepRunning(); + } + return res; + } + + // REQUIRES: timer is running and 'SkipWithError(...)' has not been called + // by the current thread. + // Stop the benchmark timer. If not called, the timer will be + // automatically stopped after KeepRunning() returns false for the first time. + // + // For threaded benchmarks the PauseTiming() function only pauses the timing + // for the current thread. + // + // NOTE: The "real time" measurement is per-thread. If different threads + // report different measurements the largest one is reported. + // + // NOTE: PauseTiming()/ResumeTiming() are relatively + // heavyweight, and so their use should generally be avoided + // within each benchmark iteration, if possible. + void PauseTiming(); + + // REQUIRES: timer is not running and 'SkipWithError(...)' has not been called + // by the current thread. + // Start the benchmark timer. The timer is NOT running on entrance to the + // benchmark function. It begins running after the first call to KeepRunning() + // + // NOTE: PauseTiming()/ResumeTiming() are relatively + // heavyweight, and so their use should generally be avoided + // within each benchmark iteration, if possible. + void ResumeTiming(); + + // REQUIRES: 'SkipWithError(...)' has not been called previously by the + // current thread. + // Skip any future iterations of the 'KeepRunning()' loop in the current + // thread and report an error with the specified 'msg'. After this call + // the user may explicitly 'return' from the benchmark. + // + // For threaded benchmarks only the current thread stops executing and future + // calls to `KeepRunning()` will block until all threads have completed + // the `KeepRunning()` loop. If multiple threads report an error only the + // first error message is used. + // + // NOTE: Calling 'SkipWithError(...)' does not cause the benchmark to exit + // the current scope immediately. If the function is called from within + // the 'KeepRunning()' loop the current iteration will finish. It is the users + // responsibility to exit the scope as needed. + void SkipWithError(const char* msg); + + // REQUIRES: called exactly once per iteration of the KeepRunning loop. + // Set the manually measured time for this benchmark iteration, which + // is used instead of automatically measured time if UseManualTime() was + // specified. + // + // For threaded benchmarks the final value will be set to the largest + // reported values. + void SetIterationTime(double seconds); + + // Set the number of bytes processed by the current benchmark + // execution. This routine is typically called once at the end of a + // throughput oriented benchmark. If this routine is called with a + // value > 0, the report is printed in MB/sec instead of nanoseconds + // per iteration. + // + // REQUIRES: a benchmark has exited its KeepRunning loop. + BENCHMARK_ALWAYS_INLINE + void SetBytesProcessed(size_t bytes) { bytes_processed_ = bytes; } + + BENCHMARK_ALWAYS_INLINE + size_t bytes_processed() const { return bytes_processed_; } + + // If this routine is called with complexity_n > 0 and complexity report is + // requested for the + // family benchmark, then current benchmark will be part of the computation + // and complexity_n will + // represent the length of N. + BENCHMARK_ALWAYS_INLINE + void SetComplexityN(int complexity_n) { complexity_n_ = complexity_n; } + + BENCHMARK_ALWAYS_INLINE + int complexity_length_n() { return complexity_n_; } + + // If this routine is called with items > 0, then an items/s + // label is printed on the benchmark report line for the currently + // executing benchmark. It is typically called at the end of a processing + // benchmark where a processing items/second output is desired. + // + // REQUIRES: a benchmark has exited its KeepRunning loop. + BENCHMARK_ALWAYS_INLINE + void SetItemsProcessed(size_t items) { items_processed_ = items; } + + BENCHMARK_ALWAYS_INLINE + size_t items_processed() const { return items_processed_; } + + // If this routine is called, the specified label is printed at the + // end of the benchmark report line for the currently executing + // benchmark. Example: + // static void BM_Compress(benchmark::State& state) { + // ... + // double compress = input_size / output_size; + // state.SetLabel(StringPrintf("compress:%.1f%%", 100.0*compression)); + // } + // Produces output that looks like: + // BM_Compress 50 50 14115038 compress:27.3% + // + // REQUIRES: a benchmark has exited its KeepRunning loop. + void SetLabel(const char* label); + + void BENCHMARK_ALWAYS_INLINE SetLabel(const std::string& str) { + this->SetLabel(str.c_str()); + } + + // Range arguments for this run. CHECKs if the argument has been set. + BENCHMARK_ALWAYS_INLINE + int range(std::size_t pos = 0) const { + assert(range_.size() > pos); + return range_[pos]; + } + + BENCHMARK_DEPRECATED_MSG("use 'range(0)' instead") + int range_x() const { return range(0); } + + BENCHMARK_DEPRECATED_MSG("use 'range(1)' instead") + int range_y() const { return range(1); } + + BENCHMARK_ALWAYS_INLINE + size_t iterations() const { return total_iterations_; } + + private: + bool started_; + bool finished_; + size_t total_iterations_; + + std::vector range_; + + size_t bytes_processed_; + size_t items_processed_; + + int complexity_n_; + + bool error_occurred_; + + public: + // Container for user-defined counters. + UserCounters counters; + // Index of the executing thread. Values from [0, threads). + const int thread_index; + // Number of threads concurrently executing the benchmark. + const int threads; + const size_t max_iterations; + + // TODO(EricWF) make me private + State(size_t max_iters, const std::vector& ranges, int thread_i, + int n_threads, internal::ThreadTimer* timer, + internal::ThreadManager* manager); + + private: + void StartKeepRunning(); + void FinishKeepRunning(); + internal::ThreadTimer* timer_; + internal::ThreadManager* manager_; + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(State); +}; + +namespace internal { + +typedef void(Function)(State&); + +// ------------------------------------------------------ +// Benchmark registration object. The BENCHMARK() macro expands +// into an internal::Benchmark* object. Various methods can +// be called on this object to change the properties of the benchmark. +// Each method returns "this" so that multiple method calls can +// chained into one expression. +class Benchmark { + public: + virtual ~Benchmark(); + + // Note: the following methods all return "this" so that multiple + // method calls can be chained together in one expression. + + // Run this benchmark once with "x" as the extra argument passed + // to the function. + // REQUIRES: The function passed to the constructor must accept an arg1. + Benchmark* Arg(int x); + + // Run this benchmark with the given time unit for the generated output report + Benchmark* Unit(TimeUnit unit); + + // Run this benchmark once for a number of values picked from the + // range [start..limit]. (start and limit are always picked.) + // REQUIRES: The function passed to the constructor must accept an arg1. + Benchmark* Range(int start, int limit); + + // Run this benchmark once for all values in the range [start..limit] with + // specific step + // REQUIRES: The function passed to the constructor must accept an arg1. + Benchmark* DenseRange(int start, int limit, int step = 1); + + // Run this benchmark once with "args" as the extra arguments passed + // to the function. + // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... + Benchmark* Args(const std::vector& args); + + // Equivalent to Args({x, y}) + // NOTE: This is a legacy C++03 interface provided for compatibility only. + // New code should use 'Args'. + Benchmark* ArgPair(int x, int y) { + std::vector args; + args.push_back(x); + args.push_back(y); + return Args(args); + } + + // Run this benchmark once for a number of values picked from the + // ranges [start..limit]. (starts and limits are always picked.) + // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... + Benchmark* Ranges(const std::vector >& ranges); + + // Equivalent to ArgNames({name}) + Benchmark* ArgName(const std::string& name); + + // Set the argument names to display in the benchmark name. If not called, + // only argument values will be shown. + Benchmark* ArgNames(const std::vector& names); + + // Equivalent to Ranges({{lo1, hi1}, {lo2, hi2}}). + // NOTE: This is a legacy C++03 interface provided for compatibility only. + // New code should use 'Ranges'. + Benchmark* RangePair(int lo1, int hi1, int lo2, int hi2) { + std::vector > ranges; + ranges.push_back(std::make_pair(lo1, hi1)); + ranges.push_back(std::make_pair(lo2, hi2)); + return Ranges(ranges); + } + + // Pass this benchmark object to *func, which can customize + // the benchmark by calling various methods like Arg, Args, + // Threads, etc. + Benchmark* Apply(void (*func)(Benchmark* benchmark)); + + // Set the range multiplier for non-dense range. If not called, the range + // multiplier kRangeMultiplier will be used. + Benchmark* RangeMultiplier(int multiplier); + + // Set the minimum amount of time to use when running this benchmark. This + // option overrides the `benchmark_min_time` flag. + // REQUIRES: `t > 0` and `Iterations` has not been called on this benchmark. + Benchmark* MinTime(double t); + + // Specify the amount of iterations that should be run by this benchmark. + // REQUIRES: 'n > 0' and `MinTime` has not been called on this benchmark. + // + // NOTE: This function should only be used when *exact* iteration control is + // needed and never to control or limit how long a benchmark runs, where + // `--benchmark_min_time=N` or `MinTime(...)` should be used instead. + Benchmark* Iterations(size_t n); + + // Specify the amount of times to repeat this benchmark. This option overrides + // the `benchmark_repetitions` flag. + // REQUIRES: `n > 0` + Benchmark* Repetitions(int n); + + // Specify if each repetition of the benchmark should be reported separately + // or if only the final statistics should be reported. If the benchmark + // is not repeated then the single result is always reported. + Benchmark* ReportAggregatesOnly(bool value = true); + + // If a particular benchmark is I/O bound, runs multiple threads internally or + // if for some reason CPU timings are not representative, call this method. If + // called, the elapsed time will be used to control how many iterations are + // run, and in the printing of items/second or MB/seconds values. If not + // called, the cpu time used by the benchmark will be used. + Benchmark* UseRealTime(); + + // If a benchmark must measure time manually (e.g. if GPU execution time is + // being + // measured), call this method. If called, each benchmark iteration should + // call + // SetIterationTime(seconds) to report the measured time, which will be used + // to control how many iterations are run, and in the printing of items/second + // or MB/second values. + Benchmark* UseManualTime(); + + // Set the asymptotic computational complexity for the benchmark. If called + // the asymptotic computational complexity will be shown on the output. + Benchmark* Complexity(BigO complexity = benchmark::oAuto); + + // Set the asymptotic computational complexity for the benchmark. If called + // the asymptotic computational complexity will be shown on the output. + Benchmark* Complexity(BigOFunc* complexity); + + // Support for running multiple copies of the same benchmark concurrently + // in multiple threads. This may be useful when measuring the scaling + // of some piece of code. + + // Run one instance of this benchmark concurrently in t threads. + Benchmark* Threads(int t); + + // Pick a set of values T from [min_threads,max_threads]. + // min_threads and max_threads are always included in T. Run this + // benchmark once for each value in T. The benchmark run for a + // particular value t consists of t threads running the benchmark + // function concurrently. For example, consider: + // BENCHMARK(Foo)->ThreadRange(1,16); + // This will run the following benchmarks: + // Foo in 1 thread + // Foo in 2 threads + // Foo in 4 threads + // Foo in 8 threads + // Foo in 16 threads + Benchmark* ThreadRange(int min_threads, int max_threads); + + // For each value n in the range, run this benchmark once using n threads. + // min_threads and max_threads are always included in the range. + // stride specifies the increment. E.g. DenseThreadRange(1, 8, 3) starts + // a benchmark with 1, 4, 7 and 8 threads. + Benchmark* DenseThreadRange(int min_threads, int max_threads, int stride = 1); + + // Equivalent to ThreadRange(NumCPUs(), NumCPUs()) + Benchmark* ThreadPerCpu(); + + virtual void Run(State& state) = 0; + + // Used inside the benchmark implementation + struct Instance; + + protected: + explicit Benchmark(const char* name); + Benchmark(Benchmark const&); + void SetName(const char* name); + + int ArgsCnt() const; + + static void AddRange(std::vector* dst, int lo, int hi, int mult); + + private: + friend class BenchmarkFamilies; + + std::string name_; + ReportMode report_mode_; + std::vector arg_names_; // Args for all benchmark runs + std::vector > args_; // Args for all benchmark runs + TimeUnit time_unit_; + int range_multiplier_; + double min_time_; + size_t iterations_; + int repetitions_; + bool use_real_time_; + bool use_manual_time_; + BigO complexity_; + BigOFunc* complexity_lambda_; + std::vector thread_counts_; + + Benchmark& operator=(Benchmark const&); +}; + +} // namespace internal + +// Create and register a benchmark with the specified 'name' that invokes +// the specified functor 'fn'. +// +// RETURNS: A pointer to the registered benchmark. +internal::Benchmark* RegisterBenchmark(const char* name, + internal::Function* fn); + +#if defined(BENCHMARK_HAS_CXX11) +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn); +#endif + +// Remove all registered benchmarks. All pointers to previously registered +// benchmarks are invalidated. +void ClearRegisteredBenchmarks(); + +namespace internal { +// The class used to hold all Benchmarks created from static function. +// (ie those created using the BENCHMARK(...) macros. +class FunctionBenchmark : public Benchmark { + public: + FunctionBenchmark(const char* name, Function* func) + : Benchmark(name), func_(func) {} + + virtual void Run(State& st); + + private: + Function* func_; +}; + +#ifdef BENCHMARK_HAS_CXX11 +template +class LambdaBenchmark : public Benchmark { + public: + virtual void Run(State& st) { lambda_(st); } + + private: + template + LambdaBenchmark(const char* name, OLambda&& lam) + : Benchmark(name), lambda_(std::forward(lam)) {} + + LambdaBenchmark(LambdaBenchmark const&) = delete; + + private: + template + friend Benchmark* ::benchmark::RegisterBenchmark(const char*, Lam&&); + + Lambda lambda_; +}; +#endif + +} // namespace internal + +inline internal::Benchmark* RegisterBenchmark(const char* name, + internal::Function* fn) { + return internal::RegisterBenchmarkInternal( + ::new internal::FunctionBenchmark(name, fn)); +} + +#ifdef BENCHMARK_HAS_CXX11 +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn) { + using BenchType = + internal::LambdaBenchmark::type>; + return internal::RegisterBenchmarkInternal( + ::new BenchType(name, std::forward(fn))); +} +#endif + +#if defined(BENCHMARK_HAS_CXX11) && \ + (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn, + Args&&... args) { + return benchmark::RegisterBenchmark( + name, [=](benchmark::State& st) { fn(st, args...); }); +} +#else +#define BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK +#endif + +// The base class for all fixture tests. +class Fixture : public internal::Benchmark { + public: + Fixture() : internal::Benchmark("") {} + + virtual void Run(State& st) { + this->SetUp(st); + this->BenchmarkCase(st); + this->TearDown(st); + } + + // These will be deprecated ... + virtual void SetUp(const State&) {} + virtual void TearDown(const State&) {} + // ... In favor of these. + virtual void SetUp(State& st) { SetUp(const_cast(st)); } + virtual void TearDown(State& st) { TearDown(const_cast(st)); } + + protected: + virtual void BenchmarkCase(State&) = 0; +}; + +} // namespace benchmark + +// ------------------------------------------------------ +// Macro to register benchmarks + +// Check that __COUNTER__ is defined and that __COUNTER__ increases by 1 +// every time it is expanded. X + 1 == X + 0 is used in case X is defined to be +// empty. If X is empty the expression becomes (+1 == +0). +#if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) +#define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__ +#else +#define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__ +#endif + +// Helpers for generating unique variable names +#define BENCHMARK_PRIVATE_NAME(n) \ + BENCHMARK_PRIVATE_CONCAT(_benchmark_, BENCHMARK_PRIVATE_UNIQUE_ID, n) +#define BENCHMARK_PRIVATE_CONCAT(a, b, c) BENCHMARK_PRIVATE_CONCAT2(a, b, c) +#define BENCHMARK_PRIVATE_CONCAT2(a, b, c) a##b##c + +#define BENCHMARK_PRIVATE_DECLARE(n) \ + static ::benchmark::internal::Benchmark* BENCHMARK_PRIVATE_NAME(n) \ + BENCHMARK_UNUSED + +#define BENCHMARK(n) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark(#n, n))) + +// Old-style macros +#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) +#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->Args({(a1), (a2)}) +#define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t)) +#define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) +#define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ + BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}}) + +#if __cplusplus >= 201103L + +// Register a benchmark which invokes the function specified by `func` +// with the additional arguments specified by `...`. +// +// For example: +// +// template ` +// void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { +// [...] +//} +// /* Registers a benchmark named "BM_takes_args/int_string_test` */ +// BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); +#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(func) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark( \ + #func "/" #test_case_name, \ + [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) + +#endif // __cplusplus >= 11 + +// This will register a benchmark for a templatized function. For example: +// +// template +// void BM_Foo(int iters); +// +// BENCHMARK_TEMPLATE(BM_Foo, 1); +// +// will register BM_Foo<1> as a benchmark. +#define BENCHMARK_TEMPLATE1(n, a) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark(#n "<" #a ">", n))) + +#define BENCHMARK_TEMPLATE2(n, a, b) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark(#n "<" #a "," #b ">", \ + n))) + +#if __cplusplus >= 201103L +#define BENCHMARK_TEMPLATE(n, ...) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark( \ + #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) +#else +#define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a) +#endif + +#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() : BaseClass() { \ + this->SetName(#BaseClass "/" #Method); \ + } \ + \ + protected: \ + virtual void BenchmarkCase(::benchmark::State&); \ + }; + +#define BENCHMARK_DEFINE_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#define BENCHMARK_REGISTER_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_REGISTER_F(BaseClass##_##Method##_Benchmark) + +#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ + BENCHMARK_PRIVATE_DECLARE(TestName) = \ + (::benchmark::internal::RegisterBenchmarkInternal(new TestName())) + +// This macro will define and register a benchmark within a fixture class. +#define BENCHMARK_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +// Helper macro to create a main routine in a test that runs the benchmarks +#define BENCHMARK_MAIN() \ + int main(int argc, char** argv) { \ + ::benchmark::Initialize(&argc, argv); \ + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; \ + ::benchmark::RunSpecifiedBenchmarks(); \ + } + + +// ------------------------------------------------------ +// Benchmark Reporters + +namespace benchmark { + +// Interface for custom benchmark result printers. +// By default, benchmark reports are printed to stdout. However an application +// can control the destination of the reports by calling +// RunSpecifiedBenchmarks and passing it a custom reporter object. +// The reporter object must implement the following interface. +class BenchmarkReporter { + public: + struct Context { + int num_cpus; + double mhz_per_cpu; + bool cpu_scaling_enabled; + + // The number of chars in the longest benchmark name. + size_t name_field_width; + }; + + struct Run { + Run() + : error_occurred(false), + iterations(1), + time_unit(kNanosecond), + real_accumulated_time(0), + cpu_accumulated_time(0), + bytes_per_second(0), + items_per_second(0), + max_heapbytes_used(0), + complexity(oNone), + complexity_lambda(), + complexity_n(0), + report_big_o(false), + report_rms(false), + counters() {} + + std::string benchmark_name; + std::string report_label; // Empty if not set by benchmark. + bool error_occurred; + std::string error_message; + + int64_t iterations; + TimeUnit time_unit; + double real_accumulated_time; + double cpu_accumulated_time; + + // Return a value representing the real time per iteration in the unit + // specified by 'time_unit'. + // NOTE: If 'iterations' is zero the returned value represents the + // accumulated time. + double GetAdjustedRealTime() const; + + // Return a value representing the cpu time per iteration in the unit + // specified by 'time_unit'. + // NOTE: If 'iterations' is zero the returned value represents the + // accumulated time. + double GetAdjustedCPUTime() const; + + // Zero if not set by benchmark. + double bytes_per_second; + double items_per_second; + + // This is set to 0.0 if memory tracing is not enabled. + double max_heapbytes_used; + + // Keep track of arguments to compute asymptotic complexity + BigO complexity; + BigOFunc* complexity_lambda; + int complexity_n; + + // Inform print function whether the current run is a complexity report + bool report_big_o; + bool report_rms; + + UserCounters counters; + }; + + // Construct a BenchmarkReporter with the output stream set to 'std::cout' + // and the error stream set to 'std::cerr' + BenchmarkReporter(); + + // Called once for every suite of benchmarks run. + // The parameter "context" contains information that the + // reporter may wish to use when generating its report, for example the + // platform under which the benchmarks are running. The benchmark run is + // never started if this function returns false, allowing the reporter + // to skip runs based on the context information. + virtual bool ReportContext(const Context& context) = 0; + + // Called once for each group of benchmark runs, gives information about + // cpu-time and heap memory usage during the benchmark run. If the group + // of runs contained more than two entries then 'report' contains additional + // elements representing the mean and standard deviation of those runs. + // Additionally if this group of runs was the last in a family of benchmarks + // 'reports' contains additional entries representing the asymptotic + // complexity and RMS of that benchmark family. + virtual void ReportRuns(const std::vector& report) = 0; + + // Called once and only once after ever group of benchmarks is run and + // reported. + virtual void Finalize() {} + + // REQUIRES: The object referenced by 'out' is valid for the lifetime + // of the reporter. + void SetOutputStream(std::ostream* out) { + assert(out); + output_stream_ = out; + } + + // REQUIRES: The object referenced by 'err' is valid for the lifetime + // of the reporter. + void SetErrorStream(std::ostream* err) { + assert(err); + error_stream_ = err; + } + + std::ostream& GetOutputStream() const { return *output_stream_; } + + std::ostream& GetErrorStream() const { return *error_stream_; } + + virtual ~BenchmarkReporter(); + + // Write a human readable string to 'out' representing the specified + // 'context'. + // REQUIRES: 'out' is non-null. + static void PrintBasicContext(std::ostream* out, Context const& context); + + private: + std::ostream* output_stream_; + std::ostream* error_stream_; +}; + +// Simple reporter that outputs benchmark data to the console. This is the +// default reporter used by RunSpecifiedBenchmarks(). +class ConsoleReporter : public BenchmarkReporter { +public: + enum OutputOptions { + OO_None = 0, + OO_Color = 1, + OO_Tabular = 2, + OO_ColorTabular = OO_Color|OO_Tabular, + OO_Defaults = OO_ColorTabular + }; + explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) + : output_options_(opts_), name_field_width_(0), + prev_counters_(), printed_header_(false) {} + + virtual bool ReportContext(const Context& context); + virtual void ReportRuns(const std::vector& reports); + + protected: + virtual void PrintRunData(const Run& report); + virtual void PrintHeader(const Run& report); + + OutputOptions output_options_; + size_t name_field_width_; + UserCounters prev_counters_; + bool printed_header_; +}; + +class JSONReporter : public BenchmarkReporter { + public: + JSONReporter() : first_report_(true) {} + virtual bool ReportContext(const Context& context); + virtual void ReportRuns(const std::vector& reports); + virtual void Finalize(); + + private: + void PrintRunData(const Run& report); + + bool first_report_; +}; + +class CSVReporter : public BenchmarkReporter { + public: + CSVReporter() : printed_header_(false) {} + virtual bool ReportContext(const Context& context); + virtual void ReportRuns(const std::vector& reports); + + private: + void PrintRunData(const Run& report); + + bool printed_header_; + std::set< std::string > user_counter_names_; +}; + +inline const char* GetTimeUnitString(TimeUnit unit) { + switch (unit) { + case kMillisecond: + return "ms"; + case kMicrosecond: + return "us"; + case kNanosecond: + default: + return "ns"; + } +} + +inline double GetTimeUnitMultiplier(TimeUnit unit) { + switch (unit) { + case kMillisecond: + return 1e3; + case kMicrosecond: + return 1e6; + case kNanosecond: + default: + return 1e9; + } +} + +} // namespace benchmark + +#endif // BENCHMARK_BENCHMARK_H_ diff --git a/include/benchmark/benchmark_api.h b/include/benchmark/benchmark_api.h new file mode 100644 index 0000000..a9ae671 --- /dev/null +++ b/include/benchmark/benchmark_api.h @@ -0,0 +1,27 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef BENCHMARK_BENCHMARK_API_H_ +#define BENCHMARK_BENCHMARK_API_H_ + +#ifdef __DEPRECATED +# ifndef BENCHMARK_WARNING_MSG +# warning the benchmark_api.h header has been deprecated and will be removed, please include benchmark.h instead +# else + BENCHMARK_WARNING_MSG("the benchmark_api.h header has been deprecated and will be removed, please include benchmark.h instead") +# endif +#endif + +#include "benchmark.h" // For forward declaration of BenchmarkReporter + +#endif // BENCHMARK_BENCHMARK_API_H_ diff --git a/include/benchmark/reporter.h b/include/benchmark/reporter.h new file mode 100644 index 0000000..5baca1a --- /dev/null +++ b/include/benchmark/reporter.h @@ -0,0 +1,27 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef BENCHMARK_REPORTER_H_ +#define BENCHMARK_REPORTER_H_ + +#ifdef __DEPRECATED +# ifndef BENCHMARK_WARNING_MSG +# warning the reporter.h header has been deprecated and will be removed, please include benchmark.h instead +# else + BENCHMARK_WARNING_MSG("the reporter.h header has been deprecated and will be removed, please include benchmark.h instead") +# endif +#endif + +#include "benchmark.h" // For forward declaration of BenchmarkReporter + +#endif // BENCHMARK_REPORTER_H_ diff --git a/mingw.py b/mingw.py new file mode 100644 index 0000000..706ad55 --- /dev/null +++ b/mingw.py @@ -0,0 +1,320 @@ +#! /usr/bin/env python +# encoding: utf-8 + +import argparse +import errno +import logging +import os +import platform +import re +import sys +import subprocess +import tempfile + +try: + import winreg +except ImportError: + import _winreg as winreg +try: + import urllib.request as request +except ImportError: + import urllib as request +try: + import urllib.parse as parse +except ImportError: + import urlparse as parse + +class EmptyLogger(object): + ''' + Provides an implementation that performs no logging + ''' + def debug(self, *k, **kw): + pass + def info(self, *k, **kw): + pass + def warn(self, *k, **kw): + pass + def error(self, *k, **kw): + pass + def critical(self, *k, **kw): + pass + def setLevel(self, *k, **kw): + pass + +urls = ( + 'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20' + 'targetting%20Win32/Personal%20Builds/mingw-builds/installer/' + 'repository.txt', + 'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/' + 'repository.txt' +) +''' +A list of mingw-build repositories +''' + +def repository(urls = urls, log = EmptyLogger()): + ''' + Downloads and parse mingw-build repository files and parses them + ''' + log.info('getting mingw-builds repository') + versions = {} + re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files') + re_sub = r'http://downloads.sourceforge.net/project/\1' + for url in urls: + log.debug(' - requesting: %s', url) + socket = request.urlopen(url) + repo = socket.read() + if not isinstance(repo, str): + repo = repo.decode(); + socket.close() + for entry in repo.split('\n')[:-1]: + value = entry.split('|') + version = tuple([int(n) for n in value[0].strip().split('.')]) + version = versions.setdefault(version, {}) + arch = value[1].strip() + if arch == 'x32': + arch = 'i686' + elif arch == 'x64': + arch = 'x86_64' + arch = version.setdefault(arch, {}) + threading = arch.setdefault(value[2].strip(), {}) + exceptions = threading.setdefault(value[3].strip(), {}) + revision = exceptions.setdefault(int(value[4].strip()[3:]), + re_sourceforge.sub(re_sub, value[5].strip())) + return versions + +def find_in_path(file, path=None): + ''' + Attempts to find an executable in the path + ''' + if platform.system() == 'Windows': + file += '.exe' + if path is None: + path = os.environ.get('PATH', '') + if type(path) is type(''): + path = path.split(os.pathsep) + return list(filter(os.path.exists, + map(lambda dir, file=file: os.path.join(dir, file), path))) + +def find_7zip(log = EmptyLogger()): + ''' + Attempts to find 7zip for unpacking the mingw-build archives + ''' + log.info('finding 7zip') + path = find_in_path('7z') + if not path: + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip') + path, _ = winreg.QueryValueEx(key, 'Path') + path = [os.path.join(path, '7z.exe')] + log.debug('found \'%s\'', path[0]) + return path[0] + +find_7zip() + +def unpack(archive, location, log = EmptyLogger()): + ''' + Unpacks a mingw-builds archive + ''' + sevenzip = find_7zip(log) + log.info('unpacking %s', os.path.basename(archive)) + cmd = [sevenzip, 'x', archive, '-o' + location, '-y'] + log.debug(' - %r', cmd) + with open(os.devnull, 'w') as devnull: + subprocess.check_call(cmd, stdout = devnull) + +def download(url, location, log = EmptyLogger()): + ''' + Downloads and unpacks a mingw-builds archive + ''' + log.info('downloading MinGW') + log.debug(' - url: %s', url) + log.debug(' - location: %s', location) + + re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*') + + stream = request.urlopen(url) + try: + content = stream.getheader('Content-Disposition') or '' + except AttributeError: + content = stream.headers.getheader('Content-Disposition') or '' + matches = re_content.match(content) + if matches: + filename = matches.group(2) + else: + parsed = parse.urlparse(stream.geturl()) + filename = os.path.basename(parsed.path) + + try: + os.makedirs(location) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(location): + pass + else: + raise + + archive = os.path.join(location, filename) + with open(archive, 'wb') as out: + while True: + buf = stream.read(1024) + if not buf: + break + out.write(buf) + unpack(archive, location, log = log) + os.remove(archive) + + possible = os.path.join(location, 'mingw64') + if not os.path.exists(possible): + possible = os.path.join(location, 'mingw32') + if not os.path.exists(possible): + raise ValueError('Failed to find unpacked MinGW: ' + possible) + return possible + +def root(location = None, arch = None, version = None, threading = None, + exceptions = None, revision = None, log = EmptyLogger()): + ''' + Returns the root folder of a specific version of the mingw-builds variant + of gcc. Will download the compiler if needed + ''' + + # Get the repository if we don't have all the information + if not (arch and version and threading and exceptions and revision): + versions = repository(log = log) + + # Determine some defaults + version = version or max(versions.keys()) + if not arch: + arch = platform.machine().lower() + if arch == 'x86': + arch = 'i686' + elif arch == 'amd64': + arch = 'x86_64' + if not threading: + keys = versions[version][arch].keys() + if 'posix' in keys: + threading = 'posix' + elif 'win32' in keys: + threading = 'win32' + else: + threading = keys[0] + if not exceptions: + keys = versions[version][arch][threading].keys() + if 'seh' in keys: + exceptions = 'seh' + elif 'sjlj' in keys: + exceptions = 'sjlj' + else: + exceptions = keys[0] + if revision == None: + revision = max(versions[version][arch][threading][exceptions].keys()) + if not location: + location = os.path.join(tempfile.gettempdir(), 'mingw-builds') + + # Get the download url + url = versions[version][arch][threading][exceptions][revision] + + # Tell the user whatzzup + log.info('finding MinGW %s', '.'.join(str(v) for v in version)) + log.debug(' - arch: %s', arch) + log.debug(' - threading: %s', threading) + log.debug(' - exceptions: %s', exceptions) + log.debug(' - revision: %s', revision) + log.debug(' - url: %s', url) + + # Store each specific revision differently + slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}' + slug = slug.format( + version = '.'.join(str(v) for v in version), + arch = arch, + threading = threading, + exceptions = exceptions, + revision = revision + ) + if arch == 'x86_64': + root_dir = os.path.join(location, slug, 'mingw64') + elif arch == 'i686': + root_dir = os.path.join(location, slug, 'mingw32') + else: + raise ValueError('Unknown MinGW arch: ' + arch) + + # Download if needed + if not os.path.exists(root_dir): + downloaded = download(url, os.path.join(location, slug), log = log) + if downloaded != root_dir: + raise ValueError('The location of mingw did not match\n%s\n%s' + % (downloaded, root_dir)) + + return root_dir + +def str2ver(string): + ''' + Converts a version string into a tuple + ''' + try: + version = tuple(int(v) for v in string.split('.')) + if len(version) is not 3: + raise ValueError() + except ValueError: + raise argparse.ArgumentTypeError( + 'please provide a three digit version string') + return version + +def main(): + ''' + Invoked when the script is run directly by the python interpreter + ''' + parser = argparse.ArgumentParser( + description = 'Downloads a specific version of MinGW', + formatter_class = argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument('--location', + help = 'the location to download the compiler to', + default = os.path.join(tempfile.gettempdir(), 'mingw-builds')) + parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'], + help = 'the target MinGW architecture string') + parser.add_argument('--version', type = str2ver, + help = 'the version of GCC to download') + parser.add_argument('--threading', choices = ['posix', 'win32'], + help = 'the threading type of the compiler') + parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'], + help = 'the method to throw exceptions') + parser.add_argument('--revision', type=int, + help = 'the revision of the MinGW release') + group = parser.add_mutually_exclusive_group() + group.add_argument('-v', '--verbose', action='store_true', + help='increase the script output verbosity') + group.add_argument('-q', '--quiet', action='store_true', + help='only print errors and warning') + args = parser.parse_args() + + # Create the logger + logger = logging.getLogger('mingw') + handler = logging.StreamHandler() + formatter = logging.Formatter('%(message)s') + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + if args.quiet: + logger.setLevel(logging.WARN) + if args.verbose: + logger.setLevel(logging.DEBUG) + + # Get MinGW + root_dir = root(location = args.location, arch = args.arch, + version = args.version, threading = args.threading, + exceptions = args.exceptions, revision = args.revision, + log = logger) + + sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin')) + +if __name__ == '__main__': + try: + main() + except IOError as e: + sys.stderr.write('IO error: %s\n' % e) + sys.exit(1) + except OSError as e: + sys.stderr.write('OS error: %s\n' % e) + sys.exit(1) + except KeyboardInterrupt as e: + sys.stderr.write('Killed\n') + sys.exit(1) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..244484b --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,78 @@ +# Allow the source files to find headers in src/ +include_directories(${PROJECT_SOURCE_DIR}/src) + +if (DEFINED BENCHMARK_CXX_LINKER_FLAGS) + list(APPEND CMAKE_SHARED_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) + list(APPEND CMAKE_MODULE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) +endif() + +file(GLOB + SOURCE_FILES + *.cc + ${PROJECT_SOURCE_DIR}/include/benchmark/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.h) + +add_library(benchmark ${SOURCE_FILES}) +set_target_properties(benchmark PROPERTIES + OUTPUT_NAME "benchmark" + VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION} +) +target_include_directories(benchmark PUBLIC + $ + ) + +# Link threads. +target_link_libraries(benchmark ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +find_library(LIBRT rt) +if(LIBRT) + target_link_libraries(benchmark ${LIBRT}) +endif() + +# We need extra libraries on Windows +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(benchmark Shlwapi) +endif() + +set(include_install_dir "include") +set(lib_install_dir "lib/") +set(bin_install_dir "bin/") +set(config_install_dir "lib/cmake/${PROJECT_NAME}") + +set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") + +set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") +set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") +set(targets_export_name "${PROJECT_NAME}Targets") + +set(namespace "${PROJECT_NAME}::") + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${version_config}" VERSION ${GIT_VERSION} COMPATIBILITY SameMajorVersion +) + +configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY) + +# Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable) +install( + TARGETS benchmark + EXPORT ${targets_export_name} + ARCHIVE DESTINATION ${lib_install_dir} + LIBRARY DESTINATION ${lib_install_dir} + RUNTIME DESTINATION ${bin_install_dir} + INCLUDES DESTINATION ${include_install_dir}) + +install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark" + DESTINATION ${include_install_dir} + FILES_MATCHING PATTERN "*.*h") + +install( + FILES "${project_config}" "${version_config}" + DESTINATION "${config_install_dir}") + +install( + EXPORT "${targets_export_name}" + NAMESPACE "${namespace}" + DESTINATION "${config_install_dir}") diff --git a/src/arraysize.h b/src/arraysize.h new file mode 100644 index 0000000..51a50f2 --- /dev/null +++ b/src/arraysize.h @@ -0,0 +1,33 @@ +#ifndef BENCHMARK_ARRAYSIZE_H_ +#define BENCHMARK_ARRAYSIZE_H_ + +#include "internal_macros.h" + +namespace benchmark { +namespace internal { +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template +char (&ArraySizeHelper(T (&array)[N]))[N]; + +// That gcc wants both of these prototypes seems mysterious. VC, for +// its part, can't decide which to use (another mystery). Matching of +// template overloads: the final frontier. +#ifndef COMPILER_MSVC +template +char (&ArraySizeHelper(const T (&array)[N]))[N]; +#endif + +#define arraysize(array) (sizeof(::benchmark::internal::ArraySizeHelper(array))) + +} // end namespace internal +} // end namespace benchmark + +#endif // BENCHMARK_ARRAYSIZE_H_ diff --git a/src/benchmark.cc b/src/benchmark.cc new file mode 100644 index 0000000..1ba0a50 --- /dev/null +++ b/src/benchmark.cc @@ -0,0 +1,715 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "benchmark_api_internal.h" +#include "internal_macros.h" + +#ifndef BENCHMARK_OS_WINDOWS +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "colorprint.h" +#include "commandlineflags.h" +#include "complexity.h" +#include "counter.h" +#include "log.h" +#include "mutex.h" +#include "re.h" +#include "stat.h" +#include "string_util.h" +#include "sysinfo.h" +#include "timers.h" + +DEFINE_bool(benchmark_list_tests, false, + "Print a list of benchmarks. This option overrides all other " + "options."); + +DEFINE_string(benchmark_filter, ".", + "A regular expression that specifies the set of benchmarks " + "to execute. If this flag is empty, no benchmarks are run. " + "If this flag is the string \"all\", all benchmarks linked " + "into the process are run."); + +DEFINE_double(benchmark_min_time, 0.5, + "Minimum number of seconds we should run benchmark before " + "results are considered significant. For cpu-time based " + "tests, this is the lower bound on the total cpu time " + "used by all threads that make up the test. For real-time " + "based tests, this is the lower bound on the elapsed time " + "of the benchmark execution, regardless of number of " + "threads."); + +DEFINE_int32(benchmark_repetitions, 1, + "The number of runs of each benchmark. If greater than 1, the " + "mean and standard deviation of the runs will be reported."); + +DEFINE_bool(benchmark_report_aggregates_only, false, + "Report the result of each benchmark repetitions. When 'true' is " + "specified only the mean, standard deviation, and other statistics " + "are reported for repeated benchmarks."); + +DEFINE_string(benchmark_format, "console", + "The format to use for console output. Valid values are " + "'console', 'json', or 'csv'."); + +DEFINE_string(benchmark_out_format, "json", + "The format to use for file output. Valid values are " + "'console', 'json', or 'csv'."); + +DEFINE_string(benchmark_out, "", "The file to write additonal output to"); + +DEFINE_string(benchmark_color, "auto", + "Whether to use colors in the output. Valid values: " + "'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use " + "colors if the output is being sent to a terminal and the TERM " + "environment variable is set to a terminal type that supports " + "colors."); + +DEFINE_bool(benchmark_counters_tabular, false, + "Whether to use tabular format when printing user counters to " + "the console. Valid values: 'true'/'yes'/1, 'false'/'no'/0." + "Defaults to false."); + +DEFINE_int32(v, 0, "The level of verbose logging to output"); + +namespace benchmark { +namespace internal { + +void UseCharPointer(char const volatile*) {} + +} // end namespace internal + +namespace { + +static const size_t kMaxIterations = 1000000000; + +} // end namespace + +namespace internal { + +class ThreadManager { + public: + ThreadManager(int num_threads) + : alive_threads_(num_threads), start_stop_barrier_(num_threads) {} + + Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) { + return benchmark_mutex_; + } + + bool StartStopBarrier() EXCLUDES(end_cond_mutex_) { + return start_stop_barrier_.wait(); + } + + void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) { + start_stop_barrier_.removeThread(); + if (--alive_threads_ == 0) { + MutexLock lock(end_cond_mutex_); + end_condition_.notify_all(); + } + } + + void WaitForAllThreads() EXCLUDES(end_cond_mutex_) { + MutexLock lock(end_cond_mutex_); + end_condition_.wait(lock.native_handle(), + [this]() { return alive_threads_ == 0; }); + } + + public: + struct Result { + double real_time_used = 0; + double cpu_time_used = 0; + double manual_time_used = 0; + int64_t bytes_processed = 0; + int64_t items_processed = 0; + int complexity_n = 0; + std::string report_label_; + std::string error_message_; + bool has_error_ = false; + UserCounters counters; + }; + GUARDED_BY(GetBenchmarkMutex()) Result results; + + private: + mutable Mutex benchmark_mutex_; + std::atomic alive_threads_; + Barrier start_stop_barrier_; + Mutex end_cond_mutex_; + Condition end_condition_; +}; + +// Timer management class +class ThreadTimer { + public: + ThreadTimer() = default; + + // Called by each thread + void StartTimer() { + running_ = true; + start_real_time_ = ChronoClockNow(); + start_cpu_time_ = ThreadCPUUsage(); + } + + // Called by each thread + void StopTimer() { + CHECK(running_); + running_ = false; + real_time_used_ += ChronoClockNow() - start_real_time_; + cpu_time_used_ += ThreadCPUUsage() - start_cpu_time_; + } + + // Called by each thread + void SetIterationTime(double seconds) { manual_time_used_ += seconds; } + + bool running() const { return running_; } + + // REQUIRES: timer is not running + double real_time_used() { + CHECK(!running_); + return real_time_used_; + } + + // REQUIRES: timer is not running + double cpu_time_used() { + CHECK(!running_); + return cpu_time_used_; + } + + // REQUIRES: timer is not running + double manual_time_used() { + CHECK(!running_); + return manual_time_used_; + } + + private: + bool running_ = false; // Is the timer running + double start_real_time_ = 0; // If running_ + double start_cpu_time_ = 0; // If running_ + + // Accumulated time so far (does not contain current slice if running_) + double real_time_used_ = 0; + double cpu_time_used_ = 0; + // Manually set iteration time. User sets this with SetIterationTime(seconds). + double manual_time_used_ = 0; +}; + +namespace { + +BenchmarkReporter::Run CreateRunReport( + const benchmark::internal::Benchmark::Instance& b, + const internal::ThreadManager::Result& results, size_t iters, + double seconds) { + // Create report about this benchmark run. + BenchmarkReporter::Run report; + + report.benchmark_name = b.name; + report.error_occurred = results.has_error_; + report.error_message = results.error_message_; + report.report_label = results.report_label_; + // Report the total iterations across all threads. + report.iterations = static_cast(iters) * b.threads; + report.time_unit = b.time_unit; + + if (!report.error_occurred) { + double bytes_per_second = 0; + if (results.bytes_processed > 0 && seconds > 0.0) { + bytes_per_second = (results.bytes_processed / seconds); + } + double items_per_second = 0; + if (results.items_processed > 0 && seconds > 0.0) { + items_per_second = (results.items_processed / seconds); + } + + if (b.use_manual_time) { + report.real_accumulated_time = results.manual_time_used; + } else { + report.real_accumulated_time = results.real_time_used; + } + report.cpu_accumulated_time = results.cpu_time_used; + report.bytes_per_second = bytes_per_second; + report.items_per_second = items_per_second; + report.complexity_n = results.complexity_n; + report.complexity = b.complexity; + report.complexity_lambda = b.complexity_lambda; + report.counters = results.counters; + internal::Finish(&report.counters, seconds, b.threads); + } + return report; +} + +// Execute one thread of benchmark b for the specified number of iterations. +// Adds the stats collected for the thread into *total. +void RunInThread(const benchmark::internal::Benchmark::Instance* b, + size_t iters, int thread_id, + internal::ThreadManager* manager) { + internal::ThreadTimer timer; + State st(iters, b->arg, thread_id, b->threads, &timer, manager); + b->benchmark->Run(st); + CHECK(st.iterations() == st.max_iterations) + << "Benchmark returned before State::KeepRunning() returned false!"; + { + MutexLock l(manager->GetBenchmarkMutex()); + internal::ThreadManager::Result& results = manager->results; + results.cpu_time_used += timer.cpu_time_used(); + results.real_time_used += timer.real_time_used(); + results.manual_time_used += timer.manual_time_used(); + results.bytes_processed += st.bytes_processed(); + results.items_processed += st.items_processed(); + results.complexity_n += st.complexity_length_n(); + internal::Increment(&results.counters, st.counters); + } + manager->NotifyThreadComplete(); +} + +std::vector RunBenchmark( + const benchmark::internal::Benchmark::Instance& b, + std::vector* complexity_reports) { + std::vector reports; // return value + + const bool has_explicit_iteration_count = b.iterations != 0; + size_t iters = has_explicit_iteration_count ? b.iterations : 1; + std::unique_ptr manager; + std::vector pool(b.threads - 1); + const int repeats = + b.repetitions != 0 ? b.repetitions : FLAGS_benchmark_repetitions; + const bool report_aggregates_only = + repeats != 1 && + (b.report_mode == internal::RM_Unspecified + ? FLAGS_benchmark_report_aggregates_only + : b.report_mode == internal::RM_ReportAggregatesOnly); + for (int repetition_num = 0; repetition_num < repeats; repetition_num++) { + for (;;) { + // Try benchmark + VLOG(2) << "Running " << b.name << " for " << iters << "\n"; + + manager.reset(new internal::ThreadManager(b.threads)); + for (std::size_t ti = 0; ti < pool.size(); ++ti) { + pool[ti] = std::thread(&RunInThread, &b, iters, + static_cast(ti + 1), manager.get()); + } + RunInThread(&b, iters, 0, manager.get()); + manager->WaitForAllThreads(); + for (std::thread& thread : pool) thread.join(); + internal::ThreadManager::Result results; + { + MutexLock l(manager->GetBenchmarkMutex()); + results = manager->results; + } + manager.reset(); + // Adjust real/manual time stats since they were reported per thread. + results.real_time_used /= b.threads; + results.manual_time_used /= b.threads; + + VLOG(2) << "Ran in " << results.cpu_time_used << "/" + << results.real_time_used << "\n"; + + // Base decisions off of real time if requested by this benchmark. + double seconds = results.cpu_time_used; + if (b.use_manual_time) { + seconds = results.manual_time_used; + } else if (b.use_real_time) { + seconds = results.real_time_used; + } + + const double min_time = + !IsZero(b.min_time) ? b.min_time : FLAGS_benchmark_min_time; + + // Determine if this run should be reported; Either it has + // run for a sufficient amount of time or because an error was reported. + const bool should_report = repetition_num > 0 + || has_explicit_iteration_count // An exact iteration count was requested + || results.has_error_ + || iters >= kMaxIterations + || seconds >= min_time // the elapsed time is large enough + // CPU time is specified but the elapsed real time greatly exceeds the + // minimum time. Note that user provided timers are except from this + // sanity check. + || ((results.real_time_used >= 5 * min_time) && !b.use_manual_time); + + if (should_report) { + BenchmarkReporter::Run report = + CreateRunReport(b, results, iters, seconds); + if (!report.error_occurred && b.complexity != oNone) + complexity_reports->push_back(report); + reports.push_back(report); + break; + } + + // See how much iterations should be increased by + // Note: Avoid division by zero with max(seconds, 1ns). + double multiplier = min_time * 1.4 / std::max(seconds, 1e-9); + // If our last run was at least 10% of FLAGS_benchmark_min_time then we + // use the multiplier directly. Otherwise we use at most 10 times + // expansion. + // NOTE: When the last run was at least 10% of the min time the max + // expansion should be 14x. + bool is_significant = (seconds / min_time) > 0.1; + multiplier = is_significant ? multiplier : std::min(10.0, multiplier); + if (multiplier <= 1.0) multiplier = 2.0; + double next_iters = std::max(multiplier * iters, iters + 1.0); + if (next_iters > kMaxIterations) { + next_iters = kMaxIterations; + } + VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n"; + iters = static_cast(next_iters + 0.5); + } + } + // Calculate additional statistics + auto stat_reports = ComputeStats(reports); + if ((b.complexity != oNone) && b.last_benchmark_instance) { + auto additional_run_stats = ComputeBigO(*complexity_reports); + stat_reports.insert(stat_reports.end(), additional_run_stats.begin(), + additional_run_stats.end()); + complexity_reports->clear(); + } + + if (report_aggregates_only) reports.clear(); + reports.insert(reports.end(), stat_reports.begin(), stat_reports.end()); + return reports; +} + +} // namespace +} // namespace internal + +State::State(size_t max_iters, const std::vector& ranges, int thread_i, + int n_threads, internal::ThreadTimer* timer, + internal::ThreadManager* manager) + : started_(false), + finished_(false), + total_iterations_(0), + range_(ranges), + bytes_processed_(0), + items_processed_(0), + complexity_n_(0), + error_occurred_(false), + counters(), + thread_index(thread_i), + threads(n_threads), + max_iterations(max_iters), + timer_(timer), + manager_(manager) { + CHECK(max_iterations != 0) << "At least one iteration must be run"; + CHECK_LT(thread_index, threads) << "thread_index must be less than threads"; +} + +void State::PauseTiming() { + // Add in time accumulated so far + CHECK(started_ && !finished_ && !error_occurred_); + timer_->StopTimer(); +} + +void State::ResumeTiming() { + CHECK(started_ && !finished_ && !error_occurred_); + timer_->StartTimer(); +} + +void State::SkipWithError(const char* msg) { + CHECK(msg); + error_occurred_ = true; + { + MutexLock l(manager_->GetBenchmarkMutex()); + if (manager_->results.has_error_ == false) { + manager_->results.error_message_ = msg; + manager_->results.has_error_ = true; + } + } + total_iterations_ = max_iterations; + if (timer_->running()) timer_->StopTimer(); +} + +void State::SetIterationTime(double seconds) { + timer_->SetIterationTime(seconds); +} + +void State::SetLabel(const char* label) { + MutexLock l(manager_->GetBenchmarkMutex()); + manager_->results.report_label_ = label; +} + +void State::StartKeepRunning() { + CHECK(!started_ && !finished_); + started_ = true; + manager_->StartStopBarrier(); + if (!error_occurred_) ResumeTiming(); +} + +void State::FinishKeepRunning() { + CHECK(started_ && (!finished_ || error_occurred_)); + if (!error_occurred_) { + PauseTiming(); + } + // Total iterations now is one greater than max iterations. Fix this. + total_iterations_ = max_iterations; + finished_ = true; + manager_->StartStopBarrier(); +} + +namespace internal { +namespace { + +void RunBenchmarks(const std::vector& benchmarks, + BenchmarkReporter* console_reporter, + BenchmarkReporter* file_reporter) { + // Note the file_reporter can be null. + CHECK(console_reporter != nullptr); + + // Determine the width of the name field using a minimum width of 10. + bool has_repetitions = FLAGS_benchmark_repetitions > 1; + size_t name_field_width = 10; + for (const Benchmark::Instance& benchmark : benchmarks) { + name_field_width = + std::max(name_field_width, benchmark.name.size()); + has_repetitions |= benchmark.repetitions > 1; + } + if (has_repetitions) name_field_width += std::strlen("_stddev"); + + // Print header here + BenchmarkReporter::Context context; + context.num_cpus = NumCPUs(); + context.mhz_per_cpu = CyclesPerSecond() / 1000000.0f; + + context.cpu_scaling_enabled = CpuScalingEnabled(); + context.name_field_width = name_field_width; + + // Keep track of runing times of all instances of current benchmark + std::vector complexity_reports; + + // We flush streams after invoking reporter methods that write to them. This + // ensures users get timely updates even when streams are not line-buffered. + auto flushStreams = [](BenchmarkReporter* reporter) { + if (!reporter) return; + std::flush(reporter->GetOutputStream()); + std::flush(reporter->GetErrorStream()); + }; + + if (console_reporter->ReportContext(context) && + (!file_reporter || file_reporter->ReportContext(context))) { + flushStreams(console_reporter); + flushStreams(file_reporter); + for (const auto& benchmark : benchmarks) { + std::vector reports = + RunBenchmark(benchmark, &complexity_reports); + console_reporter->ReportRuns(reports); + if (file_reporter) file_reporter->ReportRuns(reports); + flushStreams(console_reporter); + flushStreams(file_reporter); + } + } + console_reporter->Finalize(); + if (file_reporter) file_reporter->Finalize(); + flushStreams(console_reporter); + flushStreams(file_reporter); +} + +std::unique_ptr CreateReporter( + std::string const& name, ConsoleReporter::OutputOptions output_opts) { + typedef std::unique_ptr PtrType; + if (name == "console") { + return PtrType(new ConsoleReporter(output_opts)); + } else if (name == "json") { + return PtrType(new JSONReporter); + } else if (name == "csv") { + return PtrType(new CSVReporter); + } else { + std::cerr << "Unexpected format: '" << name << "'\n"; + std::exit(1); + } +} + +} // end namespace + +bool IsZero(double n) { + return std::abs(n) < std::numeric_limits::epsilon(); +} + +ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) { + int output_opts = ConsoleReporter::OO_Defaults; + if ((FLAGS_benchmark_color == "auto" && IsColorTerminal()) || + IsTruthyFlagValue(FLAGS_benchmark_color)) { + output_opts |= ConsoleReporter::OO_Color; + } else { + output_opts &= ~ConsoleReporter::OO_Color; + } + if(force_no_color) { + output_opts &= ~ConsoleReporter::OO_Color; + } + if(FLAGS_benchmark_counters_tabular) { + output_opts |= ConsoleReporter::OO_Tabular; + } else { + output_opts &= ~ConsoleReporter::OO_Tabular; + } + return static_cast< ConsoleReporter::OutputOptions >(output_opts); +} + +} // end namespace internal + +size_t RunSpecifiedBenchmarks() { + return RunSpecifiedBenchmarks(nullptr, nullptr); +} + +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter) { + return RunSpecifiedBenchmarks(console_reporter, nullptr); +} + +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter, + BenchmarkReporter* file_reporter) { + std::string spec = FLAGS_benchmark_filter; + if (spec.empty() || spec == "all") + spec = "."; // Regexp that matches all benchmarks + + // Setup the reporters + std::ofstream output_file; + std::unique_ptr default_console_reporter; + std::unique_ptr default_file_reporter; + if (!console_reporter) { + default_console_reporter = internal::CreateReporter( + FLAGS_benchmark_format, internal::GetOutputOptions()); + console_reporter = default_console_reporter.get(); + } + auto& Out = console_reporter->GetOutputStream(); + auto& Err = console_reporter->GetErrorStream(); + + std::string const& fname = FLAGS_benchmark_out; + if (fname.empty() && file_reporter) { + Err << "A custom file reporter was provided but " + "--benchmark_out= was not specified." + << std::endl; + std::exit(1); + } + if (!fname.empty()) { + output_file.open(fname); + if (!output_file.is_open()) { + Err << "invalid file name: '" << fname << std::endl; + std::exit(1); + } + if (!file_reporter) { + default_file_reporter = internal::CreateReporter( + FLAGS_benchmark_out_format, ConsoleReporter::OO_None); + file_reporter = default_file_reporter.get(); + } + file_reporter->SetOutputStream(&output_file); + file_reporter->SetErrorStream(&output_file); + } + + std::vector benchmarks; + if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0; + + if (benchmarks.empty()) { + Err << "Failed to match any benchmarks against regex: " << spec << "\n"; + return 0; + } + + if (FLAGS_benchmark_list_tests) { + for (auto const& benchmark : benchmarks) Out << benchmark.name << "\n"; + } else { + internal::RunBenchmarks(benchmarks, console_reporter, file_reporter); + } + + return benchmarks.size(); +} + +namespace internal { + +void PrintUsageAndExit() { + fprintf(stdout, + "benchmark" + " [--benchmark_list_tests={true|false}]\n" + " [--benchmark_filter=]\n" + " [--benchmark_min_time=]\n" + " [--benchmark_repetitions=]\n" + " [--benchmark_report_aggregates_only={true|false}\n" + " [--benchmark_format=]\n" + " [--benchmark_out=]\n" + " [--benchmark_out_format=]\n" + " [--benchmark_color={auto|true|false}]\n" + " [--benchmark_counters_tabular={true|false}]\n" + " [--v=]\n"); + exit(0); +} + +void ParseCommandLineFlags(int* argc, char** argv) { + using namespace benchmark; + for (int i = 1; i < *argc; ++i) { + if (ParseBoolFlag(argv[i], "benchmark_list_tests", + &FLAGS_benchmark_list_tests) || + ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) || + ParseDoubleFlag(argv[i], "benchmark_min_time", + &FLAGS_benchmark_min_time) || + ParseInt32Flag(argv[i], "benchmark_repetitions", + &FLAGS_benchmark_repetitions) || + ParseBoolFlag(argv[i], "benchmark_report_aggregates_only", + &FLAGS_benchmark_report_aggregates_only) || + ParseStringFlag(argv[i], "benchmark_format", &FLAGS_benchmark_format) || + ParseStringFlag(argv[i], "benchmark_out", &FLAGS_benchmark_out) || + ParseStringFlag(argv[i], "benchmark_out_format", + &FLAGS_benchmark_out_format) || + ParseStringFlag(argv[i], "benchmark_color", &FLAGS_benchmark_color) || + // "color_print" is the deprecated name for "benchmark_color". + // TODO: Remove this. + ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) || + ParseBoolFlag(argv[i], "benchmark_counters_tabular", + &FLAGS_benchmark_counters_tabular) || + ParseInt32Flag(argv[i], "v", &FLAGS_v)) { + for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1]; + + --(*argc); + --i; + } else if (IsFlag(argv[i], "help")) { + PrintUsageAndExit(); + } + } + for (auto const* flag : + {&FLAGS_benchmark_format, &FLAGS_benchmark_out_format}) + if (*flag != "console" && *flag != "json" && *flag != "csv") { + PrintUsageAndExit(); + } + if (FLAGS_benchmark_color.empty()) { + PrintUsageAndExit(); + } +} + +int InitializeStreams() { + static std::ios_base::Init init; + return 0; +} + +} // end namespace internal + +void Initialize(int* argc, char** argv) { + internal::ParseCommandLineFlags(argc, argv); + internal::LogLevel() = FLAGS_v; +} + +bool ReportUnrecognizedArguments(int argc, char** argv) { + for (int i = 1; i < argc; ++i) { + fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0], argv[i]); + } + return argc > 1; +} + +} // end namespace benchmark diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h new file mode 100644 index 0000000..36d2340 --- /dev/null +++ b/src/benchmark_api_internal.h @@ -0,0 +1,46 @@ +#ifndef BENCHMARK_API_INTERNAL_H +#define BENCHMARK_API_INTERNAL_H + +#include "benchmark/benchmark.h" + +#include +#include +#include +#include +#include + +namespace benchmark { +namespace internal { + +// Information kept per benchmark we may want to run +struct Benchmark::Instance { + std::string name; + Benchmark* benchmark; + ReportMode report_mode; + std::vector arg; + TimeUnit time_unit; + int range_multiplier; + bool use_real_time; + bool use_manual_time; + BigO complexity; + BigOFunc* complexity_lambda; + UserCounters counters; + bool last_benchmark_instance; + int repetitions; + double min_time; + size_t iterations; + int threads; // Number of concurrent threads to us +}; + +bool FindBenchmarksInternal(const std::string& re, + std::vector* benchmarks, + std::ostream* Err); + +bool IsZero(double n); + +ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color = false); + +} // end namespace internal +} // end namespace benchmark + +#endif // BENCHMARK_API_INTERNAL_H diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc new file mode 100644 index 0000000..ed70d82 --- /dev/null +++ b/src/benchmark_register.cc @@ -0,0 +1,467 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "benchmark_api_internal.h" +#include "internal_macros.h" + +#ifndef BENCHMARK_OS_WINDOWS +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "commandlineflags.h" +#include "complexity.h" +#include "log.h" +#include "mutex.h" +#include "re.h" +#include "stat.h" +#include "string_util.h" +#include "sysinfo.h" +#include "timers.h" + +namespace benchmark { + +namespace { +// For non-dense Range, intermediate values are powers of kRangeMultiplier. +static const int kRangeMultiplier = 8; +// The size of a benchmark family determines is the number of inputs to repeat +// the benchmark on. If this is "large" then warn the user during configuration. +static const size_t kMaxFamilySize = 100; +} // end namespace + +namespace internal { + +//=============================================================================// +// BenchmarkFamilies +//=============================================================================// + +// Class for managing registered benchmarks. Note that each registered +// benchmark identifies a family of related benchmarks to run. +class BenchmarkFamilies { + public: + static BenchmarkFamilies* GetInstance(); + + // Registers a benchmark family and returns the index assigned to it. + size_t AddBenchmark(std::unique_ptr family); + + // Clear all registered benchmark families. + void ClearBenchmarks(); + + // Extract the list of benchmark instances that match the specified + // regular expression. + bool FindBenchmarks(const std::string& re, + std::vector* benchmarks, + std::ostream* Err); + + private: + BenchmarkFamilies() {} + + std::vector> families_; + Mutex mutex_; +}; + +BenchmarkFamilies* BenchmarkFamilies::GetInstance() { + static BenchmarkFamilies instance; + return &instance; +} + +size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr family) { + MutexLock l(mutex_); + size_t index = families_.size(); + families_.push_back(std::move(family)); + return index; +} + +void BenchmarkFamilies::ClearBenchmarks() { + MutexLock l(mutex_); + families_.clear(); + families_.shrink_to_fit(); +} + +bool BenchmarkFamilies::FindBenchmarks( + const std::string& spec, std::vector* benchmarks, + std::ostream* ErrStream) { + CHECK(ErrStream); + auto& Err = *ErrStream; + // Make regular expression out of command-line flag + std::string error_msg; + Regex re; + if (!re.Init(spec, &error_msg)) { + Err << "Could not compile benchmark re: " << error_msg << std::endl; + return false; + } + + // Special list of thread counts to use when none are specified + const std::vector one_thread = {1}; + + MutexLock l(mutex_); + for (std::unique_ptr& family : families_) { + // Family was deleted or benchmark doesn't match + if (!family) continue; + + if (family->ArgsCnt() == -1) { + family->Args({}); + } + const std::vector* thread_counts = + (family->thread_counts_.empty() + ? &one_thread + : &static_cast&>(family->thread_counts_)); + const size_t family_size = family->args_.size() * thread_counts->size(); + // The benchmark will be run at least 'family_size' different inputs. + // If 'family_size' is very large warn the user. + if (family_size > kMaxFamilySize) { + Err << "The number of inputs is very large. " << family->name_ + << " will be repeated at least " << family_size << " times.\n"; + } + // reserve in the special case the regex ".", since we know the final + // family size. + if (spec == ".") benchmarks->reserve(family_size); + + for (auto const& args : family->args_) { + for (int num_threads : *thread_counts) { + Benchmark::Instance instance; + instance.name = family->name_; + instance.benchmark = family.get(); + instance.report_mode = family->report_mode_; + instance.arg = args; + instance.time_unit = family->time_unit_; + instance.range_multiplier = family->range_multiplier_; + instance.min_time = family->min_time_; + instance.iterations = family->iterations_; + instance.repetitions = family->repetitions_; + instance.use_real_time = family->use_real_time_; + instance.use_manual_time = family->use_manual_time_; + instance.complexity = family->complexity_; + instance.complexity_lambda = family->complexity_lambda_; + instance.threads = num_threads; + + // Add arguments to instance name + size_t arg_i = 0; + for (auto const& arg : args) { + instance.name += "/"; + + if (arg_i < family->arg_names_.size()) { + const auto& arg_name = family->arg_names_[arg_i]; + if (!arg_name.empty()) { + instance.name += + StringPrintF("%s:", family->arg_names_[arg_i].c_str()); + } + } + + instance.name += StringPrintF("%d", arg); + ++arg_i; + } + + if (!IsZero(family->min_time_)) + instance.name += StringPrintF("/min_time:%0.3f", family->min_time_); + if (family->iterations_ != 0) + instance.name += StringPrintF("/iterations:%d", family->iterations_); + if (family->repetitions_ != 0) + instance.name += StringPrintF("/repeats:%d", family->repetitions_); + + if (family->use_manual_time_) { + instance.name += "/manual_time"; + } else if (family->use_real_time_) { + instance.name += "/real_time"; + } + + // Add the number of threads used to the name + if (!family->thread_counts_.empty()) { + instance.name += StringPrintF("/threads:%d", instance.threads); + } + + if (re.Match(instance.name)) { + instance.last_benchmark_instance = (&args == &family->args_.back()); + benchmarks->push_back(std::move(instance)); + } + } + } + } + return true; +} + +Benchmark* RegisterBenchmarkInternal(Benchmark* bench) { + std::unique_ptr bench_ptr(bench); + BenchmarkFamilies* families = BenchmarkFamilies::GetInstance(); + families->AddBenchmark(std::move(bench_ptr)); + return bench; +} + +// FIXME: This function is a hack so that benchmark.cc can access +// `BenchmarkFamilies` +bool FindBenchmarksInternal(const std::string& re, + std::vector* benchmarks, + std::ostream* Err) { + return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err); +} + +//=============================================================================// +// Benchmark +//=============================================================================// + +Benchmark::Benchmark(const char* name) + : name_(name), + report_mode_(RM_Unspecified), + time_unit_(kNanosecond), + range_multiplier_(kRangeMultiplier), + min_time_(0), + iterations_(0), + repetitions_(0), + use_real_time_(false), + use_manual_time_(false), + complexity_(oNone), + complexity_lambda_(nullptr) {} + +Benchmark::~Benchmark() {} + +void Benchmark::AddRange(std::vector* dst, int lo, int hi, int mult) { + CHECK_GE(lo, 0); + CHECK_GE(hi, lo); + CHECK_GE(mult, 2); + + // Add "lo" + dst->push_back(lo); + + static const int kint32max = std::numeric_limits::max(); + + // Now space out the benchmarks in multiples of "mult" + for (int32_t i = 1; i < kint32max / mult; i *= mult) { + if (i >= hi) break; + if (i > lo) { + dst->push_back(i); + } + } + // Add "hi" (if different from "lo") + if (hi != lo) { + dst->push_back(hi); + } +} + +Benchmark* Benchmark::Arg(int x) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + args_.push_back({x}); + return this; +} + +Benchmark* Benchmark::Unit(TimeUnit unit) { + time_unit_ = unit; + return this; +} + +Benchmark* Benchmark::Range(int start, int limit) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + std::vector arglist; + AddRange(&arglist, start, limit, range_multiplier_); + + for (int i : arglist) { + args_.push_back({i}); + } + return this; +} + +Benchmark* Benchmark::Ranges(const std::vector>& ranges) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(ranges.size())); + std::vector> arglists(ranges.size()); + std::size_t total = 1; + for (std::size_t i = 0; i < ranges.size(); i++) { + AddRange(&arglists[i], ranges[i].first, ranges[i].second, + range_multiplier_); + total *= arglists[i].size(); + } + + std::vector ctr(arglists.size(), 0); + + for (std::size_t i = 0; i < total; i++) { + std::vector tmp; + tmp.reserve(arglists.size()); + + for (std::size_t j = 0; j < arglists.size(); j++) { + tmp.push_back(arglists[j].at(ctr[j])); + } + + args_.push_back(std::move(tmp)); + + for (std::size_t j = 0; j < arglists.size(); j++) { + if (ctr[j] + 1 < arglists[j].size()) { + ++ctr[j]; + break; + } + ctr[j] = 0; + } + } + return this; +} + +Benchmark* Benchmark::ArgName(const std::string& name) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + arg_names_ = {name}; + return this; +} + +Benchmark* Benchmark::ArgNames(const std::vector& names) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(names.size())); + arg_names_ = names; + return this; +} + +Benchmark* Benchmark::DenseRange(int start, int limit, int step) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + CHECK_GE(start, 0); + CHECK_LE(start, limit); + for (int arg = start; arg <= limit; arg += step) { + args_.push_back({arg}); + } + return this; +} + +Benchmark* Benchmark::Args(const std::vector& args) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(args.size())); + args_.push_back(args); + return this; +} + +Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) { + custom_arguments(this); + return this; +} + +Benchmark* Benchmark::RangeMultiplier(int multiplier) { + CHECK(multiplier > 1); + range_multiplier_ = multiplier; + return this; +} + + +Benchmark* Benchmark::MinTime(double t) { + CHECK(t > 0.0); + CHECK(iterations_ == 0); + min_time_ = t; + return this; +} + + +Benchmark* Benchmark::Iterations(size_t n) { + CHECK(n > 0); + CHECK(IsZero(min_time_)); + iterations_ = n; + return this; +} + +Benchmark* Benchmark::Repetitions(int n) { + CHECK(n > 0); + repetitions_ = n; + return this; +} + +Benchmark* Benchmark::ReportAggregatesOnly(bool value) { + report_mode_ = value ? RM_ReportAggregatesOnly : RM_Default; + return this; +} + +Benchmark* Benchmark::UseRealTime() { + CHECK(!use_manual_time_) + << "Cannot set UseRealTime and UseManualTime simultaneously."; + use_real_time_ = true; + return this; +} + +Benchmark* Benchmark::UseManualTime() { + CHECK(!use_real_time_) + << "Cannot set UseRealTime and UseManualTime simultaneously."; + use_manual_time_ = true; + return this; +} + +Benchmark* Benchmark::Complexity(BigO complexity) { + complexity_ = complexity; + return this; +} + +Benchmark* Benchmark::Complexity(BigOFunc* complexity) { + complexity_lambda_ = complexity; + complexity_ = oLambda; + return this; +} + +Benchmark* Benchmark::Threads(int t) { + CHECK_GT(t, 0); + thread_counts_.push_back(t); + return this; +} + +Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) { + CHECK_GT(min_threads, 0); + CHECK_GE(max_threads, min_threads); + + AddRange(&thread_counts_, min_threads, max_threads, 2); + return this; +} + +Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads, + int stride) { + CHECK_GT(min_threads, 0); + CHECK_GE(max_threads, min_threads); + CHECK_GE(stride, 1); + + for (auto i = min_threads; i < max_threads; i += stride) { + thread_counts_.push_back(i); + } + thread_counts_.push_back(max_threads); + return this; +} + +Benchmark* Benchmark::ThreadPerCpu() { + static int num_cpus = NumCPUs(); + thread_counts_.push_back(num_cpus); + return this; +} + +void Benchmark::SetName(const char* name) { name_ = name; } + +int Benchmark::ArgsCnt() const { + if (args_.empty()) { + if (arg_names_.empty()) return -1; + return static_cast(arg_names_.size()); + } + return static_cast(args_.front().size()); +} + +//=============================================================================// +// FunctionBenchmark +//=============================================================================// + +void FunctionBenchmark::Run(State& st) { func_(st); } + +} // end namespace internal + +void ClearRegisteredBenchmarks() { + internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks(); +} + +} // end namespace benchmark diff --git a/src/check.h b/src/check.h new file mode 100644 index 0000000..73bead2 --- /dev/null +++ b/src/check.h @@ -0,0 +1,79 @@ +#ifndef CHECK_H_ +#define CHECK_H_ + +#include +#include +#include + +#include "internal_macros.h" +#include "log.h" + +namespace benchmark { +namespace internal { + +typedef void(AbortHandlerT)(); + +inline AbortHandlerT*& GetAbortHandler() { + static AbortHandlerT* handler = &std::abort; + return handler; +} + +BENCHMARK_NORETURN inline void CallAbortHandler() { + GetAbortHandler()(); + std::abort(); // fallback to enforce noreturn +} + +// CheckHandler is the class constructed by failing CHECK macros. CheckHandler +// will log information about the failures and abort when it is destructed. +class CheckHandler { + public: + CheckHandler(const char* check, const char* file, const char* func, int line) + : log_(GetErrorLogInstance()) { + log_ << file << ":" << line << ": " << func << ": Check `" << check + << "' failed. "; + } + + LogType& GetLog() { return log_; } + + BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) { + log_ << std::endl; + CallAbortHandler(); + } + + CheckHandler& operator=(const CheckHandler&) = delete; + CheckHandler(const CheckHandler&) = delete; + CheckHandler() = delete; + + private: + LogType& log_; +}; + +} // end namespace internal +} // end namespace benchmark + +// The CHECK macro returns a std::ostream object that can have extra information +// written to it. +#ifndef NDEBUG +#define CHECK(b) \ + (b ? ::benchmark::internal::GetNullLogInstance() \ + : ::benchmark::internal::CheckHandler(#b, __FILE__, __func__, __LINE__) \ + .GetLog()) +#else +#define CHECK(b) ::benchmark::internal::GetNullLogInstance() +#endif + +#define CHECK_EQ(a, b) CHECK((a) == (b)) +#define CHECK_NE(a, b) CHECK((a) != (b)) +#define CHECK_GE(a, b) CHECK((a) >= (b)) +#define CHECK_LE(a, b) CHECK((a) <= (b)) +#define CHECK_GT(a, b) CHECK((a) > (b)) +#define CHECK_LT(a, b) CHECK((a) < (b)) + +#define CHECK_FLOAT_EQ(a, b, eps) CHECK(std::fabs((a) - (b)) < (eps)) +#define CHECK_FLOAT_NE(a, b, eps) CHECK(std::fabs((a) - (b)) >= (eps)) +#define CHECK_FLOAT_GE(a, b, eps) CHECK((a) - (b) > -(eps)) +#define CHECK_FLOAT_LE(a, b, eps) CHECK((b) - (a) > -(eps)) +#define CHECK_FLOAT_GT(a, b, eps) CHECK((a) - (b) > (eps)) +#define CHECK_FLOAT_LT(a, b, eps) CHECK((b) - (a) > (eps)) + +#endif // CHECK_H_ diff --git a/src/colorprint.cc b/src/colorprint.cc new file mode 100644 index 0000000..2dec4a8 --- /dev/null +++ b/src/colorprint.cc @@ -0,0 +1,188 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "colorprint.h" + +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#include +#else +#include +#endif // BENCHMARK_OS_WINDOWS + +namespace benchmark { +namespace { +#ifdef BENCHMARK_OS_WINDOWS +typedef WORD PlatformColorCode; +#else +typedef const char* PlatformColorCode; +#endif + +PlatformColorCode GetPlatformColorCode(LogColor color) { +#ifdef BENCHMARK_OS_WINDOWS + switch (color) { + case COLOR_RED: + return FOREGROUND_RED; + case COLOR_GREEN: + return FOREGROUND_GREEN; + case COLOR_YELLOW: + return FOREGROUND_RED | FOREGROUND_GREEN; + case COLOR_BLUE: + return FOREGROUND_BLUE; + case COLOR_MAGENTA: + return FOREGROUND_BLUE | FOREGROUND_RED; + case COLOR_CYAN: + return FOREGROUND_BLUE | FOREGROUND_GREEN; + case COLOR_WHITE: // fall through to default + default: + return 0; + } +#else + switch (color) { + case COLOR_RED: + return "1"; + case COLOR_GREEN: + return "2"; + case COLOR_YELLOW: + return "3"; + case COLOR_BLUE: + return "4"; + case COLOR_MAGENTA: + return "5"; + case COLOR_CYAN: + return "6"; + case COLOR_WHITE: + return "7"; + default: + return nullptr; + }; +#endif +} + +} // end namespace + +std::string FormatString(const char* msg, va_list args) { + // we might need a second shot at this, so pre-emptivly make a copy + va_list args_cp; + va_copy(args_cp, args); + + std::size_t size = 256; + char local_buff[256]; + auto ret = vsnprintf(local_buff, size, msg, args_cp); + + va_end(args_cp); + + // currently there is no error handling for failure, so this is hack. + CHECK(ret >= 0); + + if (ret == 0) // handle empty expansion + return {}; + else if (static_cast(ret) < size) + return local_buff; + else { + // we did not provide a long enough buffer on our first attempt. + size = (size_t)ret + 1; // + 1 for the null byte + std::unique_ptr buff(new char[size]); + ret = vsnprintf(buff.get(), size, msg, args); + CHECK(ret > 0 && ((size_t)ret) < size); + return buff.get(); + } +} + +std::string FormatString(const char* msg, ...) { + va_list args; + va_start(args, msg); + auto tmp = FormatString(msg, args); + va_end(args); + return tmp; +} + +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + ColorPrintf(out, color, fmt, args); + va_end(args); +} + +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, + va_list args) { +#ifdef BENCHMARK_OS_WINDOWS + ((void)out); // suppress unused warning + + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetPlatformColorCode(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + const char* color_code = GetPlatformColorCode(color); + if (color_code) out << FormatString("\033[0;3%sm", color_code); + out << FormatString(fmt, args) << "\033[m"; +#endif +} + +bool IsColorTerminal() { +#if BENCHMARK_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return 0 != _isatty(_fileno(stdout)); +#else + // On non-Windows platforms, we rely on the TERM variable. This list of + // supported TERM values is copied from Google Test: + // . + const char* const SUPPORTED_TERM_VALUES[] = { + "xterm", "xterm-color", "xterm-256color", + "screen", "screen-256color", "tmux", + "tmux-256color", "rxvt-unicode", "rxvt-unicode-256color", + "linux", "cygwin", + }; + + const char* const term = getenv("TERM"); + + bool term_supports_color = false; + for (const char* candidate : SUPPORTED_TERM_VALUES) { + if (term && 0 == strcmp(term, candidate)) { + term_supports_color = true; + break; + } + } + + return 0 != isatty(fileno(stdout)) && term_supports_color; +#endif // BENCHMARK_OS_WINDOWS +} + +} // end namespace benchmark diff --git a/src/colorprint.h b/src/colorprint.h new file mode 100644 index 0000000..9f6fab9 --- /dev/null +++ b/src/colorprint.h @@ -0,0 +1,33 @@ +#ifndef BENCHMARK_COLORPRINT_H_ +#define BENCHMARK_COLORPRINT_H_ + +#include +#include +#include + +namespace benchmark { +enum LogColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE +}; + +std::string FormatString(const char* msg, va_list args); +std::string FormatString(const char* msg, ...); + +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, + va_list args); +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...); + +// Returns true if stdout appears to be a terminal that supports colored +// output, false otherwise. +bool IsColorTerminal(); + +} // end namespace benchmark + +#endif // BENCHMARK_COLORPRINT_H_ diff --git a/src/commandlineflags.cc b/src/commandlineflags.cc new file mode 100644 index 0000000..2fc9251 --- /dev/null +++ b/src/commandlineflags.cc @@ -0,0 +1,218 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "commandlineflags.h" + +#include +#include +#include +#include +#include + +namespace benchmark { +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { + // Parses the environment variable as a decimal integer. + char* end = nullptr; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + std::cerr << src_text << " is expected to be a 32-bit integer, " + << "but actually has value \"" << str << "\".\n"; + return false; + } + + // Is the parsed value in the range of an Int32? + const int32_t result = static_cast(long_value); + if (long_value == std::numeric_limits::max() || + long_value == std::numeric_limits::min() || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + std::cerr << src_text << " is expected to be a 32-bit integer, " + << "but actually has value \"" << str << "\", " + << "which overflows.\n"; + return false; + } + + *value = result; + return true; +} + +// Parses 'str' for a double. If successful, writes the result to *value and +// returns true; otherwise leaves *value unchanged and returns false. +bool ParseDouble(const std::string& src_text, const char* str, double* value) { + // Parses the environment variable as a decimal integer. + char* end = nullptr; + const double double_value = strtod(str, &end); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + std::cerr << src_text << " is expected to be a double, " + << "but actually has value \"" << str << "\".\n"; + return false; + } + + *value = double_value; + return true; +} + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "BENCHMARK_FOO" in the open-source version. +static std::string FlagToEnvVar(const char* flag) { + const std::string flag_str(flag); + + std::string env_var; + for (size_t i = 0; i != flag_str.length(); ++i) + env_var += static_cast(::toupper(flag_str.c_str()[i])); + + return "BENCHMARK_" + env_var; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromEnv(const char* flag, bool default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = getenv(env_var.c_str()); + return string_value == nullptr ? default_value + : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +int32_t Int32FromEnv(const char* flag, int32_t default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = getenv(env_var.c_str()); + if (string_value == nullptr) { + // The environment variable is not set. + return default_value; + } + + int32_t result = default_value; + if (!ParseInt32(std::string("Environment variable ") + env_var, string_value, + &result)) { + std::cout << "The default value " << default_value << " is used.\n"; + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromEnv(const char* flag, const char* default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value = getenv(env_var.c_str()); + return value == nullptr ? default_value : value; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or nullptr if the parsing failed. +const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { + // str and flag must not be nullptr. + if (str == nullptr || flag == nullptr) return nullptr; + + // The flag must start with "--". + const std::string flag_str = std::string("--") + std::string(flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) return flag_end; + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return nullptr; + + // Returns the string after "=". + return flag_end + 1; +} + +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Converts the string value to a bool. + *value = IsTruthyFlagValue(value_str); + return true; +} + +bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Sets *value to the value of the flag. + return ParseInt32(std::string("The value of flag --") + flag, value_str, + value); +} + +bool ParseDoubleFlag(const char* str, const char* flag, double* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Sets *value to the value of the flag. + return ParseDouble(std::string("The value of flag --") + flag, value_str, + value); +} + +bool ParseStringFlag(const char* str, const char* flag, std::string* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + *value = value_str; + return true; +} + +bool IsFlag(const char* str, const char* flag) { + return (ParseFlagValue(str, flag, true) != nullptr); +} + +bool IsTruthyFlagValue(const std::string& value) { + if (value.empty()) return true; + char ch = value[0]; + return isalnum(ch) && + !(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N'); +} +} // end namespace benchmark diff --git a/src/commandlineflags.h b/src/commandlineflags.h new file mode 100644 index 0000000..945c9a9 --- /dev/null +++ b/src/commandlineflags.h @@ -0,0 +1,79 @@ +#ifndef BENCHMARK_COMMANDLINEFLAGS_H_ +#define BENCHMARK_COMMANDLINEFLAGS_H_ + +#include +#include + +// Macro for referencing flags. +#define FLAG(name) FLAGS_##name + +// Macros for declaring flags. +#define DECLARE_bool(name) extern bool FLAG(name) +#define DECLARE_int32(name) extern int32_t FLAG(name) +#define DECLARE_int64(name) extern int64_t FLAG(name) +#define DECLARE_double(name) extern double FLAG(name) +#define DECLARE_string(name) extern std::string FLAG(name) + +// Macros for defining flags. +#define DEFINE_bool(name, default_val, doc) bool FLAG(name) = (default_val) +#define DEFINE_int32(name, default_val, doc) int32_t FLAG(name) = (default_val) +#define DEFINE_int64(name, default_val, doc) int64_t FLAG(name) = (default_val) +#define DEFINE_double(name, default_val, doc) double FLAG(name) = (default_val) +#define DEFINE_string(name, default_val, doc) \ + std::string FLAG(name) = (default_val) + +namespace benchmark { +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +bool ParseInt32(const std::string& src_text, const char* str, int32_t* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromEnv(const char* flag, bool default_val); +int32_t Int32FromEnv(const char* flag, int32_t default_val); +double DoubleFromEnv(const char* flag, double default_val); +const char* StringFromEnv(const char* flag, const char* default_val); + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true if it passes IsTruthyValue(). +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value); + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, int32_t* value); + +// Parses a string for a Double flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseDoubleFlag(const char* str, const char* flag, double* value); + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, std::string* value); + +// Returns true if the string matches the flag. +bool IsFlag(const char* str, const char* flag); + +// Returns true unless value starts with one of: '0', 'f', 'F', 'n' or 'N', or +// some non-alphanumeric character. As a special case, also returns true if +// value is the empty string. +bool IsTruthyFlagValue(const std::string& value); +} // end namespace benchmark + +#endif // BENCHMARK_COMMANDLINEFLAGS_H_ diff --git a/src/complexity.cc b/src/complexity.cc new file mode 100644 index 0000000..33975be --- /dev/null +++ b/src/complexity.cc @@ -0,0 +1,324 @@ +// Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Source project : https://github.com/ismaelJimenez/cpp.leastsq +// Adapted to be used with google benchmark + +#include "benchmark/benchmark.h" + +#include +#include +#include "check.h" +#include "complexity.h" +#include "stat.h" + +namespace benchmark { + +// Internal function to calculate the different scalability forms +BigOFunc* FittingCurve(BigO complexity) { + switch (complexity) { + case oN: + return [](int n) -> double { return n; }; + case oNSquared: + return [](int n) -> double { return std::pow(n, 2); }; + case oNCubed: + return [](int n) -> double { return std::pow(n, 3); }; + case oLogN: + return [](int n) { return log2(n); }; + case oNLogN: + return [](int n) { return n * log2(n); }; + case o1: + default: + return [](int) { return 1.0; }; + } +} + +// Function to return an string for the calculated complexity +std::string GetBigOString(BigO complexity) { + switch (complexity) { + case oN: + return "N"; + case oNSquared: + return "N^2"; + case oNCubed: + return "N^3"; + case oLogN: + return "lgN"; + case oNLogN: + return "NlgN"; + case o1: + return "(1)"; + default: + return "f(N)"; + } +} + +// Find the coefficient for the high-order term in the running time, by +// minimizing the sum of squares of relative error, for the fitting curve +// given by the lambda expresion. +// - n : Vector containing the size of the benchmark tests. +// - time : Vector containing the times for the benchmark tests. +// - fitting_curve : lambda expresion (e.g. [](int n) {return n; };). + +// For a deeper explanation on the algorithm logic, look the README file at +// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit + +LeastSq MinimalLeastSq(const std::vector& n, + const std::vector& time, + BigOFunc* fitting_curve) { + double sigma_gn = 0.0; + double sigma_gn_squared = 0.0; + double sigma_time = 0.0; + double sigma_time_gn = 0.0; + + // Calculate least square fitting parameter + for (size_t i = 0; i < n.size(); ++i) { + double gn_i = fitting_curve(n[i]); + sigma_gn += gn_i; + sigma_gn_squared += gn_i * gn_i; + sigma_time += time[i]; + sigma_time_gn += time[i] * gn_i; + } + + LeastSq result; + result.complexity = oLambda; + + // Calculate complexity. + result.coef = sigma_time_gn / sigma_gn_squared; + + // Calculate RMS + double rms = 0.0; + for (size_t i = 0; i < n.size(); ++i) { + double fit = result.coef * fitting_curve(n[i]); + rms += pow((time[i] - fit), 2); + } + + // Normalized RMS by the mean of the observed values + double mean = sigma_time / n.size(); + result.rms = sqrt(rms / n.size()) / mean; + + return result; +} + +// Find the coefficient for the high-order term in the running time, by +// minimizing the sum of squares of relative error. +// - n : Vector containing the size of the benchmark tests. +// - time : Vector containing the times for the benchmark tests. +// - complexity : If different than oAuto, the fitting curve will stick to +// this one. If it is oAuto, it will be calculated the best +// fitting curve. +LeastSq MinimalLeastSq(const std::vector& n, + const std::vector& time, const BigO complexity) { + CHECK_EQ(n.size(), time.size()); + CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two + // benchmark runs are given + CHECK_NE(complexity, oNone); + + LeastSq best_fit; + + if (complexity == oAuto) { + std::vector fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed}; + + // Take o1 as default best fitting curve + best_fit = MinimalLeastSq(n, time, FittingCurve(o1)); + best_fit.complexity = o1; + + // Compute all possible fitting curves and stick to the best one + for (const auto& fit : fit_curves) { + LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit)); + if (current_fit.rms < best_fit.rms) { + best_fit = current_fit; + best_fit.complexity = fit; + } + } + } else { + best_fit = MinimalLeastSq(n, time, FittingCurve(complexity)); + best_fit.complexity = complexity; + } + + return best_fit; +} + +std::vector ComputeStats( + const std::vector& reports) { + typedef BenchmarkReporter::Run Run; + std::vector results; + + auto error_count = + std::count_if(reports.begin(), reports.end(), + [](Run const& run) { return run.error_occurred; }); + + if (reports.size() - error_count < 2) { + // We don't report aggregated data if there was a single run. + return results; + } + // Accumulators. + Stat1_d real_accumulated_time_stat; + Stat1_d cpu_accumulated_time_stat; + Stat1_d bytes_per_second_stat; + Stat1_d items_per_second_stat; + // All repetitions should be run with the same number of iterations so we + // can take this information from the first benchmark. + int64_t const run_iterations = reports.front().iterations; + // create stats for user counters + struct CounterStat { + Counter c; + Stat1_d s; + }; + std::map< std::string, CounterStat > counter_stats; + for(Run const& r : reports) { + for(auto const& cnt : r.counters) { + auto it = counter_stats.find(cnt.first); + if(it == counter_stats.end()) { + counter_stats.insert({cnt.first, {cnt.second, Stat1_d{}}}); + } else { + CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags); + } + } + } + + // Populate the accumulators. + for (Run const& run : reports) { + CHECK_EQ(reports[0].benchmark_name, run.benchmark_name); + CHECK_EQ(run_iterations, run.iterations); + if (run.error_occurred) continue; + real_accumulated_time_stat += + Stat1_d(run.real_accumulated_time / run.iterations); + cpu_accumulated_time_stat += + Stat1_d(run.cpu_accumulated_time / run.iterations); + items_per_second_stat += Stat1_d(run.items_per_second); + bytes_per_second_stat += Stat1_d(run.bytes_per_second); + // user counters + for(auto const& cnt : run.counters) { + auto it = counter_stats.find(cnt.first); + CHECK_NE(it, counter_stats.end()); + it->second.s += Stat1_d(cnt.second); + } + } + + // Get the data from the accumulator to BenchmarkReporter::Run's. + Run mean_data; + mean_data.benchmark_name = reports[0].benchmark_name + "_mean"; + mean_data.iterations = run_iterations; + mean_data.real_accumulated_time = + real_accumulated_time_stat.Mean() * run_iterations; + mean_data.cpu_accumulated_time = + cpu_accumulated_time_stat.Mean() * run_iterations; + mean_data.bytes_per_second = bytes_per_second_stat.Mean(); + mean_data.items_per_second = items_per_second_stat.Mean(); + mean_data.time_unit = reports[0].time_unit; + // user counters + for(auto const& kv : counter_stats) { + auto c = Counter(kv.second.s.Mean(), counter_stats[kv.first].c.flags); + mean_data.counters[kv.first] = c; + } + + // Only add label to mean/stddev if it is same for all runs + mean_data.report_label = reports[0].report_label; + for (std::size_t i = 1; i < reports.size(); i++) { + if (reports[i].report_label != reports[0].report_label) { + mean_data.report_label = ""; + break; + } + } + + Run stddev_data; + stddev_data.benchmark_name = reports[0].benchmark_name + "_stddev"; + stddev_data.report_label = mean_data.report_label; + stddev_data.iterations = 0; + stddev_data.real_accumulated_time = real_accumulated_time_stat.StdDev(); + stddev_data.cpu_accumulated_time = cpu_accumulated_time_stat.StdDev(); + stddev_data.bytes_per_second = bytes_per_second_stat.StdDev(); + stddev_data.items_per_second = items_per_second_stat.StdDev(); + stddev_data.time_unit = reports[0].time_unit; + // user counters + for(auto const& kv : counter_stats) { + auto c = Counter(kv.second.s.StdDev(), counter_stats[kv.first].c.flags); + stddev_data.counters[kv.first] = c; + } + + results.push_back(mean_data); + results.push_back(stddev_data); + return results; +} + +std::vector ComputeBigO( + const std::vector& reports) { + typedef BenchmarkReporter::Run Run; + std::vector results; + + if (reports.size() < 2) return results; + + // Accumulators. + std::vector n; + std::vector real_time; + std::vector cpu_time; + + // Populate the accumulators. + for (const Run& run : reports) { + CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?"; + n.push_back(run.complexity_n); + real_time.push_back(run.real_accumulated_time / run.iterations); + cpu_time.push_back(run.cpu_accumulated_time / run.iterations); + } + + LeastSq result_cpu; + LeastSq result_real; + + if (reports[0].complexity == oLambda) { + result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda); + result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda); + } else { + result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity); + result_real = MinimalLeastSq(n, real_time, result_cpu.complexity); + } + std::string benchmark_name = + reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/')); + + // Get the data from the accumulator to BenchmarkReporter::Run's. + Run big_o; + big_o.benchmark_name = benchmark_name + "_BigO"; + big_o.iterations = 0; + big_o.real_accumulated_time = result_real.coef; + big_o.cpu_accumulated_time = result_cpu.coef; + big_o.report_big_o = true; + big_o.complexity = result_cpu.complexity; + + // All the time results are reported after being multiplied by the + // time unit multiplier. But since RMS is a relative quantity it + // should not be multiplied at all. So, here, we _divide_ it by the + // multiplier so that when it is multiplied later the result is the + // correct one. + double multiplier = GetTimeUnitMultiplier(reports[0].time_unit); + + // Only add label to mean/stddev if it is same for all runs + Run rms; + big_o.report_label = reports[0].report_label; + rms.benchmark_name = benchmark_name + "_RMS"; + rms.report_label = big_o.report_label; + rms.iterations = 0; + rms.real_accumulated_time = result_real.rms / multiplier; + rms.cpu_accumulated_time = result_cpu.rms / multiplier; + rms.report_rms = true; + rms.complexity = result_cpu.complexity; + // don't forget to keep the time unit, or we won't be able to + // recover the correct value. + rms.time_unit = reports[0].time_unit; + + results.push_back(big_o); + results.push_back(rms); + return results; +} + +} // end namespace benchmark diff --git a/src/complexity.h b/src/complexity.h new file mode 100644 index 0000000..c0ca60e --- /dev/null +++ b/src/complexity.h @@ -0,0 +1,60 @@ +// Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Source project : https://github.com/ismaelJimenez/cpp.leastsq +// Adapted to be used with google benchmark + +#ifndef COMPLEXITY_H_ +#define COMPLEXITY_H_ + +#include +#include + +#include "benchmark/benchmark.h" + +namespace benchmark { + +// Return a vector containing the mean and standard devation information for +// the specified list of reports. If 'reports' contains less than two +// non-errored runs an empty vector is returned +std::vector ComputeStats( + const std::vector& reports); + +// Return a vector containing the bigO and RMS information for the specified +// list of reports. If 'reports.size() < 2' an empty vector is returned. +std::vector ComputeBigO( + const std::vector& reports); + +// This data structure will contain the result returned by MinimalLeastSq +// - coef : Estimated coeficient for the high-order term as +// interpolated from data. +// - rms : Normalized Root Mean Squared Error. +// - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability +// form has been provided to MinimalLeastSq this will return +// the same value. In case BigO::oAuto has been selected, this +// parameter will return the best fitting curve detected. + +struct LeastSq { + LeastSq() : coef(0.0), rms(0.0), complexity(oNone) {} + + double coef; + double rms; + BigO complexity; +}; + +// Function to return an string for the calculated complexity +std::string GetBigOString(BigO complexity); + +} // end namespace benchmark +#endif // COMPLEXITY_H_ diff --git a/src/console_reporter.cc b/src/console_reporter.cc new file mode 100644 index 0000000..4bb6f71 --- /dev/null +++ b/src/console_reporter.cc @@ -0,0 +1,180 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "complexity.h" +#include "counter.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "colorprint.h" +#include "commandlineflags.h" +#include "internal_macros.h" +#include "string_util.h" +#include "timers.h" + +namespace benchmark { + +bool ConsoleReporter::ReportContext(const Context& context) { + name_field_width_ = context.name_field_width; + printed_header_ = false; + prev_counters_.clear(); + + PrintBasicContext(&GetErrorStream(), context); + +#ifdef BENCHMARK_OS_WINDOWS + if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) { + GetErrorStream() + << "Color printing is only supported for stdout on windows." + " Disabling color printing\n"; + output_options_ = static_cast< OutputOptions >(output_options_ & ~OO_Color); + } +#endif + + return true; +} + +void ConsoleReporter::PrintHeader(const Run& run) { + std::string str = FormatString("%-*s %13s %13s %10s", static_cast(name_field_width_), + "Benchmark", "Time", "CPU", "Iterations"); + if(!run.counters.empty()) { + if(output_options_ & OO_Tabular) { + for(auto const& c : run.counters) { + str += FormatString(" %10s", c.first.c_str()); + } + } else { + str += " UserCounters..."; + } + } + str += "\n"; + std::string line = std::string(str.length(), '-'); + GetOutputStream() << line << "\n" << str << line << "\n"; +} + +void ConsoleReporter::ReportRuns(const std::vector& reports) { + for (const auto& run : reports) { + // print the header: + // --- if none was printed yet + bool print_header = !printed_header_; + // --- or if the format is tabular and this run + // has different fields from the prev header + print_header |= (output_options_ & OO_Tabular) && + (!internal::SameNames(run.counters, prev_counters_)); + if (print_header) { + printed_header_ = true; + prev_counters_ = run.counters; + PrintHeader(run); + } + // As an alternative to printing the headers like this, we could sort + // the benchmarks by header and then print. But this would require + // waiting for the full results before printing, or printing twice. + PrintRunData(run); + } +} + +static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt, + ...) { + va_list args; + va_start(args, fmt); + out << FormatString(fmt, args); + va_end(args); +} + +void ConsoleReporter::PrintRunData(const Run& result) { + typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...); + auto& Out = GetOutputStream(); + PrinterFn* printer = (output_options_ & OO_Color) ? + (PrinterFn*)ColorPrintf : IgnoreColorPrint; + auto name_color = + (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN; + printer(Out, name_color, "%-*s ", name_field_width_, + result.benchmark_name.c_str()); + + if (result.error_occurred) { + printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'", + result.error_message.c_str()); + printer(Out, COLOR_DEFAULT, "\n"); + return; + } + // Format bytes per second + std::string rate; + if (result.bytes_per_second > 0) { + rate = StrCat(" ", HumanReadableNumber(result.bytes_per_second), "B/s"); + } + + // Format items per second + std::string items; + if (result.items_per_second > 0) { + items = + StrCat(" ", HumanReadableNumber(result.items_per_second), " items/s"); + } + + const double real_time = result.GetAdjustedRealTime(); + const double cpu_time = result.GetAdjustedCPUTime(); + + if (result.report_big_o) { + std::string big_o = GetBigOString(result.complexity); + printer(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time, big_o.c_str(), + cpu_time, big_o.c_str()); + } else if (result.report_rms) { + printer(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100, + cpu_time * 100); + } else { + const char* timeLabel = GetTimeUnitString(result.time_unit); + printer(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel, + cpu_time, timeLabel); + } + + if (!result.report_big_o && !result.report_rms) { + printer(Out, COLOR_CYAN, "%10lld", result.iterations); + } + + for (auto& c : result.counters) { + auto const& s = HumanReadableNumber(c.second.value); + if (output_options_ & OO_Tabular) { + if (c.second.flags & Counter::kIsRate) { + printer(Out, COLOR_DEFAULT, " %8s/s", s.c_str()); + } else { + printer(Out, COLOR_DEFAULT, " %10s", s.c_str()); + } + } else { + const char* unit = (c.second.flags & Counter::kIsRate) ? "/s" : ""; + printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(), + unit); + } + } + + if (!rate.empty()) { + printer(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str()); + } + + if (!items.empty()) { + printer(Out, COLOR_DEFAULT, " %*s", 18, items.c_str()); + } + + if (!result.report_label.empty()) { + printer(Out, COLOR_DEFAULT, " %s", result.report_label.c_str()); + } + + printer(Out, COLOR_DEFAULT, "\n"); +} + +} // end namespace benchmark diff --git a/src/counter.cc b/src/counter.cc new file mode 100644 index 0000000..ed1aa04 --- /dev/null +++ b/src/counter.cc @@ -0,0 +1,68 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "counter.h" + +namespace benchmark { +namespace internal { + +double Finish(Counter const& c, double cpu_time, double num_threads) { + double v = c.value; + if (c.flags & Counter::kIsRate) { + v /= cpu_time; + } + if (c.flags & Counter::kAvgThreads) { + v /= num_threads; + } + return v; +} + +void Finish(UserCounters *l, double cpu_time, double num_threads) { + for (auto &c : *l) { + c.second.value = Finish(c.second, cpu_time, num_threads); + } +} + +void Increment(UserCounters *l, UserCounters const& r) { + // add counters present in both or just in *l + for (auto &c : *l) { + auto it = r.find(c.first); + if (it != r.end()) { + c.second.value = c.second + it->second; + } + } + // add counters present in r, but not in *l + for (auto const &tc : r) { + auto it = l->find(tc.first); + if (it == l->end()) { + (*l)[tc.first] = tc.second; + } + } +} + +bool SameNames(UserCounters const& l, UserCounters const& r) { + if (&l == &r) return true; + if (l.size() != r.size()) { + return false; + } + for (auto const& c : l) { + if (r.find(c.first) == r.end()) { + return false; + } + } + return true; +} + +} // end namespace internal +} // end namespace benchmark diff --git a/src/counter.h b/src/counter.h new file mode 100644 index 0000000..dd6865a --- /dev/null +++ b/src/counter.h @@ -0,0 +1,26 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" + +namespace benchmark { + +// these counter-related functions are hidden to reduce API surface. +namespace internal { +void Finish(UserCounters *l, double time, double num_threads); +void Increment(UserCounters *l, UserCounters const& r); +bool SameNames(UserCounters const& l, UserCounters const& r); +} // end namespace internal + +} //end namespace benchmark diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc new file mode 100644 index 0000000..3551064 --- /dev/null +++ b/src/csv_reporter.cc @@ -0,0 +1,149 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "complexity.h" + +#include +#include +#include +#include +#include +#include + +#include "string_util.h" +#include "timers.h" +#include "check.h" + +// File format reference: http://edoceo.com/utilitas/csv-file-format. + +namespace benchmark { + +namespace { +std::vector elements = { + "name", "iterations", "real_time", "cpu_time", + "time_unit", "bytes_per_second", "items_per_second", "label", + "error_occurred", "error_message"}; +} // namespace + +bool CSVReporter::ReportContext(const Context& context) { + PrintBasicContext(&GetErrorStream(), context); + return true; +} + +void CSVReporter::ReportRuns(const std::vector & reports) { + std::ostream& Out = GetOutputStream(); + + if (!printed_header_) { + // save the names of all the user counters + for (const auto& run : reports) { + for (const auto& cnt : run.counters) { + user_counter_names_.insert(cnt.first); + } + } + + // print the header + for (auto B = elements.begin(); B != elements.end();) { + Out << *B++; + if (B != elements.end()) Out << ","; + } + for (auto B = user_counter_names_.begin(); B != user_counter_names_.end();) { + Out << ",\"" << *B++ << "\""; + } + Out << "\n"; + + printed_header_ = true; + } else { + // check that all the current counters are saved in the name set + for (const auto& run : reports) { + for (const auto& cnt : run.counters) { + CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end()) + << "All counters must be present in each run. " + << "Counter named \"" << cnt.first + << "\" was not in a run after being added to the header"; + } + } + } + + // print results for each run + for (const auto& run : reports) { + PrintRunData(run); + } + +} + +void CSVReporter::PrintRunData(const Run & run) { + std::ostream& Out = GetOutputStream(); + + // Field with embedded double-quote characters must be doubled and the field + // delimited with double-quotes. + std::string name = run.benchmark_name; + ReplaceAll(&name, "\"", "\"\""); + Out << '"' << name << "\","; + if (run.error_occurred) { + Out << std::string(elements.size() - 3, ','); + Out << "true,"; + std::string msg = run.error_message; + ReplaceAll(&msg, "\"", "\"\""); + Out << '"' << msg << "\"\n"; + return; + } + + // Do not print iteration on bigO and RMS report + if (!run.report_big_o && !run.report_rms) { + Out << run.iterations; + } + Out << ","; + + Out << run.GetAdjustedRealTime() << ","; + Out << run.GetAdjustedCPUTime() << ","; + + // Do not print timeLabel on bigO and RMS report + if (run.report_big_o) { + Out << GetBigOString(run.complexity); + } else if (!run.report_rms) { + Out << GetTimeUnitString(run.time_unit); + } + Out << ","; + + if (run.bytes_per_second > 0.0) { + Out << run.bytes_per_second; + } + Out << ","; + if (run.items_per_second > 0.0) { + Out << run.items_per_second; + } + Out << ","; + if (!run.report_label.empty()) { + // Field with embedded double-quote characters must be doubled and the field + // delimited with double-quotes. + std::string label = run.report_label; + ReplaceAll(&label, "\"", "\"\""); + Out << "\"" << label << "\""; + } + Out << ",,"; // for error_occurred and error_message + + // Print user counters + for (const auto &ucn : user_counter_names_) { + auto it = run.counters.find(ucn); + if(it == run.counters.end()) { + Out << ","; + } else { + Out << "," << it->second; + } + } + Out << '\n'; +} + +} // end namespace benchmark diff --git a/src/cycleclock.h b/src/cycleclock.h new file mode 100644 index 0000000..4251fe4 --- /dev/null +++ b/src/cycleclock.h @@ -0,0 +1,172 @@ +// ---------------------------------------------------------------------- +// CycleClock +// A CycleClock tells you the current time in Cycles. The "time" +// is actually time since power-on. This is like time() but doesn't +// involve a system call and is much more precise. +// +// NOTE: Not all cpu/platform/kernel combinations guarantee that this +// clock increments at a constant rate or is synchronized across all logical +// cpus in a system. +// +// If you need the above guarantees, please consider using a different +// API. There are efforts to provide an interface which provides a millisecond +// granularity and implemented as a memory read. A memory read is generally +// cheaper than the CycleClock for many architectures. +// +// Also, in some out of order CPU implementations, the CycleClock is not +// serializing. So if you're trying to count at cycles granularity, your +// data might be inaccurate due to out of order instruction execution. +// ---------------------------------------------------------------------- + +#ifndef BENCHMARK_CYCLECLOCK_H_ +#define BENCHMARK_CYCLECLOCK_H_ + +#include + +#include "benchmark/benchmark.h" +#include "internal_macros.h" + +#if defined(BENCHMARK_OS_MACOSX) +#include +#endif +// For MSVC, we want to use '_asm rdtsc' when possible (since it works +// with even ancient MSVC compilers), and when not possible the +// __rdtsc intrinsic, declared in . Unfortunately, in some +// environments, and have conflicting +// declarations of some other intrinsics, breaking compilation. +// Therefore, we simply declare __rdtsc ourselves. See also +// http://connect.microsoft.com/VisualStudio/feedback/details/262047 +#if defined(COMPILER_MSVC) && !defined(_M_IX86) +extern "C" uint64_t __rdtsc(); +#pragma intrinsic(__rdtsc) +#endif + +#ifndef BENCHMARK_OS_WINDOWS +#include +#include +#endif + +#ifdef BENCHMARK_OS_EMSCRIPTEN +#include +#endif + +namespace benchmark { +// NOTE: only i386 and x86_64 have been well tested. +// PPC, sparc, alpha, and ia64 are based on +// http://peter.kuscsik.com/wordpress/?p=14 +// with modifications by m3b. See also +// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h +namespace cycleclock { +// This should return the number of cycles since power-on. Thread-safe. +inline BENCHMARK_ALWAYS_INLINE int64_t Now() { +#if defined(BENCHMARK_OS_MACOSX) + // this goes at the top because we need ALL Macs, regardless of + // architecture, to return the number of "mach time units" that + // have passed since startup. See sysinfo.cc where + // InitializeSystemInfo() sets the supposed cpu clock frequency of + // macs to the number of mach time units per second, not actual + // CPU clock frequency (which can change in the face of CPU + // frequency scaling). Also note that when the Mac sleeps, this + // counter pauses; it does not continue counting, nor does it + // reset to zero. + return mach_absolute_time(); +#elif defined(BENCHMARK_OS_EMSCRIPTEN) + // this goes above x86-specific code because old versions of Emscripten + // define __x86_64__, although they have nothing to do with it. + return static_cast(emscripten_get_now() * 1e+6); +#elif defined(__i386__) + int64_t ret; + __asm__ volatile("rdtsc" : "=A"(ret)); + return ret; +#elif defined(__x86_64__) || defined(__amd64__) + uint64_t low, high; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + return (high << 32) | low; +#elif defined(__powerpc__) || defined(__ppc__) + // This returns a time-base, which is not always precisely a cycle-count. + int64_t tbl, tbu0, tbu1; + asm("mftbu %0" : "=r"(tbu0)); + asm("mftb %0" : "=r"(tbl)); + asm("mftbu %0" : "=r"(tbu1)); + tbl &= -static_cast(tbu0 == tbu1); + // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage) + return (tbu1 << 32) | tbl; +#elif defined(__sparc__) + int64_t tick; + asm(".byte 0x83, 0x41, 0x00, 0x00"); + asm("mov %%g1, %0" : "=r"(tick)); + return tick; +#elif defined(__ia64__) + int64_t itc; + asm("mov %0 = ar.itc" : "=r"(itc)); + return itc; +#elif defined(COMPILER_MSVC) && defined(_M_IX86) + // Older MSVC compilers (like 7.x) don't seem to support the + // __rdtsc intrinsic properly, so I prefer to use _asm instead + // when I know it will work. Otherwise, I'll use __rdtsc and hope + // the code is being compiled with a non-ancient compiler. + _asm rdtsc +#elif defined(COMPILER_MSVC) + return __rdtsc(); +#elif defined(BENCHMARK_OS_NACL) + // Native Client validator on x86/x86-64 allows RDTSC instructions, + // and this case is handled above. Native Client validator on ARM + // rejects MRC instructions (used in the ARM-specific sequence below), + // so we handle it here. Portable Native Client compiles to + // architecture-agnostic bytecode, which doesn't provide any + // cycle counter access mnemonics. + + // Native Client does not provide any API to access cycle counter. + // Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday + // because is provides nanosecond resolution (which is noticable at + // least for PNaCl modules running on x86 Mac & Linux). + // Initialize to always return 0 if clock_gettime fails. + struct timespec ts = { 0, 0 }; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000000 + ts.tv_nsec; +#elif defined(__aarch64__) + // System timer of ARMv8 runs at a different frequency than the CPU's. + // The frequency is fixed, typically in the range 1-50MHz. It can be + // read at CNTFRQ special register. We assume the OS has set up + // the virtual timer properly. + int64_t virtual_timer_value; + asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); + return virtual_timer_value; +#elif defined(__ARM_ARCH) + // V6 is the earliest arch that has a standard cyclecount + // Native Client validator doesn't allow MRC instructions. +#if (__ARM_ARCH >= 6) + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + // Read the user mode perf monitor counter access permissions. + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return static_cast(pmccntr) * 64; // Should optimize to << 6 + } + } +#endif + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#elif defined(__mips__) + // mips apparently only allows rdtsc for superusers, so we fall + // back to gettimeofday. It's possible clock_gettime would be better. + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#else +// The soft failover to a generic implementation is automatic only for ARM. +// For other platforms the developer is expected to make an attempt to create +// a fast implementation and use generic version if nothing better is available. +#error You need to define CycleTimer for your OS and CPU +#endif +} +} // end namespace cycleclock +} // end namespace benchmark + +#endif // BENCHMARK_CYCLECLOCK_H_ diff --git a/src/internal_macros.h b/src/internal_macros.h new file mode 100644 index 0000000..9428874 --- /dev/null +++ b/src/internal_macros.h @@ -0,0 +1,57 @@ +#ifndef BENCHMARK_INTERNAL_MACROS_H_ +#define BENCHMARK_INTERNAL_MACROS_H_ + +#include "benchmark/benchmark.h" + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if defined(__clang__) +#define COMPILER_CLANG +#elif defined(_MSC_VER) +#define COMPILER_MSVC +#elif defined(__GNUC__) +#define COMPILER_GCC +#endif + +#if __has_feature(cxx_attributes) +#define BENCHMARK_NORETURN [[noreturn]] +#elif defined(__GNUC__) +#define BENCHMARK_NORETURN __attribute__((noreturn)) +#elif defined(COMPILER_MSVC) +#define BENCHMARK_NORETURN __declspec(noreturn) +#else +#define BENCHMARK_NORETURN +#endif + +#if defined(__CYGWIN__) +#define BENCHMARK_OS_CYGWIN 1 +#elif defined(_WIN32) +#define BENCHMARK_OS_WINDOWS 1 +#elif defined(__APPLE__) +#include "TargetConditionals.h" + #if defined(TARGET_OS_MAC) + #define BENCHMARK_OS_MACOSX 1 + #if defined(TARGET_OS_IPHONE) + #define BENCHMARK_OS_IOS 1 + #endif + #endif +#elif defined(__FreeBSD__) +#define BENCHMARK_OS_FREEBSD 1 +#elif defined(__linux__) +#define BENCHMARK_OS_LINUX 1 +#elif defined(__native_client__) +#define BENCHMARK_OS_NACL 1 +#elif defined(EMSCRIPTEN) +#define BENCHMARK_OS_EMSCRIPTEN 1 +#elif defined(__rtems__) +#define BENCHMARK_OS_RTEMS 1 +#endif + +#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \ + && !defined(__EXCEPTIONS) +#define BENCHMARK_HAS_NO_EXCEPTIONS +#endif + +#endif // BENCHMARK_INTERNAL_MACROS_H_ diff --git a/src/json_reporter.cc b/src/json_reporter.cc new file mode 100644 index 0000000..edf6ecc --- /dev/null +++ b/src/json_reporter.cc @@ -0,0 +1,168 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "complexity.h" + +#include +#include +#include +#include +#include +#include + +#include "string_util.h" +#include "timers.h" + +namespace benchmark { + +namespace { + +std::string FormatKV(std::string const& key, std::string const& value) { + return StringPrintF("\"%s\": \"%s\"", key.c_str(), value.c_str()); +} + +std::string FormatKV(std::string const& key, const char* value) { + return StringPrintF("\"%s\": \"%s\"", key.c_str(), value); +} + +std::string FormatKV(std::string const& key, bool value) { + return StringPrintF("\"%s\": %s", key.c_str(), value ? "true" : "false"); +} + +std::string FormatKV(std::string const& key, int64_t value) { + std::stringstream ss; + ss << '"' << key << "\": " << value; + return ss.str(); +} + +std::string FormatKV(std::string const& key, double value) { + return StringPrintF("\"%s\": %.2f", key.c_str(), value); +} + +int64_t RoundDouble(double v) { return static_cast(v + 0.5); } + +} // end namespace + +bool JSONReporter::ReportContext(const Context& context) { + std::ostream& out = GetOutputStream(); + + out << "{\n"; + std::string inner_indent(2, ' '); + + // Open context block and print context information. + out << inner_indent << "\"context\": {\n"; + std::string indent(4, ' '); + + std::string walltime_value = LocalDateTimeString(); + out << indent << FormatKV("date", walltime_value) << ",\n"; + + out << indent << FormatKV("num_cpus", static_cast(context.num_cpus)) + << ",\n"; + out << indent << FormatKV("mhz_per_cpu", RoundDouble(context.mhz_per_cpu)) + << ",\n"; + out << indent << FormatKV("cpu_scaling_enabled", context.cpu_scaling_enabled) + << ",\n"; + +#if defined(NDEBUG) + const char build_type[] = "release"; +#else + const char build_type[] = "debug"; +#endif + out << indent << FormatKV("library_build_type", build_type) << "\n"; + // Close context block and open the list of benchmarks. + out << inner_indent << "},\n"; + out << inner_indent << "\"benchmarks\": [\n"; + return true; +} + +void JSONReporter::ReportRuns(std::vector const& reports) { + if (reports.empty()) { + return; + } + std::string indent(4, ' '); + std::ostream& out = GetOutputStream(); + if (!first_report_) { + out << ",\n"; + } + first_report_ = false; + + for (auto it = reports.begin(); it != reports.end(); ++it) { + out << indent << "{\n"; + PrintRunData(*it); + out << indent << '}'; + auto it_cp = it; + if (++it_cp != reports.end()) { + out << ",\n"; + } + } +} + +void JSONReporter::Finalize() { + // Close the list of benchmarks and the top level object. + GetOutputStream() << "\n ]\n}\n"; +} + +void JSONReporter::PrintRunData(Run const& run) { + std::string indent(6, ' '); + std::ostream& out = GetOutputStream(); + out << indent << FormatKV("name", run.benchmark_name) << ",\n"; + if (run.error_occurred) { + out << indent << FormatKV("error_occurred", run.error_occurred) << ",\n"; + out << indent << FormatKV("error_message", run.error_message) << ",\n"; + } + if (!run.report_big_o && !run.report_rms) { + out << indent << FormatKV("iterations", run.iterations) << ",\n"; + out << indent + << FormatKV("real_time", RoundDouble(run.GetAdjustedRealTime())) + << ",\n"; + out << indent + << FormatKV("cpu_time", RoundDouble(run.GetAdjustedCPUTime())); + out << ",\n" + << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit)); + } else if (run.report_big_o) { + out << indent + << FormatKV("cpu_coefficient", RoundDouble(run.GetAdjustedCPUTime())) + << ",\n"; + out << indent + << FormatKV("real_coefficient", RoundDouble(run.GetAdjustedRealTime())) + << ",\n"; + out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n"; + out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit)); + } else if (run.report_rms) { + out << indent + << FormatKV("rms", run.GetAdjustedCPUTime()); + } + if (run.bytes_per_second > 0.0) { + out << ",\n" + << indent + << FormatKV("bytes_per_second", RoundDouble(run.bytes_per_second)); + } + if (run.items_per_second > 0.0) { + out << ",\n" + << indent + << FormatKV("items_per_second", RoundDouble(run.items_per_second)); + } + for(auto &c : run.counters) { + out << ",\n" + << indent + << FormatKV(c.first, RoundDouble(c.second)); + } + if (!run.report_label.empty()) { + out << ",\n" << indent << FormatKV("label", run.report_label); + } + out << '\n'; +} + +} // end namespace benchmark diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..d06e103 --- /dev/null +++ b/src/log.h @@ -0,0 +1,73 @@ +#ifndef BENCHMARK_LOG_H_ +#define BENCHMARK_LOG_H_ + +#include +#include + +#include "benchmark/benchmark.h" + +namespace benchmark { +namespace internal { + +typedef std::basic_ostream&(EndLType)(std::basic_ostream&); + +class LogType { + friend LogType& GetNullLogInstance(); + friend LogType& GetErrorLogInstance(); + + // FIXME: Add locking to output. + template + friend LogType& operator<<(LogType&, Tp const&); + friend LogType& operator<<(LogType&, EndLType*); + + private: + LogType(std::ostream* out) : out_(out) {} + std::ostream* out_; + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(LogType); +}; + +template +LogType& operator<<(LogType& log, Tp const& value) { + if (log.out_) { + *log.out_ << value; + } + return log; +} + +inline LogType& operator<<(LogType& log, EndLType* m) { + if (log.out_) { + *log.out_ << m; + } + return log; +} + +inline int& LogLevel() { + static int log_level = 0; + return log_level; +} + +inline LogType& GetNullLogInstance() { + static LogType log(nullptr); + return log; +} + +inline LogType& GetErrorLogInstance() { + static LogType log(&std::clog); + return log; +} + +inline LogType& GetLogInstanceForLevel(int level) { + if (level <= LogLevel()) { + return GetErrorLogInstance(); + } + return GetNullLogInstance(); +} + +} // end namespace internal +} // end namespace benchmark + +#define VLOG(x) \ + (::benchmark::internal::GetLogInstanceForLevel(x) << "-- LOG(" << x << "):" \ + " ") + +#endif diff --git a/src/mutex.h b/src/mutex.h new file mode 100644 index 0000000..5f461d0 --- /dev/null +++ b/src/mutex.h @@ -0,0 +1,155 @@ +#ifndef BENCHMARK_MUTEX_H_ +#define BENCHMARK_MUTEX_H_ + +#include +#include + +#include "check.h" + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define REQUIRES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define REQUIRES_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define RELEASE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define RELEASE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define ASSERT_SHARED_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +namespace benchmark { + +typedef std::condition_variable Condition; + +// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that +// we can annotate them with thread safety attributes and use the +// -Wthread-safety warning with clang. The standard library types cannot be +// used directly because they do not provided the required annotations. +class CAPABILITY("mutex") Mutex { + public: + Mutex() {} + + void lock() ACQUIRE() { mut_.lock(); } + void unlock() RELEASE() { mut_.unlock(); } + std::mutex& native_handle() { return mut_; } + + private: + std::mutex mut_; +}; + +class SCOPED_CAPABILITY MutexLock { + typedef std::unique_lock MutexLockImp; + + public: + MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {} + ~MutexLock() RELEASE() {} + MutexLockImp& native_handle() { return ml_; } + + private: + MutexLockImp ml_; +}; + +class Barrier { + public: + Barrier(int num_threads) : running_threads_(num_threads) {} + + // Called by each thread + bool wait() EXCLUDES(lock_) { + bool last_thread = false; + { + MutexLock ml(lock_); + last_thread = createBarrier(ml); + } + if (last_thread) phase_condition_.notify_all(); + return last_thread; + } + + void removeThread() EXCLUDES(lock_) { + MutexLock ml(lock_); + --running_threads_; + if (entered_ != 0) phase_condition_.notify_all(); + } + + private: + Mutex lock_; + Condition phase_condition_; + int running_threads_; + + // State for barrier management + int phase_number_ = 0; + int entered_ = 0; // Number of threads that have entered this barrier + + // Enter the barrier and wait until all other threads have also + // entered the barrier. Returns iff this is the last thread to + // enter the barrier. + bool createBarrier(MutexLock& ml) REQUIRES(lock_) { + CHECK_LT(entered_, running_threads_); + entered_++; + if (entered_ < running_threads_) { + // Wait for all threads to enter + int phase_number_cp = phase_number_; + auto cb = [this, phase_number_cp]() { + return this->phase_number_ > phase_number_cp || + entered_ == running_threads_; // A thread has aborted in error + }; + phase_condition_.wait(ml.native_handle(), cb); + if (phase_number_ > phase_number_cp) return false; + // else (running_threads_ == entered_) and we are the last thread. + } + // Last thread has reached the barrier + phase_number_++; + entered_ = 0; + return true; + } +}; + +} // end namespace benchmark + +#endif // BENCHMARK_MUTEX_H_ diff --git a/src/re.h b/src/re.h new file mode 100644 index 0000000..01e9736 --- /dev/null +++ b/src/re.h @@ -0,0 +1,140 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_RE_H_ +#define BENCHMARK_RE_H_ + +#include "internal_macros.h" + +// Prefer C regex libraries when compiling w/o exceptions so that we can +// correctly report errors. +#if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && defined(HAVE_STD_REGEX) && \ + (defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX)) +#undef HAVE_STD_REGEX +#endif + +#if defined(HAVE_STD_REGEX) +#include +#elif defined(HAVE_GNU_POSIX_REGEX) +#include +#elif defined(HAVE_POSIX_REGEX) +#include +#else +#error No regular expression backend was found! +#endif +#include + +#include "check.h" + +namespace benchmark { + +// A wrapper around the POSIX regular expression API that provides automatic +// cleanup +class Regex { + public: + Regex() : init_(false) {} + + ~Regex(); + + // Compile a regular expression matcher from spec. Returns true on success. + // + // On failure (and if error is not nullptr), error is populated with a human + // readable error message if an error occurs. + bool Init(const std::string& spec, std::string* error); + + // Returns whether str matches the compiled regular expression. + bool Match(const std::string& str); + + private: + bool init_; +// Underlying regular expression object +#if defined(HAVE_STD_REGEX) + std::regex re_; +#elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX) + regex_t re_; +#else +#error No regular expression backend implementation available +#endif +}; + +#if defined(HAVE_STD_REGEX) + +inline bool Regex::Init(const std::string& spec, std::string* error) { +#ifdef BENCHMARK_HAS_NO_EXCEPTIONS + ((void)error); // suppress unused warning +#else + try { +#endif + re_ = std::regex(spec, std::regex_constants::extended); + init_ = true; +#ifndef BENCHMARK_HAS_NO_EXCEPTIONS + } catch (const std::regex_error& e) { + if (error) { + *error = e.what(); + } + } +#endif + return init_; +} + +inline Regex::~Regex() {} + +inline bool Regex::Match(const std::string& str) { + if (!init_) { + return false; + } + return std::regex_search(str, re_); +} + +#else +inline bool Regex::Init(const std::string& spec, std::string* error) { + int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + if (error) { + size_t needed = regerror(ec, &re_, nullptr, 0); + char* errbuf = new char[needed]; + regerror(ec, &re_, errbuf, needed); + + // regerror returns the number of bytes necessary to null terminate + // the string, so we move that when assigning to error. + CHECK_NE(needed, 0); + error->assign(errbuf, needed - 1); + + delete[] errbuf; + } + + return false; + } + + init_ = true; + return true; +} + +inline Regex::~Regex() { + if (init_) { + regfree(&re_); + } +} + +inline bool Regex::Match(const std::string& str) { + if (!init_) { + return false; + } + return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0; +} +#endif + +} // end namespace benchmark + +#endif // BENCHMARK_RE_H_ diff --git a/src/reporter.cc b/src/reporter.cc new file mode 100644 index 0000000..aacd453 --- /dev/null +++ b/src/reporter.cc @@ -0,0 +1,68 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "timers.h" + +#include + +#include +#include +#include + +#include "check.h" +#include "stat.h" + +namespace benchmark { + +BenchmarkReporter::BenchmarkReporter() + : output_stream_(&std::cout), error_stream_(&std::cerr) {} + +BenchmarkReporter::~BenchmarkReporter() {} + +void BenchmarkReporter::PrintBasicContext(std::ostream *out, + Context const &context) { + CHECK(out) << "cannot be null"; + auto &Out = *out; + + Out << "Run on (" << context.num_cpus << " X " << context.mhz_per_cpu + << " MHz CPU " << ((context.num_cpus > 1) ? "s" : "") << ")\n"; + + Out << LocalDateTimeString() << "\n"; + + if (context.cpu_scaling_enabled) { + Out << "***WARNING*** CPU scaling is enabled, the benchmark " + "real time measurements may be noisy and will incur extra " + "overhead.\n"; + } + +#ifndef NDEBUG + Out << "***WARNING*** Library was built as DEBUG. Timings may be " + "affected.\n"; +#endif +} + +double BenchmarkReporter::Run::GetAdjustedRealTime() const { + double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit); + if (iterations != 0) new_time /= static_cast(iterations); + return new_time; +} + +double BenchmarkReporter::Run::GetAdjustedCPUTime() const { + double new_time = cpu_accumulated_time * GetTimeUnitMultiplier(time_unit); + if (iterations != 0) new_time /= static_cast(iterations); + return new_time; +} + +} // end namespace benchmark diff --git a/src/sleep.cc b/src/sleep.cc new file mode 100644 index 0000000..54aa04a --- /dev/null +++ b/src/sleep.cc @@ -0,0 +1,51 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sleep.h" + +#include +#include +#include + +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#endif + +namespace benchmark { +#ifdef BENCHMARK_OS_WINDOWS +// Window's Sleep takes milliseconds argument. +void SleepForMilliseconds(int milliseconds) { Sleep(milliseconds); } +void SleepForSeconds(double seconds) { + SleepForMilliseconds(static_cast(kNumMillisPerSecond * seconds)); +} +#else // BENCHMARK_OS_WINDOWS +void SleepForMicroseconds(int microseconds) { + struct timespec sleep_time; + sleep_time.tv_sec = microseconds / kNumMicrosPerSecond; + sleep_time.tv_nsec = (microseconds % kNumMicrosPerSecond) * kNumNanosPerMicro; + while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) + ; // Ignore signals and wait for the full interval to elapse. +} + +void SleepForMilliseconds(int milliseconds) { + SleepForMicroseconds(milliseconds * kNumMicrosPerMilli); +} + +void SleepForSeconds(double seconds) { + SleepForMicroseconds(static_cast(seconds * kNumMicrosPerSecond)); +} +#endif // BENCHMARK_OS_WINDOWS +} // end namespace benchmark diff --git a/src/sleep.h b/src/sleep.h new file mode 100644 index 0000000..f98551a --- /dev/null +++ b/src/sleep.h @@ -0,0 +1,15 @@ +#ifndef BENCHMARK_SLEEP_H_ +#define BENCHMARK_SLEEP_H_ + +namespace benchmark { +const int kNumMillisPerSecond = 1000; +const int kNumMicrosPerMilli = 1000; +const int kNumMicrosPerSecond = kNumMillisPerSecond * 1000; +const int kNumNanosPerMicro = 1000; +const int kNumNanosPerSecond = kNumNanosPerMicro * kNumMicrosPerSecond; + +void SleepForMilliseconds(int milliseconds); +void SleepForSeconds(double seconds); +} // end namespace benchmark + +#endif // BENCHMARK_SLEEP_H_ diff --git a/src/stat.h b/src/stat.h new file mode 100644 index 0000000..d356875 --- /dev/null +++ b/src/stat.h @@ -0,0 +1,310 @@ +#ifndef BENCHMARK_STAT_H_ +#define BENCHMARK_STAT_H_ + +#include +#include +#include +#include + +namespace benchmark { + +template +class Stat1; + +template +class Stat1MinMax; + +typedef Stat1 Stat1_f; +typedef Stat1 Stat1_d; +typedef Stat1MinMax Stat1MinMax_f; +typedef Stat1MinMax Stat1MinMax_d; + +template +class Vector2; +template +class Vector3; +template +class Vector4; + +template +class Stat1 { + public: + typedef Stat1 Self; + + Stat1() { Clear(); } + // Create a sample of value dat and weight 1 + explicit Stat1(const VType &dat) { + sum_ = dat; + sum_squares_ = Sqr(dat); + numsamples_ = 1; + } + // Create statistics for all the samples between begin (included) + // and end(excluded) + explicit Stat1(const VType *begin, const VType *end) { + Clear(); + for (const VType *item = begin; item < end; ++item) { + (*this) += Stat1(*item); + } + } + // Create a sample of value dat and weight w + Stat1(const VType &dat, const NumType &w) { + sum_ = w * dat; + sum_squares_ = w * Sqr(dat); + numsamples_ = w; + } + // Copy operator + Stat1(const Self &stat) { + sum_ = stat.sum_; + sum_squares_ = stat.sum_squares_; + numsamples_ = stat.numsamples_; + } + + void Clear() { + numsamples_ = NumType(); + sum_squares_ = sum_ = VType(); + } + + Self &operator=(const Self &stat) { + sum_ = stat.sum_; + sum_squares_ = stat.sum_squares_; + numsamples_ = stat.numsamples_; + return (*this); + } + // Merge statistics from two sample sets. + Self &operator+=(const Self &stat) { + sum_ += stat.sum_; + sum_squares_ += stat.sum_squares_; + numsamples_ += stat.numsamples_; + return (*this); + } + // The operation opposite to += + Self &operator-=(const Self &stat) { + sum_ -= stat.sum_; + sum_squares_ -= stat.sum_squares_; + numsamples_ -= stat.numsamples_; + return (*this); + } + // Multiply the weight of the set of samples by a factor k + Self &operator*=(const VType &k) { + sum_ *= k; + sum_squares_ *= k; + numsamples_ *= k; + return (*this); + } + + // Merge statistics from two sample sets. + Self operator+(const Self &stat) const { return Self(*this) += stat; } + + // The operation opposite to + + Self operator-(const Self &stat) const { return Self(*this) -= stat; } + + // Multiply the weight of the set of samples by a factor k + Self operator*(const VType &k) const { return Self(*this) *= k; } + + // Return the total weight of this sample set + NumType numSamples() const { return numsamples_; } + + // Return the sum of this sample set + VType Sum() const { return sum_; } + + // Return the mean of this sample set + VType Mean() const { + if (numsamples_ == 0) return VType(); + return sum_ * (1.0 / numsamples_); + } + + // Return the mean of this sample set and compute the standard deviation at + // the same time. + VType Mean(VType *stddev) const { + if (numsamples_ == 0) return VType(); + VType mean = sum_ * (1.0 / numsamples_); + if (stddev) { + // Sample standard deviation is undefined for n = 1 + if (numsamples_ == 1) { + *stddev = VType(); + } else { + VType avg_squares = sum_squares_ * (1.0 / numsamples_); + *stddev = Sqrt(numsamples_ / (numsamples_ - 1.0) * (avg_squares - Sqr(mean))); + } + } + return mean; + } + + // Return the standard deviation of the sample set + VType StdDev() const { + VType stddev = VType(); + Mean(&stddev); + return stddev; + } + + private: + static_assert(std::is_integral::value && + !std::is_same::value, + "NumType must be an integral type that is not bool."); + // Let i be the index of the samples provided (using +=) + // and weight[i],value[i] be the data of sample #i + // then the variables have the following meaning: + NumType numsamples_; // sum of weight[i]; + VType sum_; // sum of weight[i]*value[i]; + VType sum_squares_; // sum of weight[i]*value[i]^2; + + // Template function used to square a number. + // For a vector we square all components + template + static inline SType Sqr(const SType &dat) { + return dat * dat; + } + + template + static inline Vector2 Sqr(const Vector2 &dat) { + return dat.MulComponents(dat); + } + + template + static inline Vector3 Sqr(const Vector3 &dat) { + return dat.MulComponents(dat); + } + + template + static inline Vector4 Sqr(const Vector4 &dat) { + return dat.MulComponents(dat); + } + + // Template function used to take the square root of a number. + // For a vector we square all components + template + static inline SType Sqrt(const SType &dat) { + // Avoid NaN due to imprecision in the calculations + if (dat < 0) return 0; + return sqrt(dat); + } + + template + static inline Vector2 Sqrt(const Vector2 &dat) { + // Avoid NaN due to imprecision in the calculations + return Max(dat, Vector2()).Sqrt(); + } + + template + static inline Vector3 Sqrt(const Vector3 &dat) { + // Avoid NaN due to imprecision in the calculations + return Max(dat, Vector3()).Sqrt(); + } + + template + static inline Vector4 Sqrt(const Vector4 &dat) { + // Avoid NaN due to imprecision in the calculations + return Max(dat, Vector4()).Sqrt(); + } +}; + +// Useful printing function +template +std::ostream &operator<<(std::ostream &out, const Stat1 &s) { + out << "{ avg = " << s.Mean() << " std = " << s.StdDev() + << " nsamples = " << s.NumSamples() << "}"; + return out; +} + +// Stat1MinMax: same as Stat1, but it also +// keeps the Min and Max values; the "-" +// operator is disabled because it cannot be implemented +// efficiently +template +class Stat1MinMax : public Stat1 { + public: + typedef Stat1MinMax Self; + + Stat1MinMax() { Clear(); } + // Create a sample of value dat and weight 1 + explicit Stat1MinMax(const VType &dat) : Stat1(dat) { + max_ = dat; + min_ = dat; + } + // Create statistics for all the samples between begin (included) + // and end(excluded) + explicit Stat1MinMax(const VType *begin, const VType *end) { + Clear(); + for (const VType *item = begin; item < end; ++item) { + (*this) += Stat1MinMax(*item); + } + } + // Create a sample of value dat and weight w + Stat1MinMax(const VType &dat, const NumType &w) + : Stat1(dat, w) { + max_ = dat; + min_ = dat; + } + // Copy operator + Stat1MinMax(const Self &stat) : Stat1(stat) { + max_ = stat.max_; + min_ = stat.min_; + } + + void Clear() { + Stat1::Clear(); + if (std::numeric_limits::has_infinity) { + min_ = std::numeric_limits::infinity(); + max_ = -std::numeric_limits::infinity(); + } else { + min_ = std::numeric_limits::max(); + max_ = std::numeric_limits::min(); + } + } + + Self &operator=(const Self &stat) { + this->Stat1::operator=(stat); + max_ = stat.max_; + min_ = stat.min_; + return (*this); + } + // Merge statistics from two sample sets. + Self &operator+=(const Self &stat) { + this->Stat1::operator+=(stat); + if (stat.max_ > max_) max_ = stat.max_; + if (stat.min_ < min_) min_ = stat.min_; + return (*this); + } + // Multiply the weight of the set of samples by a factor k + Self &operator*=(const VType &stat) { + this->Stat1::operator*=(stat); + return (*this); + } + // Merge statistics from two sample sets. + Self operator+(const Self &stat) const { return Self(*this) += stat; } + // Multiply the weight of the set of samples by a factor k + Self operator*(const VType &k) const { return Self(*this) *= k; } + + // Return the maximal value in this sample set + VType Max() const { return max_; } + // Return the minimal value in this sample set + VType Min() const { return min_; } + + private: + // The - operation makes no sense with Min/Max + // unless we keep the full list of values (but we don't) + // make it private, and let it undefined so nobody can call it + Self &operator-=(const Self &stat); // senseless. let it undefined. + + // The operation opposite to - + Self operator-(const Self &stat) const; // senseless. let it undefined. + + // Let i be the index of the samples provided (using +=) + // and weight[i],value[i] be the data of sample #i + // then the variables have the following meaning: + VType max_; // max of value[i] + VType min_; // min of value[i] +}; + +// Useful printing function +template +std::ostream &operator<<(std::ostream &out, + const Stat1MinMax &s) { + out << "{ avg = " << s.Mean() << " std = " << s.StdDev() + << " nsamples = " << s.NumSamples() << " min = " << s.Min() + << " max = " << s.Max() << "}"; + return out; +} +} // end namespace benchmark + +#endif // BENCHMARK_STAT_H_ diff --git a/src/string_util.cc b/src/string_util.cc new file mode 100644 index 0000000..cd4e7cf --- /dev/null +++ b/src/string_util.cc @@ -0,0 +1,172 @@ +#include "string_util.h" + +#include +#include +#include +#include +#include +#include + +#include "arraysize.h" + +namespace benchmark { +namespace { + +// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta. +const char kBigSIUnits[] = "kMGTPEZY"; +// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi. +const char kBigIECUnits[] = "KMGTPEZY"; +// milli, micro, nano, pico, femto, atto, zepto, yocto. +const char kSmallSIUnits[] = "munpfazy"; + +// We require that all three arrays have the same size. +static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits), + "SI and IEC unit arrays must be the same size"); +static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits), + "Small SI and Big SI unit arrays must be the same size"); + +static const int64_t kUnitsSize = arraysize(kBigSIUnits); + +} // end anonymous namespace + +void ToExponentAndMantissa(double val, double thresh, int precision, + double one_k, std::string* mantissa, + int64_t* exponent) { + std::stringstream mantissa_stream; + + if (val < 0) { + mantissa_stream << "-"; + val = -val; + } + + // Adjust threshold so that it never excludes things which can't be rendered + // in 'precision' digits. + const double adjusted_threshold = + std::max(thresh, 1.0 / std::pow(10.0, precision)); + const double big_threshold = adjusted_threshold * one_k; + const double small_threshold = adjusted_threshold; + // Values in ]simple_threshold,small_threshold[ will be printed as-is + const double simple_threshold = 0.01; + + if (val > big_threshold) { + // Positive powers + double scaled = val; + for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) { + scaled /= one_k; + if (scaled <= big_threshold) { + mantissa_stream << scaled; + *exponent = i + 1; + *mantissa = mantissa_stream.str(); + return; + } + } + mantissa_stream << val; + *exponent = 0; + } else if (val < small_threshold) { + // Negative powers + if (val < simple_threshold) { + double scaled = val; + for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) { + scaled *= one_k; + if (scaled >= small_threshold) { + mantissa_stream << scaled; + *exponent = -static_cast(i + 1); + *mantissa = mantissa_stream.str(); + return; + } + } + } + mantissa_stream << val; + *exponent = 0; + } else { + mantissa_stream << val; + *exponent = 0; + } + *mantissa = mantissa_stream.str(); +} + +std::string ExponentToPrefix(int64_t exponent, bool iec) { + if (exponent == 0) return ""; + + const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1); + if (index >= kUnitsSize) return ""; + + const char* array = + (exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits); + if (iec) + return array[index] + std::string("i"); + else + return std::string(1, array[index]); +} + +std::string ToBinaryStringFullySpecified(double value, double threshold, + int precision) { + std::string mantissa; + int64_t exponent; + ToExponentAndMantissa(value, threshold, precision, 1024.0, &mantissa, + &exponent); + return mantissa + ExponentToPrefix(exponent, false); +} + +void AppendHumanReadable(int n, std::string* str) { + std::stringstream ss; + // Round down to the nearest SI prefix. + ss << ToBinaryStringFullySpecified(n, 1.0, 0); + *str += ss.str(); +} + +std::string HumanReadableNumber(double n) { + // 1.1 means that figures up to 1.1k should be shown with the next unit down; + // this softens edge effects. + // 1 means that we should show one decimal place of precision. + return ToBinaryStringFullySpecified(n, 1.1, 1); +} + +std::string StringPrintFImp(const char* msg, va_list args) { + // we might need a second shot at this, so pre-emptivly make a copy + va_list args_cp; + va_copy(args_cp, args); + + // TODO(ericwf): use std::array for first attempt to avoid one memory + // allocation guess what the size might be + std::array local_buff; + std::size_t size = local_buff.size(); + // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation + // in the android-ndk + auto ret = vsnprintf(local_buff.data(), size, msg, args_cp); + + va_end(args_cp); + + // handle empty expansion + if (ret == 0) return std::string{}; + if (static_cast(ret) < size) + return std::string(local_buff.data()); + + // we did not provide a long enough buffer on our first attempt. + // add 1 to size to account for null-byte in size cast to prevent overflow + size = static_cast(ret) + 1; + auto buff_ptr = std::unique_ptr(new char[size]); + // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation + // in the android-ndk + ret = vsnprintf(buff_ptr.get(), size, msg, args); + return std::string(buff_ptr.get()); +} + +std::string StringPrintF(const char* format, ...) { + va_list args; + va_start(args, format); + std::string tmp = StringPrintFImp(format, args); + va_end(args); + return tmp; +} + +void ReplaceAll(std::string* str, const std::string& from, + const std::string& to) { + std::size_t start = 0; + while ((start = str->find(from, start)) != std::string::npos) { + str->replace(start, from.length(), to); + start += to.length(); + } +} + +} // end namespace benchmark diff --git a/src/string_util.h b/src/string_util.h new file mode 100644 index 0000000..0b190b9 --- /dev/null +++ b/src/string_util.h @@ -0,0 +1,40 @@ +#ifndef BENCHMARK_STRING_UTIL_H_ +#define BENCHMARK_STRING_UTIL_H_ + +#include +#include +#include +#include "internal_macros.h" + +namespace benchmark { + +void AppendHumanReadable(int n, std::string* str); + +std::string HumanReadableNumber(double n); + +std::string StringPrintF(const char* format, ...); + +inline std::ostream& StringCatImp(std::ostream& out) BENCHMARK_NOEXCEPT { + return out; +} + +template +inline std::ostream& StringCatImp(std::ostream& out, First&& f, + Rest&&... rest) { + out << std::forward(f); + return StringCatImp(out, std::forward(rest)...); +} + +template +inline std::string StrCat(Args&&... args) { + std::ostringstream ss; + StringCatImp(ss, std::forward(args)...); + return ss.str(); +} + +void ReplaceAll(std::string* str, const std::string& from, + const std::string& to); + +} // end namespace benchmark + +#endif // BENCHMARK_STRING_UTIL_H_ diff --git a/src/sysinfo.cc b/src/sysinfo.cc new file mode 100644 index 0000000..7feb79e --- /dev/null +++ b/src/sysinfo.cc @@ -0,0 +1,355 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sysinfo.h" +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#include +#include +#else +#include +#include +#include +#include // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD +#include +#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arraysize.h" +#include "check.h" +#include "cycleclock.h" +#include "internal_macros.h" +#include "log.h" +#include "sleep.h" +#include "string_util.h" + +namespace benchmark { +namespace { +std::once_flag cpuinfo_init; +double cpuinfo_cycles_per_second = 1.0; +int cpuinfo_num_cpus = 1; // Conservative guess + +#if !defined BENCHMARK_OS_MACOSX +const int64_t estimate_time_ms = 1000; + +// Helper function estimates cycles/sec by observing cycles elapsed during +// sleep(). Using small sleep time decreases accuracy significantly. +int64_t EstimateCyclesPerSecond() { + const int64_t start_ticks = cycleclock::Now(); + SleepForMilliseconds(estimate_time_ms); + return cycleclock::Now() - start_ticks; +} +#endif + +#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN +// Helper function for reading an int from a file. Returns true if successful +// and the memory location pointed to by value is set to the value read. +bool ReadIntFromFile(const char* file, long* value) { + bool ret = false; + int fd = open(file, O_RDONLY); + if (fd != -1) { + char line[1024]; + char* err; + memset(line, '\0', sizeof(line)); + ssize_t read_err = read(fd, line, sizeof(line) - 1); + ((void)read_err); // prevent unused warning + CHECK(read_err >= 0); + const long temp_value = strtol(line, &err, 10); + if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { + *value = temp_value; + ret = true; + } + close(fd); + } + return ret; +} +#endif + +#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN +static std::string convertToLowerCase(std::string s) { + for (auto& ch : s) + ch = std::tolower(ch); + return s; +} +static bool startsWithKey(std::string Value, std::string Key, + bool IgnoreCase = true) { + if (IgnoreCase) { + Key = convertToLowerCase(std::move(Key)); + Value = convertToLowerCase(std::move(Value)); + } + return Value.compare(0, Key.size(), Key) == 0; +} +#endif + +void InitializeSystemInfo() { +#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN + char line[1024]; + char* err; + long freq; + + bool saw_mhz = false; + + // If the kernel is exporting the tsc frequency use that. There are issues + // where cpuinfo_max_freq cannot be relied on because the BIOS may be + // exporintg an invalid p-state (on x86) or p-states may be used to put the + // processor in a new mode (turbo mode). Essentially, those frequencies + // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as + // well. + if (!saw_mhz && + ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { + // The value is in kHz (as the file name suggests). For example, on a + // 2GHz warpstation, the file contains the value "2000000". + cpuinfo_cycles_per_second = freq * 1000.0; + saw_mhz = true; + } + + // If CPU scaling is in effect, we want to use the *maximum* frequency, + // not whatever CPU speed some random processor happens to be using now. + if (!saw_mhz && + ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", + &freq)) { + // The value is in kHz. For example, on a 2GHz warpstation, the file + // contains the value "2000000". + cpuinfo_cycles_per_second = freq * 1000.0; + saw_mhz = true; + } + + // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. + const char* pname = "/proc/cpuinfo"; + int fd = open(pname, O_RDONLY); + if (fd == -1) { + perror(pname); + if (!saw_mhz) { + cpuinfo_cycles_per_second = + static_cast(EstimateCyclesPerSecond()); + } + return; + } + + double bogo_clock = 1.0; + bool saw_bogo = false; + long max_cpu_id = 0; + int num_cpus = 0; + line[0] = line[1] = '\0'; + size_t chars_read = 0; + do { // we'll exit when the last read didn't read anything + // Move the next line to the beginning of the buffer + const size_t oldlinelen = strlen(line); + if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line + line[0] = '\0'; + else // still other lines left to save + memmove(line, line + oldlinelen + 1, sizeof(line) - (oldlinelen + 1)); + // Terminate the new line, reading more if we can't find the newline + char* newline = strchr(line, '\n'); + if (newline == nullptr) { + const size_t linelen = strlen(line); + const size_t bytes_to_read = sizeof(line) - 1 - linelen; + CHECK(bytes_to_read > 0); // because the memmove recovered >=1 bytes + chars_read = read(fd, line + linelen, bytes_to_read); + line[linelen + chars_read] = '\0'; + newline = strchr(line, '\n'); + } + if (newline != nullptr) *newline = '\0'; + + // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only + // accept postive values. Some environments (virtual machines) report zero, + // which would cause infinite looping in WallTime_Init. + if (!saw_mhz && startsWithKey(line, "cpu MHz")) { + const char* freqstr = strchr(line, ':'); + if (freqstr) { + cpuinfo_cycles_per_second = strtod(freqstr + 1, &err) * 1000000.0; + if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0) + saw_mhz = true; + } + } else if (startsWithKey(line, "bogomips")) { + const char* freqstr = strchr(line, ':'); + if (freqstr) { + bogo_clock = strtod(freqstr + 1, &err) * 1000000.0; + if (freqstr[1] != '\0' && *err == '\0' && bogo_clock > 0) + saw_bogo = true; + } + } else if (startsWithKey(line, "processor", /*IgnoreCase*/false)) { + // The above comparison is case-sensitive because ARM kernels often + // include a "Processor" line that tells you about the CPU, distinct + // from the usual "processor" lines that give you CPU ids. No current + // Linux architecture is using "Processor" for CPU ids. + num_cpus++; // count up every time we see an "processor :" entry + const char* id_str = strchr(line, ':'); + if (id_str) { + const long cpu_id = strtol(id_str + 1, &err, 10); + if (id_str[1] != '\0' && *err == '\0' && max_cpu_id < cpu_id) + max_cpu_id = cpu_id; + } + } + } while (chars_read > 0); + close(fd); + + if (!saw_mhz) { + if (saw_bogo) { + // If we didn't find anything better, we'll use bogomips, but + // we're not happy about it. + cpuinfo_cycles_per_second = bogo_clock; + } else { + // If we don't even have bogomips, we'll use the slow estimation. + cpuinfo_cycles_per_second = + static_cast(EstimateCyclesPerSecond()); + } + } + if (num_cpus == 0) { + fprintf(stderr, "Failed to read num. CPUs correctly from /proc/cpuinfo\n"); + } else { + if ((max_cpu_id + 1) != num_cpus) { + fprintf(stderr, + "CPU ID assignments in /proc/cpuinfo seem messed up." + " This is usually caused by a bad BIOS.\n"); + } + cpuinfo_num_cpus = num_cpus; + } + +#elif defined BENCHMARK_OS_FREEBSD +// For this sysctl to work, the machine must be configured without +// SMP, APIC, or APM support. hz should be 64-bit in freebsd 7.0 +// and later. Before that, it's a 32-bit quantity (and gives the +// wrong answer on machines faster than 2^32 Hz). See +// http://lists.freebsd.org/pipermail/freebsd-i386/2004-November/001846.html +// But also compare FreeBSD 7.0: +// http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG70#L223 +// 231 error = sysctl_handle_quad(oidp, &freq, 0, req); +// To FreeBSD 6.3 (it's the same in 6-STABLE): +// http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG6#L131 +// 139 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); +#if __FreeBSD__ >= 7 + uint64_t hz = 0; +#else + unsigned int hz = 0; +#endif + size_t sz = sizeof(hz); + const char* sysctl_path = "machdep.tsc_freq"; + if (sysctlbyname(sysctl_path, &hz, &sz, nullptr, 0) != 0) { + fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", + sysctl_path, strerror(errno)); + cpuinfo_cycles_per_second = static_cast(EstimateCyclesPerSecond()); + } else { + cpuinfo_cycles_per_second = hz; + } +// TODO: also figure out cpuinfo_num_cpus + +#elif defined BENCHMARK_OS_WINDOWS + // In NT, read MHz from the registry. If we fail to do so or we're in win9x + // then make a crude estimate. + DWORD data, data_size = sizeof(data); + if (IsWindowsXPOrGreater() && + SUCCEEDED( + SHGetValueA(HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + "~MHz", nullptr, &data, &data_size))) + cpuinfo_cycles_per_second = + static_cast((int64_t)data * (int64_t)(1000 * 1000)); // was mhz + else + cpuinfo_cycles_per_second = static_cast(EstimateCyclesPerSecond()); + + SYSTEM_INFO sysinfo; + // Use memset as opposed to = {} to avoid GCC missing initializer false + // positives. + std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO)); + GetSystemInfo(&sysinfo); + cpuinfo_num_cpus = sysinfo.dwNumberOfProcessors; // number of logical + // processors in the current + // group + +#elif defined BENCHMARK_OS_MACOSX + int32_t num_cpus = 0; + size_t size = sizeof(num_cpus); + if (::sysctlbyname("hw.ncpu", &num_cpus, &size, nullptr, 0) == 0 && + (size == sizeof(num_cpus))) { + cpuinfo_num_cpus = num_cpus; + } else { + fprintf(stderr, "%s\n", strerror(errno)); + std::exit(EXIT_FAILURE); + } + int64_t cpu_freq = 0; + size = sizeof(cpu_freq); + if (::sysctlbyname("hw.cpufrequency", &cpu_freq, &size, nullptr, 0) == 0 && + (size == sizeof(cpu_freq))) { + cpuinfo_cycles_per_second = cpu_freq; + } else { + #if defined BENCHMARK_OS_IOS + fprintf(stderr, "CPU frequency cannot be detected. \n"); + cpuinfo_cycles_per_second = 0; + #else + fprintf(stderr, "%s\n", strerror(errno)); + std::exit(EXIT_FAILURE); + #endif + } +#else + // Generic cycles per second counter + cpuinfo_cycles_per_second = static_cast(EstimateCyclesPerSecond()); +#endif +} + +} // end namespace + +double CyclesPerSecond(void) { + std::call_once(cpuinfo_init, InitializeSystemInfo); + return cpuinfo_cycles_per_second; +} + +int NumCPUs(void) { + std::call_once(cpuinfo_init, InitializeSystemInfo); + return cpuinfo_num_cpus; +} + +// The ""'s catch people who don't pass in a literal for "str" +#define strliterallen(str) (sizeof("" str "") - 1) + +// Must use a string literal for prefix. +#define memprefix(str, len, prefix) \ + ((((len) >= strliterallen(prefix)) && \ + std::memcmp(str, prefix, strliterallen(prefix)) == 0) \ + ? str + strliterallen(prefix) \ + : nullptr) + +bool CpuScalingEnabled() { +#ifndef BENCHMARK_OS_WINDOWS + // On Linux, the CPUfreq subsystem exposes CPU information as files on the + // local file system. If reading the exported files fails, then we may not be + // running on Linux, so we silently ignore all the read errors. + for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) { + std::string governor_file = + StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor"); + FILE* file = fopen(governor_file.c_str(), "r"); + if (!file) break; + char buff[16]; + size_t bytes_read = fread(buff, 1, sizeof(buff), file); + fclose(file); + if (memprefix(buff, bytes_read, "performance") == nullptr) return true; + } +#endif + return false; +} + +} // end namespace benchmark diff --git a/src/sysinfo.h b/src/sysinfo.h new file mode 100644 index 0000000..c5d9916 --- /dev/null +++ b/src/sysinfo.h @@ -0,0 +1,10 @@ +#ifndef BENCHMARK_SYSINFO_H_ +#define BENCHMARK_SYSINFO_H_ + +namespace benchmark { +int NumCPUs(); +double CyclesPerSecond(); +bool CpuScalingEnabled(); +} // end namespace benchmark + +#endif // BENCHMARK_SYSINFO_H_ diff --git a/src/timers.cc b/src/timers.cc new file mode 100644 index 0000000..817272d --- /dev/null +++ b/src/timers.cc @@ -0,0 +1,212 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "timers.h" +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#include +#include +#else +#include +#include +#include +#include // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD +#include +#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX +#include +#endif +#if defined(BENCHMARK_OS_MACOSX) +#include +#include +#include +#endif +#endif + +#ifdef BENCHMARK_OS_EMSCRIPTEN +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "log.h" +#include "sleep.h" +#include "string_util.h" + +namespace benchmark { + +// Suppress unused warnings on helper functions. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +namespace { +#if defined(BENCHMARK_OS_WINDOWS) +double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) { + ULARGE_INTEGER kernel; + ULARGE_INTEGER user; + kernel.HighPart = kernel_time.dwHighDateTime; + kernel.LowPart = kernel_time.dwLowDateTime; + user.HighPart = user_time.dwHighDateTime; + user.LowPart = user_time.dwLowDateTime; + return (static_cast(kernel.QuadPart) + + static_cast(user.QuadPart)) * + 1e-7; +} +#else +double MakeTime(struct rusage const& ru) { + return (static_cast(ru.ru_utime.tv_sec) + + static_cast(ru.ru_utime.tv_usec) * 1e-6 + + static_cast(ru.ru_stime.tv_sec) + + static_cast(ru.ru_stime.tv_usec) * 1e-6); +} +#endif +#if defined(BENCHMARK_OS_MACOSX) +double MakeTime(thread_basic_info_data_t const& info) { + return (static_cast(info.user_time.seconds) + + static_cast(info.user_time.microseconds) * 1e-6 + + static_cast(info.system_time.seconds) + + static_cast(info.system_time.microseconds) * 1e-6); +} +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID) +double MakeTime(struct timespec const& ts) { + return ts.tv_sec + (static_cast(ts.tv_nsec) * 1e-9); +} +#endif + +BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) { + std::cerr << "ERROR: " << msg << std::endl; + std::exit(EXIT_FAILURE); +} + +} // end namespace + +double ProcessCPUUsage() { +#if defined(BENCHMARK_OS_WINDOWS) + HANDLE proc = GetCurrentProcess(); + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time, + &user_time)) + return MakeTime(kernel_time, user_time); + DiagnoseAndExit("GetProccessTimes() failed"); +#elif defined(BENCHMARK_OS_EMSCRIPTEN) + // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten. + // Use Emscripten-specific API. Reported CPU time would be exactly the + // same as total time, but this is ok because there aren't long-latency + // syncronous system calls in Emscripten. + return emscripten_get_now() * 1e-3; +#elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX) + // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See + // https://github.com/google/benchmark/pull/292 + struct timespec spec; + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0) + return MakeTime(spec); + DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed"); +#else + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru); + DiagnoseAndExit("getrusage(RUSAGE_SELF, ...) failed"); +#endif +} + +double ThreadCPUUsage() { +#if defined(BENCHMARK_OS_WINDOWS) + HANDLE this_thread = GetCurrentThread(); + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time, + &user_time); + return MakeTime(kernel_time, user_time); +#elif defined(BENCHMARK_OS_MACOSX) + // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See + // https://github.com/google/benchmark/pull/292 + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + mach_port_t thread = pthread_mach_thread_np(pthread_self()); + if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count) == + KERN_SUCCESS) { + return MakeTime(info); + } + DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info"); +#elif defined(BENCHMARK_OS_EMSCRIPTEN) + // Emscripten doesn't support traditional threads + return ProcessCPUUsage(); +#elif defined(BENCHMARK_OS_RTEMS) + // RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See + // https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c + return ProcessCPUUsage(); +#elif defined(CLOCK_THREAD_CPUTIME_ID) + struct timespec ts; + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts); + DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed"); +#else +#error Per-thread timing is not available on your system. +#endif +} + +namespace { + +std::string DateTimeString(bool local) { + typedef std::chrono::system_clock Clock; + std::time_t now = Clock::to_time_t(Clock::now()); + const std::size_t kStorageSize = 128; + char storage[kStorageSize]; + std::size_t written; + + if (local) { +#if defined(BENCHMARK_OS_WINDOWS) + written = + std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now)); +#else + std::tm timeinfo; + std::memset(&timeinfo, 0, sizeof(std::tm)); + ::localtime_r(&now, &timeinfo); + written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); +#endif + } else { +#if defined(BENCHMARK_OS_WINDOWS) + written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now)); +#else + std::tm timeinfo; + std::memset(&timeinfo, 0, sizeof(std::tm)); + ::gmtime_r(&now, &timeinfo); + written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); +#endif + } + CHECK(written < kStorageSize); + ((void)written); // prevent unused variable in optimized mode. + return std::string(storage); +} + +} // end namespace + +std::string LocalDateTimeString() { return DateTimeString(true); } + +} // end namespace benchmark diff --git a/src/timers.h b/src/timers.h new file mode 100644 index 0000000..65606cc --- /dev/null +++ b/src/timers.h @@ -0,0 +1,48 @@ +#ifndef BENCHMARK_TIMERS_H +#define BENCHMARK_TIMERS_H + +#include +#include + +namespace benchmark { + +// Return the CPU usage of the current process +double ProcessCPUUsage(); + +// Return the CPU usage of the children of the current process +double ChildrenCPUUsage(); + +// Return the CPU usage of the current thread +double ThreadCPUUsage(); + +#if defined(HAVE_STEADY_CLOCK) +template +struct ChooseSteadyClock { + typedef std::chrono::high_resolution_clock type; +}; + +template <> +struct ChooseSteadyClock { + typedef std::chrono::steady_clock type; +}; +#endif + +struct ChooseClockType { +#if defined(HAVE_STEADY_CLOCK) + typedef ChooseSteadyClock<>::type type; +#else + typedef std::chrono::high_resolution_clock type; +#endif +}; + +inline double ChronoClockNow() { + typedef ChooseClockType::type ClockType; + using FpSeconds = std::chrono::duration; + return FpSeconds(ClockType::now().time_since_epoch()).count(); +} + +std::string LocalDateTimeString(); + +} // end namespace benchmark + +#endif // BENCHMARK_TIMERS_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..b55612b --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,170 @@ +# Enable the tests + +find_package(Threads REQUIRED) +include(CheckCXXCompilerFlag) + +# NOTE: Some tests use `` to perform the test. Therefore we must +# strip -DNDEBUG from the default CMake flags in DEBUG mode. +string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) +if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) + add_definitions( -UNDEBUG ) + add_definitions(-DTEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS) + # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines. + foreach (flags_var_to_scrub + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_MINSIZEREL) + string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " + "${flags_var_to_scrub}" "${${flags_var_to_scrub}}") + endforeach() +endif() + +# NOTE: These flags must be added after find_package(Threads REQUIRED) otherwise +# they will break the configuration check. +if (DEFINED BENCHMARK_CXX_LINKER_FLAGS) + list(APPEND CMAKE_EXE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) +endif() + +add_library(output_test_helper STATIC output_test_helper.cc output_test.h) + +macro(compile_benchmark_test name) + add_executable(${name} "${name}.cc") + target_link_libraries(${name} benchmark ${CMAKE_THREAD_LIBS_INIT}) +endmacro(compile_benchmark_test) + + +macro(compile_output_test name) + add_executable(${name} "${name}.cc" output_test.h) + target_link_libraries(${name} output_test_helper benchmark + ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +endmacro(compile_output_test) + + +# Demonstration executable +compile_benchmark_test(benchmark_test) +add_test(benchmark benchmark_test --benchmark_min_time=0.01) + +compile_benchmark_test(filter_test) +macro(add_filter_test name filter expect) + add_test(${name} filter_test --benchmark_min_time=0.01 --benchmark_filter=${filter} ${expect}) + add_test(${name}_list_only filter_test --benchmark_list_tests --benchmark_filter=${filter} ${expect}) +endmacro(add_filter_test) + +add_filter_test(filter_simple "Foo" 3) +add_filter_test(filter_suffix "BM_.*" 4) +add_filter_test(filter_regex_all ".*" 5) +add_filter_test(filter_regex_blank "" 5) +add_filter_test(filter_regex_none "monkey" 0) +add_filter_test(filter_regex_wildcard ".*Foo.*" 3) +add_filter_test(filter_regex_begin "^BM_.*" 4) +add_filter_test(filter_regex_begin2 "^N" 1) +add_filter_test(filter_regex_end ".*Ba$" 1) + +compile_benchmark_test(options_test) +add_test(options_benchmarks options_test --benchmark_min_time=0.01) + +compile_benchmark_test(basic_test) +add_test(basic_benchmark basic_test --benchmark_min_time=0.01) + +compile_benchmark_test(diagnostics_test) +add_test(diagnostics_test diagnostics_test --benchmark_min_time=0.01) + +compile_benchmark_test(skip_with_error_test) +add_test(skip_with_error_test skip_with_error_test --benchmark_min_time=0.01) + +compile_benchmark_test(donotoptimize_test) +# Some of the issues with DoNotOptimize only occur when optimization is enabled +check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) +if (BENCHMARK_HAS_O3_FLAG) + set_target_properties(donotoptimize_test PROPERTIES COMPILE_FLAGS "-O3") +endif() +add_test(donotoptimize_test donotoptimize_test --benchmark_min_time=0.01) + +compile_benchmark_test(fixture_test) +add_test(fixture_test fixture_test --benchmark_min_time=0.01) + +compile_benchmark_test(register_benchmark_test) +add_test(register_benchmark_test register_benchmark_test --benchmark_min_time=0.01) + +compile_benchmark_test(map_test) +add_test(map_test map_test --benchmark_min_time=0.01) + +compile_benchmark_test(multiple_ranges_test) +add_test(multiple_ranges_test multiple_ranges_test --benchmark_min_time=0.01) + +compile_output_test(reporter_output_test) +add_test(reporter_output_test reporter_output_test --benchmark_min_time=0.01) + +compile_output_test(user_counters_test) +add_test(user_counters_test user_counters_test --benchmark_min_time=0.01) + +compile_output_test(user_counters_tabular_test) +add_test(user_counters_tabular_test user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01) + +check_cxx_compiler_flag(-std=c++03 BENCHMARK_HAS_CXX03_FLAG) +if (BENCHMARK_HAS_CXX03_FLAG) + set(CXX03_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "-std=c++11" "-std=c++03" CXX03_FLAGS "${CXX03_FLAGS}") + string(REPLACE "-std=c++0x" "-std=c++03" CXX03_FLAGS "${CXX03_FLAGS}") + + compile_benchmark_test(cxx03_test) + set_target_properties(cxx03_test + PROPERTIES COMPILE_FLAGS "${CXX03_FLAGS}") + add_test(cxx03 cxx03_test --benchmark_min_time=0.01) +endif() + +# Attempt to work around flaky test failures when running on Appveyor servers. +if (DEFINED ENV{APPVEYOR}) + set(COMPLEXITY_MIN_TIME "0.5") +else() + set(COMPLEXITY_MIN_TIME "0.01") +endif() +compile_output_test(complexity_test) +add_test(complexity_benchmark complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME}) + +# Add the coverage command(s) +if(CMAKE_BUILD_TYPE) + string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER) +endif() +if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage") + find_program(GCOV gcov) + find_program(LCOV lcov) + find_program(GENHTML genhtml) + find_program(CTEST ctest) + if (GCOV AND LCOV AND GENHTML AND CTEST AND HAVE_CXX_FLAG_COVERAGE) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/lcov/index.html + COMMAND ${LCOV} -q -z -d . + COMMAND ${LCOV} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o before.lcov -i + COMMAND ${CTEST} --force-new-ctest-process + COMMAND ${LCOV} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o after.lcov + COMMAND ${LCOV} -q -a before.lcov -a after.lcov --output-file final.lcov + COMMAND ${LCOV} -q -r final.lcov "'${CMAKE_SOURCE_DIR}/test/*'" -o final.lcov + COMMAND ${GENHTML} final.lcov -o lcov --demangle-cpp --sort -p "${CMAKE_BINARY_DIR}" -t benchmark + DEPENDS filter_test benchmark_test options_test basic_test fixture_test cxx03_test complexity_test + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running LCOV" + ) + add_custom_target(coverage + DEPENDS ${CMAKE_BINARY_DIR}/lcov/index.html + COMMENT "LCOV report at lcov/index.html" + ) + message(STATUS "Coverage command added") + else() + if (HAVE_CXX_FLAG_COVERAGE) + set(CXX_FLAG_COVERAGE_MESSAGE supported) + else() + set(CXX_FLAG_COVERAGE_MESSAGE unavailable) + endif() + message(WARNING + "Coverage not available:\n" + " gcov: ${GCOV}\n" + " lcov: ${LCOV}\n" + " genhtml: ${GENHTML}\n" + " ctest: ${CTEST}\n" + " --coverage flag: ${CXX_FLAG_COVERAGE_MESSAGE}") + endif() +endif() diff --git a/test/basic_test.cc b/test/basic_test.cc new file mode 100644 index 0000000..bc1f96d --- /dev/null +++ b/test/basic_test.cc @@ -0,0 +1,99 @@ + +#include "benchmark/benchmark.h" + +#define BASIC_BENCHMARK_TEST(x) BENCHMARK(x)->Arg(8)->Arg(512)->Arg(8192) + +void BM_empty(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(state.iterations()); + } +} +BENCHMARK(BM_empty); +BENCHMARK(BM_empty)->ThreadPerCpu(); + +void BM_spin_empty(benchmark::State& state) { + while (state.KeepRunning()) { + for (int x = 0; x < state.range(0); ++x) { + benchmark::DoNotOptimize(x); + } + } +} +BASIC_BENCHMARK_TEST(BM_spin_empty); +BASIC_BENCHMARK_TEST(BM_spin_empty)->ThreadPerCpu(); + +void BM_spin_pause_before(benchmark::State& state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + while (state.KeepRunning()) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_before); +BASIC_BENCHMARK_TEST(BM_spin_pause_before)->ThreadPerCpu(); + +void BM_spin_pause_during(benchmark::State& state) { + while (state.KeepRunning()) { + state.PauseTiming(); + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + state.ResumeTiming(); + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_during); +BASIC_BENCHMARK_TEST(BM_spin_pause_during)->ThreadPerCpu(); + +void BM_pause_during(benchmark::State& state) { + while (state.KeepRunning()) { + state.PauseTiming(); + state.ResumeTiming(); + } +} +BENCHMARK(BM_pause_during); +BENCHMARK(BM_pause_during)->ThreadPerCpu(); +BENCHMARK(BM_pause_during)->UseRealTime(); +BENCHMARK(BM_pause_during)->UseRealTime()->ThreadPerCpu(); + +void BM_spin_pause_after(benchmark::State& state) { + while (state.KeepRunning()) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_after); +BASIC_BENCHMARK_TEST(BM_spin_pause_after)->ThreadPerCpu(); + +void BM_spin_pause_before_and_after(benchmark::State& state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + while (state.KeepRunning()) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after); +BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after)->ThreadPerCpu(); + +void BM_empty_stop_start(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_empty_stop_start); +BENCHMARK(BM_empty_stop_start)->ThreadPerCpu(); + +BENCHMARK_MAIN() diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc new file mode 100644 index 0000000..7a16466 --- /dev/null +++ b/test/benchmark_test.cc @@ -0,0 +1,240 @@ +#include "benchmark/benchmark.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) +#define BENCHMARK_NOINLINE __attribute__((noinline)) +#else +#define BENCHMARK_NOINLINE +#endif + +namespace { + +int BENCHMARK_NOINLINE Factorial(uint32_t n) { + return (n == 1) ? 1 : n * Factorial(n - 1); +} + +double CalculatePi(int depth) { + double pi = 0.0; + for (int i = 0; i < depth; ++i) { + double numerator = static_cast(((i % 2) * 2) - 1); + double denominator = static_cast((2 * i) - 1); + pi += numerator / denominator; + } + return (pi - 1.0) * 4; +} + +std::set ConstructRandomSet(int size) { + std::set s; + for (int i = 0; i < size; ++i) s.insert(i); + return s; +} + +std::mutex test_vector_mu; +std::vector* test_vector = nullptr; + +} // end namespace + +static void BM_Factorial(benchmark::State& state) { + int fac_42 = 0; + while (state.KeepRunning()) fac_42 = Factorial(8); + // Prevent compiler optimizations + std::stringstream ss; + ss << fac_42; + state.SetLabel(ss.str()); +} +BENCHMARK(BM_Factorial); +BENCHMARK(BM_Factorial)->UseRealTime(); + +static void BM_CalculatePiRange(benchmark::State& state) { + double pi = 0.0; + while (state.KeepRunning()) pi = CalculatePi(state.range(0)); + std::stringstream ss; + ss << pi; + state.SetLabel(ss.str()); +} +BENCHMARK_RANGE(BM_CalculatePiRange, 1, 1024 * 1024); + +static void BM_CalculatePi(benchmark::State& state) { + static const int depth = 1024; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(CalculatePi(depth)); + } +} +BENCHMARK(BM_CalculatePi)->Threads(8); +BENCHMARK(BM_CalculatePi)->ThreadRange(1, 32); +BENCHMARK(BM_CalculatePi)->ThreadPerCpu(); + +static void BM_SetInsert(benchmark::State& state) { + while (state.KeepRunning()) { + state.PauseTiming(); + std::set data = ConstructRandomSet(state.range(0)); + state.ResumeTiming(); + for (int j = 0; j < state.range(1); ++j) data.insert(rand()); + } + state.SetItemsProcessed(state.iterations() * state.range(1)); + state.SetBytesProcessed(state.iterations() * state.range(1) * sizeof(int)); +} +BENCHMARK(BM_SetInsert)->Ranges({{1 << 10, 8 << 10}, {1, 10}}); + +template +static void BM_Sequential(benchmark::State& state) { + ValueType v = 42; + while (state.KeepRunning()) { + Container c; + for (int i = state.range(0); --i;) c.push_back(v); + } + const size_t items_processed = state.iterations() * state.range(0); + state.SetItemsProcessed(items_processed); + state.SetBytesProcessed(items_processed * sizeof(v)); +} +BENCHMARK_TEMPLATE2(BM_Sequential, std::vector, int) + ->Range(1 << 0, 1 << 10); +BENCHMARK_TEMPLATE(BM_Sequential, std::list)->Range(1 << 0, 1 << 10); +// Test the variadic version of BENCHMARK_TEMPLATE in C++11 and beyond. +#if __cplusplus >= 201103L +BENCHMARK_TEMPLATE(BM_Sequential, std::vector, int)->Arg(512); +#endif + +static void BM_StringCompare(benchmark::State& state) { + std::string s1(state.range(0), '-'); + std::string s2(state.range(0), '-'); + while (state.KeepRunning()) benchmark::DoNotOptimize(s1.compare(s2)); +} +BENCHMARK(BM_StringCompare)->Range(1, 1 << 20); + +static void BM_SetupTeardown(benchmark::State& state) { + if (state.thread_index == 0) { + // No need to lock test_vector_mu here as this is running single-threaded. + test_vector = new std::vector(); + } + int i = 0; + while (state.KeepRunning()) { + std::lock_guard l(test_vector_mu); + if (i % 2 == 0) + test_vector->push_back(i); + else + test_vector->pop_back(); + ++i; + } + if (state.thread_index == 0) { + delete test_vector; + } +} +BENCHMARK(BM_SetupTeardown)->ThreadPerCpu(); + +static void BM_LongTest(benchmark::State& state) { + double tracker = 0.0; + while (state.KeepRunning()) { + for (int i = 0; i < state.range(0); ++i) + benchmark::DoNotOptimize(tracker += i); + } +} +BENCHMARK(BM_LongTest)->Range(1 << 16, 1 << 28); + +static void BM_ParallelMemset(benchmark::State& state) { + int size = state.range(0) / static_cast(sizeof(int)); + int thread_size = size / state.threads; + int from = thread_size * state.thread_index; + int to = from + thread_size; + + if (state.thread_index == 0) { + test_vector = new std::vector(size); + } + + while (state.KeepRunning()) { + for (int i = from; i < to; i++) { + // No need to lock test_vector_mu as ranges + // do not overlap between threads. + benchmark::DoNotOptimize(test_vector->at(i) = 1); + } + } + + if (state.thread_index == 0) { + delete test_vector; + } +} +BENCHMARK(BM_ParallelMemset)->Arg(10 << 20)->ThreadRange(1, 4); + +static void BM_ManualTiming(benchmark::State& state) { + size_t slept_for = 0; + int microseconds = state.range(0); + std::chrono::duration sleep_duration{ + static_cast(microseconds)}; + + while (state.KeepRunning()) { + auto start = std::chrono::high_resolution_clock::now(); + // Simulate some useful workload with a sleep + std::this_thread::sleep_for( + std::chrono::duration_cast(sleep_duration)); + auto end = std::chrono::high_resolution_clock::now(); + + auto elapsed = + std::chrono::duration_cast>(end - start); + + state.SetIterationTime(elapsed.count()); + slept_for += microseconds; + } + state.SetItemsProcessed(slept_for); +} +BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseRealTime(); +BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseManualTime(); + +#if __cplusplus >= 201103L + +template +void BM_with_args(benchmark::State& state, Args&&...) { + while (state.KeepRunning()) { + } +} +BENCHMARK_CAPTURE(BM_with_args, int_test, 42, 43, 44); +BENCHMARK_CAPTURE(BM_with_args, string_and_pair_test, std::string("abc"), + std::pair(42, 3.8)); + +void BM_non_template_args(benchmark::State& state, int, double) { + while(state.KeepRunning()) {} +} +BENCHMARK_CAPTURE(BM_non_template_args, basic_test, 0, 0); + +#endif // __cplusplus >= 201103L + +static void BM_DenseThreadRanges(benchmark::State& st) { + switch (st.range(0)) { + case 1: + assert(st.threads == 1 || st.threads == 2 || st.threads == 3); + break; + case 2: + assert(st.threads == 1 || st.threads == 3 || st.threads == 4); + break; + case 3: + assert(st.threads == 5 || st.threads == 8 || st.threads == 11 || + st.threads == 14); + break; + default: + assert(false && "Invalid test case number"); + } + while (st.KeepRunning()) { + } +} +BENCHMARK(BM_DenseThreadRanges)->Arg(1)->DenseThreadRange(1, 3); +BENCHMARK(BM_DenseThreadRanges)->Arg(2)->DenseThreadRange(1, 4, 2); +BENCHMARK(BM_DenseThreadRanges)->Arg(3)->DenseThreadRange(5, 14, 3); + +BENCHMARK_MAIN() diff --git a/test/complexity_test.cc b/test/complexity_test.cc new file mode 100644 index 0000000..62d1154 --- /dev/null +++ b/test/complexity_test.cc @@ -0,0 +1,167 @@ +#undef NDEBUG +#include +#include +#include +#include +#include +#include "benchmark/benchmark.h" +#include "output_test.h" + +namespace { + +#define ADD_COMPLEXITY_CASES(...) \ + int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__) + +int AddComplexityTest(std::string big_o_test_name, std::string rms_test_name, + std::string big_o) { + SetSubstitutions({{"%bigo_name", big_o_test_name}, + {"%rms_name", rms_test_name}, + {"%bigo_str", "[ ]* %float " + big_o}, + {"%bigo", big_o}, + {"%rms", "[ ]*[0-9]+ %"}}); + AddCases( + TC_ConsoleOut, + {{"^%bigo_name %bigo_str %bigo_str[ ]*$"}, + {"^%bigo_name", MR_Not}, // Assert we we didn't only matched a name. + {"^%rms_name %rms %rms[ ]*$", MR_Next}}); + AddCases(TC_JSONOut, {{"\"name\": \"%bigo_name\",$"}, + {"\"cpu_coefficient\": [0-9]+,$", MR_Next}, + {"\"real_coefficient\": [0-9]{1,5},$", MR_Next}, + {"\"big_o\": \"%bigo\",$", MR_Next}, + {"\"time_unit\": \"ns\"$", MR_Next}, + {"}", MR_Next}, + {"\"name\": \"%rms_name\",$"}, + {"\"rms\": %float$", MR_Next}, + {"}", MR_Next}}); + AddCases(TC_CSVOut, {{"^\"%bigo_name\",,%float,%float,%bigo,,,,,$"}, + {"^\"%bigo_name\"", MR_Not}, + {"^\"%rms_name\",,%float,%float,,,,,,$", MR_Next}}); + return 0; +} + +} // end namespace + +// ========================================================================= // +// --------------------------- Testing BigO O(1) --------------------------- // +// ========================================================================= // + +void BM_Complexity_O1(benchmark::State& state) { + while (state.KeepRunning()) { + for (int i = 0; i < 1024; ++i) { + benchmark::DoNotOptimize(&i); + } + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1); +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(); +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity([](int) { + return 1.0; +}); + +const char *big_o_1_test_name = "BM_Complexity_O1_BigO"; +const char *rms_o_1_test_name = "BM_Complexity_O1_RMS"; +const char *enum_big_o_1 = "\\([0-9]+\\)"; +// FIXME: Tolerate both '(1)' and 'lgN' as output when the complexity is auto +// deduced. +// See https://github.com/google/benchmark/issues/272 +const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)"; +const char *lambda_big_o_1 = "f\\(N\\)"; + +// Add enum tests +ADD_COMPLEXITY_CASES(big_o_1_test_name, rms_o_1_test_name, enum_big_o_1); + +// Add auto enum tests +ADD_COMPLEXITY_CASES(big_o_1_test_name, rms_o_1_test_name, auto_big_o_1); + +// Add lambda tests +ADD_COMPLEXITY_CASES(big_o_1_test_name, rms_o_1_test_name, lambda_big_o_1); + +// ========================================================================= // +// --------------------------- Testing BigO O(N) --------------------------- // +// ========================================================================= // + +std::vector ConstructRandomVector(int size) { + std::vector v; + v.reserve(size); + for (int i = 0; i < size; ++i) { + v.push_back(std::rand() % size); + } + return v; +} + +void BM_Complexity_O_N(benchmark::State& state) { + auto v = ConstructRandomVector(state.range(0)); + const int item_not_in_vector = + state.range(0) * 2; // Test worst case scenario (item not in vector) + while (state.KeepRunning()) { + benchmark::DoNotOptimize(std::find(v.begin(), v.end(), item_not_in_vector)); + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(benchmark::oN); +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity([](int n) -> double { return n; }); +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(); + +const char *big_o_n_test_name = "BM_Complexity_O_N_BigO"; +const char *rms_o_n_test_name = "BM_Complexity_O_N_RMS"; +const char *enum_auto_big_o_n = "N"; +const char *lambda_big_o_n = "f\\(N\\)"; + +// Add enum tests +ADD_COMPLEXITY_CASES(big_o_n_test_name, rms_o_n_test_name, enum_auto_big_o_n); + +// Add lambda tests +ADD_COMPLEXITY_CASES(big_o_n_test_name, rms_o_n_test_name, lambda_big_o_n); + +// ========================================================================= // +// ------------------------- Testing BigO O(N*lgN) ------------------------- // +// ========================================================================= // + +static void BM_Complexity_O_N_log_N(benchmark::State& state) { + auto v = ConstructRandomVector(state.range(0)); + while (state.KeepRunning()) { + std::sort(v.begin(), v.end()); + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(benchmark::oNLogN); +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity([](int n) { return n * log2(n); }); +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(); + +const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_BigO"; +const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_RMS"; +const char *enum_auto_big_o_n_lg_n = "NlgN"; +const char *lambda_big_o_n_lg_n = "f\\(N\\)"; + +// Add enum tests +ADD_COMPLEXITY_CASES(big_o_n_lg_n_test_name, rms_o_n_lg_n_test_name, + enum_auto_big_o_n_lg_n); + +// Add lambda tests +ADD_COMPLEXITY_CASES(big_o_n_lg_n_test_name, rms_o_n_lg_n_test_name, + lambda_big_o_n_lg_n); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char *argv[]) { RunOutputTests(argc, argv); } diff --git a/test/cxx03_test.cc b/test/cxx03_test.cc new file mode 100644 index 0000000..a79d964 --- /dev/null +++ b/test/cxx03_test.cc @@ -0,0 +1,48 @@ +#undef NDEBUG +#include +#include + +#include "benchmark/benchmark.h" + +#if __cplusplus >= 201103L +#error C++11 or greater detected. Should be C++03. +#endif + +void BM_empty(benchmark::State& state) { + while (state.KeepRunning()) { + volatile std::size_t x = state.iterations(); + ((void)x); + } +} +BENCHMARK(BM_empty); + +// The new C++11 interface for args/ranges requires initializer list support. +// Therefore we provide the old interface to support C++03. +void BM_old_arg_range_interface(benchmark::State& state) { + assert((state.range(0) == 1 && state.range(1) == 2) || + (state.range(0) == 5 && state.range(1) == 6)); + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_old_arg_range_interface)->ArgPair(1, 2)->RangePair(5, 5, 6, 6); + +template +void BM_template2(benchmark::State& state) { + BM_empty(state); +} +BENCHMARK_TEMPLATE2(BM_template2, int, long); + +template +void BM_template1(benchmark::State& state) { + BM_empty(state); +} +BENCHMARK_TEMPLATE(BM_template1, long); +BENCHMARK_TEMPLATE1(BM_template1, int); + +void BM_counters(benchmark::State& state) { + BM_empty(state); + state.counters["Foo"] = 2; +} +BENCHMARK(BM_counters); + +BENCHMARK_MAIN() diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc new file mode 100644 index 0000000..7aac806 --- /dev/null +++ b/test/diagnostics_test.cc @@ -0,0 +1,64 @@ +// Testing: +// State::PauseTiming() +// State::ResumeTiming() +// Test that CHECK's within these function diagnose when they are called +// outside of the KeepRunning() loop. +// +// NOTE: Users should NOT include or use src/check.h. This is only done in +// order to test library internals. + +#include +#include + +#include "../src/check.h" +#include "benchmark/benchmark.h" + +#if defined(__GNUC__) && !defined(__EXCEPTIONS) +#define TEST_HAS_NO_EXCEPTIONS +#endif + +void TestHandler() { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::logic_error(""); +#else + std::abort(); +#endif +} + +void try_invalid_pause_resume(benchmark::State& state) { +#if !defined(TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS) && !defined(TEST_HAS_NO_EXCEPTIONS) + try { + state.PauseTiming(); + std::abort(); + } catch (std::logic_error const&) { + } + try { + state.ResumeTiming(); + std::abort(); + } catch (std::logic_error const&) { + } +#else + (void)state; // avoid unused warning +#endif +} + +void BM_diagnostic_test(benchmark::State& state) { + static bool called_once = false; + + if (called_once == false) try_invalid_pause_resume(state); + + while (state.KeepRunning()) { + benchmark::DoNotOptimize(state.iterations()); + } + + if (called_once == false) try_invalid_pause_resume(state); + + called_once = true; +} +BENCHMARK(BM_diagnostic_test); + +int main(int argc, char* argv[]) { + benchmark::internal::GetAbortHandler() = &TestHandler; + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc new file mode 100644 index 0000000..a705654 --- /dev/null +++ b/test/donotoptimize_test.cc @@ -0,0 +1,52 @@ +#include "benchmark/benchmark.h" + +#include + +namespace { +#if defined(__GNUC__) +std::uint64_t double_up(const std::uint64_t x) __attribute__((const)); +#endif +std::uint64_t double_up(const std::uint64_t x) { return x * 2; } +} + +// Using DoNotOptimize on types like BitRef seem to cause a lot of problems +// with the inline assembly on both GCC and Clang. +struct BitRef { + int index; + unsigned char &byte; + +public: + static BitRef Make() { + static unsigned char arr[2] = {}; + BitRef b(1, arr[0]); + return b; + } +private: + BitRef(int i, unsigned char& b) : index(i), byte(b) {} +}; + +int main(int, char*[]) { + // this test verifies compilation of DoNotOptimize() for some types + + char buffer8[8]; + benchmark::DoNotOptimize(buffer8); + + char buffer20[20]; + benchmark::DoNotOptimize(buffer20); + + char buffer1024[1024]; + benchmark::DoNotOptimize(buffer1024); + benchmark::DoNotOptimize(&buffer1024[0]); + + int x = 123; + benchmark::DoNotOptimize(x); + benchmark::DoNotOptimize(&x); + benchmark::DoNotOptimize(x += 42); + + benchmark::DoNotOptimize(double_up(x)); + + // These tests are to e + benchmark::DoNotOptimize(BitRef::Make()); + BitRef lval = BitRef::Make(); + benchmark::DoNotOptimize(lval); +} diff --git a/test/filter_test.cc b/test/filter_test.cc new file mode 100644 index 0000000..3a20529 --- /dev/null +++ b/test/filter_test.cc @@ -0,0 +1,104 @@ +#include "benchmark/benchmark.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual bool ReportContext(const Context& context) { + return ConsoleReporter::ReportContext(context); + }; + + virtual void ReportRuns(const std::vector& report) { + ++count_; + ConsoleReporter::ReportRuns(report); + }; + + TestReporter() : count_(0) {} + + virtual ~TestReporter() {} + + size_t GetCount() const { return count_; } + + private: + mutable size_t count_; +}; + +} // end namespace + +static void NoPrefix(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(NoPrefix); + +static void BM_Foo(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_Foo); + +static void BM_Bar(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_Bar); + +static void BM_FooBar(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_FooBar); + +static void BM_FooBa(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_FooBa); + +int main(int argc, char **argv) { + bool list_only = false; + for (int i = 0; i < argc; ++i) + list_only |= std::string(argv[i]).find("--benchmark_list_tests") != + std::string::npos; + + benchmark::Initialize(&argc, argv); + + TestReporter test_reporter; + const size_t returned_count = + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + if (argc == 2) { + // Make sure we ran all of the tests + std::stringstream ss(argv[1]); + size_t expected_return; + ss >> expected_return; + + if (returned_count != expected_return) { + std::cerr << "ERROR: Expected " << expected_return + << " tests to match the filter but returned_count = " + << returned_count << std::endl; + return -1; + } + + const size_t expected_reports = list_only ? 0 : expected_return; + const size_t reports_count = test_reporter.GetCount(); + if (reports_count != expected_reports) { + std::cerr << "ERROR: Expected " << expected_reports + << " tests to be run but reported_count = " << reports_count + << std::endl; + return -1; + } + } + + return 0; +} diff --git a/test/fixture_test.cc b/test/fixture_test.cc new file mode 100644 index 0000000..bbc2f95 --- /dev/null +++ b/test/fixture_test.cc @@ -0,0 +1,49 @@ + +#include "benchmark/benchmark.h" + +#include +#include + +class MyFixture : public ::benchmark::Fixture { + public: + void SetUp(const ::benchmark::State& state) { + if (state.thread_index == 0) { + assert(data.get() == nullptr); + data.reset(new int(42)); + } + } + + void TearDown(const ::benchmark::State& state) { + if (state.thread_index == 0) { + assert(data.get() != nullptr); + data.reset(); + } + } + + ~MyFixture() { assert(data == nullptr); } + + std::unique_ptr data; +}; + +BENCHMARK_F(MyFixture, Foo)(benchmark::State &st) { + assert(data.get() != nullptr); + assert(*data == 42); + while (st.KeepRunning()) { + } +} + +BENCHMARK_DEFINE_F(MyFixture, Bar)(benchmark::State& st) { + if (st.thread_index == 0) { + assert(data.get() != nullptr); + assert(*data == 42); + } + while (st.KeepRunning()) { + assert(data.get() != nullptr); + assert(*data == 42); + } + st.SetItemsProcessed(st.range(0)); +} +BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42); +BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42)->ThreadPerCpu(); + +BENCHMARK_MAIN() diff --git a/test/map_test.cc b/test/map_test.cc new file mode 100644 index 0000000..83457c9 --- /dev/null +++ b/test/map_test.cc @@ -0,0 +1,56 @@ +#include "benchmark/benchmark.h" + +#include +#include + +namespace { + +std::map ConstructRandomMap(int size) { + std::map m; + for (int i = 0; i < size; ++i) { + m.insert(std::make_pair(rand() % size, rand() % size)); + } + return m; +} + +} // namespace + +// Basic version. +static void BM_MapLookup(benchmark::State& state) { + const int size = state.range(0); + while (state.KeepRunning()) { + state.PauseTiming(); + std::map m = ConstructRandomMap(size); + state.ResumeTiming(); + for (int i = 0; i < size; ++i) { + benchmark::DoNotOptimize(m.find(rand() % size)); + } + } + state.SetItemsProcessed(state.iterations() * size); +} +BENCHMARK(BM_MapLookup)->Range(1 << 3, 1 << 12); + +// Using fixtures. +class MapFixture : public ::benchmark::Fixture { + public: + void SetUp(const ::benchmark::State& st) { + m = ConstructRandomMap(st.range(0)); + } + + void TearDown(const ::benchmark::State&) { m.clear(); } + + std::map m; +}; + +BENCHMARK_DEFINE_F(MapFixture, Lookup)(benchmark::State& state) { + const int size = state.range(0); + while (state.KeepRunning()) { + for (int i = 0; i < size; ++i) { + benchmark::DoNotOptimize(m.find(rand() % size)); + } + } + state.SetItemsProcessed(state.iterations() * size); +} +BENCHMARK_REGISTER_F(MapFixture, Lookup)->Range(1 << 3, 1 << 12); + +BENCHMARK_MAIN() diff --git a/test/multiple_ranges_test.cc b/test/multiple_ranges_test.cc new file mode 100644 index 0000000..8e67b3b --- /dev/null +++ b/test/multiple_ranges_test.cc @@ -0,0 +1,74 @@ +#include "benchmark/benchmark.h" + +#include +#include + +class MultipleRangesFixture : public ::benchmark::Fixture { + public: + MultipleRangesFixture() + : expectedValues({{1, 3, 5}, + {1, 3, 8}, + {1, 3, 15}, + {2, 3, 5}, + {2, 3, 8}, + {2, 3, 15}, + {1, 4, 5}, + {1, 4, 8}, + {1, 4, 15}, + {2, 4, 5}, + {2, 4, 8}, + {2, 4, 15}, + {1, 7, 5}, + {1, 7, 8}, + {1, 7, 15}, + {2, 7, 5}, + {2, 7, 8}, + {2, 7, 15}, + {7, 6, 3}}) {} + + void SetUp(const ::benchmark::State& state) { + std::vector ranges = {state.range(0), state.range(1), state.range(2)}; + + assert(expectedValues.find(ranges) != expectedValues.end()); + + actualValues.insert(ranges); + } + + virtual ~MultipleRangesFixture() { + assert(actualValues.size() == expectedValues.size()); + } + + std::set> expectedValues; + std::set> actualValues; +}; + +BENCHMARK_DEFINE_F(MultipleRangesFixture, Empty)(benchmark::State& state) { + while (state.KeepRunning()) { + int product = state.range(0) * state.range(1) * state.range(2); + for (int x = 0; x < product; x++) { + benchmark::DoNotOptimize(x); + } + } +} + +BENCHMARK_REGISTER_F(MultipleRangesFixture, Empty) + ->RangeMultiplier(2) + ->Ranges({{1, 2}, {3, 7}, {5, 15}}) + ->Args({7, 6, 3}); + +void BM_CheckDefaultArgument(benchmark::State& state) { + // Test that the 'range()' without an argument is the same as 'range(0)'. + assert(state.range() == state.range(0)); + assert(state.range() != state.range(1)); + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_CheckDefaultArgument)->Ranges({{1, 5}, {6, 10}}); + +static void BM_MultipleRanges(benchmark::State& st) { + while (st.KeepRunning()) { + } +} +BENCHMARK(BM_MultipleRanges)->Ranges({{5, 5}, {6, 6}}); + +BENCHMARK_MAIN() diff --git a/test/options_test.cc b/test/options_test.cc new file mode 100644 index 0000000..8eac068 --- /dev/null +++ b/test/options_test.cc @@ -0,0 +1,65 @@ +#include "benchmark/benchmark.h" +#include +#include + +#if defined(NDEBUG) +#undef NDEBUG +#endif +#include + +void BM_basic(benchmark::State& state) { + while (state.KeepRunning()) { + } +} + +void BM_basic_slow(benchmark::State& state) { + std::chrono::milliseconds sleep_duration(state.range(0)); + while (state.KeepRunning()) { + std::this_thread::sleep_for( + std::chrono::duration_cast(sleep_duration)); + } +} + +BENCHMARK(BM_basic); +BENCHMARK(BM_basic)->Arg(42); +BENCHMARK(BM_basic_slow)->Arg(10)->Unit(benchmark::kNanosecond); +BENCHMARK(BM_basic_slow)->Arg(100)->Unit(benchmark::kMicrosecond); +BENCHMARK(BM_basic_slow)->Arg(1000)->Unit(benchmark::kMillisecond); +BENCHMARK(BM_basic)->Range(1, 8); +BENCHMARK(BM_basic)->RangeMultiplier(2)->Range(1, 8); +BENCHMARK(BM_basic)->DenseRange(10, 15); +BENCHMARK(BM_basic)->Args({42, 42}); +BENCHMARK(BM_basic)->Ranges({{64, 512}, {64, 512}}); +BENCHMARK(BM_basic)->MinTime(0.7); +BENCHMARK(BM_basic)->UseRealTime(); +BENCHMARK(BM_basic)->ThreadRange(2, 4); +BENCHMARK(BM_basic)->ThreadPerCpu(); +BENCHMARK(BM_basic)->Repetitions(3); + +void CustomArgs(benchmark::internal::Benchmark* b) { + for (int i = 0; i < 10; ++i) { + b->Arg(i); + } +} + +BENCHMARK(BM_basic)->Apply(CustomArgs); + +void BM_explicit_iteration_count(benchmark::State& st) { + // Test that benchmarks specified with an explicit iteration count are + // only run once. + static bool invoked_before = false; + assert(!invoked_before); + invoked_before = true; + + // Test that the requested iteration count is respected. + assert(st.max_iterations == 42); + size_t actual_iterations = 0; + while (st.KeepRunning()) + ++actual_iterations; + assert(st.iterations() == st.max_iterations); + assert(st.iterations() == 42); + +} +BENCHMARK(BM_explicit_iteration_count)->Iterations(42); + +BENCHMARK_MAIN() diff --git a/test/output_test.h b/test/output_test.h new file mode 100644 index 0000000..897a138 --- /dev/null +++ b/test/output_test.h @@ -0,0 +1,201 @@ +#ifndef TEST_OUTPUT_TEST_H +#define TEST_OUTPUT_TEST_H + +#undef NDEBUG +#include +#include +#include +#include +#include +#include +#include + +#include "../src/re.h" +#include "benchmark/benchmark.h" + +#define CONCAT2(x, y) x##y +#define CONCAT(x, y) CONCAT2(x, y) + +#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__) + +#define SET_SUBSTITUTIONS(...) \ + int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__) + +enum MatchRules { + MR_Default, // Skip non-matching lines until a match is found. + MR_Next, // Match must occur on the next line. + MR_Not // No line between the current position and the next match matches + // the regex +}; + +struct TestCase { + TestCase(std::string re, int rule = MR_Default); + + std::string regex_str; + int match_rule; + std::string substituted_regex; + std::shared_ptr regex; +}; + +enum TestCaseID { + TC_ConsoleOut, + TC_ConsoleErr, + TC_JSONOut, + TC_JSONErr, + TC_CSVOut, + TC_CSVErr, + + TC_NumID // PRIVATE +}; + +// Add a list of test cases to be run against the output specified by +// 'ID' +int AddCases(TestCaseID ID, std::initializer_list il); + +// Add or set a list of substitutions to be performed on constructed regex's +// See 'output_test_helper.cc' for a list of default substitutions. +int SetSubstitutions( + std::initializer_list> il); + +// Run all output tests. +void RunOutputTests(int argc, char* argv[]); + +// ========================================================================= // +// ------------------------- Results checking ------------------------------ // +// ========================================================================= // + +// Call this macro to register a benchmark for checking its results. This +// should be all that's needed. It subscribes a function to check the (CSV) +// results of a benchmark. This is done only after verifying that the output +// strings are really as expected. +// bm_name_pattern: a name or a regex pattern which will be matched against +// all the benchmark names. Matching benchmarks +// will be the subject of a call to checker_function +// checker_function: should be of type ResultsCheckFn (see below) +#define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \ + size_t CONCAT(dummy, __LINE__) = AddChecker(bm_name_pattern, checker_function) + +struct Results; +typedef std::function< void(Results const&) > ResultsCheckFn; + +size_t AddChecker(const char* bm_name_pattern, ResultsCheckFn fn); + +// Class holding the results of a benchmark. +// It is passed in calls to checker functions. +struct Results { + + // the benchmark name + std::string name; + // the benchmark fields + std::map< std::string, std::string > values; + + Results(const std::string& n) : name(n) {} + + int NumThreads() const; + + typedef enum { kCpuTime, kRealTime } BenchmarkTime; + + // get cpu_time or real_time in seconds + double GetTime(BenchmarkTime which) const; + + // get the real_time duration of the benchmark in seconds. + // it is better to use fuzzy float checks for this, as the float + // ASCII formatting is lossy. + double DurationRealTime() const { + return GetAs< double >("iterations") * GetTime(kRealTime); + } + // get the cpu_time duration of the benchmark in seconds + double DurationCPUTime() const { + return GetAs< double >("iterations") * GetTime(kCpuTime); + } + + // get the string for a result by name, or nullptr if the name + // is not found + const std::string* Get(const char* entry_name) const { + auto it = values.find(entry_name); + if(it == values.end()) return nullptr; + return &it->second; + } + + // get a result by name, parsed as a specific type. + // NOTE: for counters, use GetCounterAs instead. + template + T GetAs(const char* entry_name) const; + + // counters are written as doubles, so they have to be read first + // as a double, and only then converted to the asked type. + template + T GetCounterAs(const char* entry_name) const { + double dval = GetAs< double >(entry_name); + T tval = static_cast< T >(dval); + return tval; + } +}; + +template +T Results::GetAs(const char* entry_name) const { + auto *sv = Get(entry_name); + CHECK(sv != nullptr && !sv->empty()); + std::stringstream ss; + ss << *sv; + T out; + ss >> out; + CHECK(!ss.fail()); + return out; +} + +//---------------------------------- +// Macros to help in result checking. Do not use them with arguments causing +// side-effects. + +#define _CHECK_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value) \ + CONCAT(CHECK_, relationship) \ + (entry.getfn< var_type >(var_name), (value)) << "\n" \ + << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \ + << __FILE__ << ":" << __LINE__ << ": " \ + << "expected (" << #var_type << ")" << (var_name) \ + << "=" << (entry).getfn< var_type >(var_name) \ + << " to be " #relationship " to " << (value) << "\n" + +// check with tolerance. eps_factor is the tolerance window, which is +// interpreted relative to value (eg, 0.1 means 10% of value). +#define _CHECK_FLOAT_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value, eps_factor) \ + CONCAT(CHECK_FLOAT_, relationship) \ + (entry.getfn< var_type >(var_name), (value), (eps_factor) * (value)) << "\n" \ + << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \ + << __FILE__ << ":" << __LINE__ << ": " \ + << "expected (" << #var_type << ")" << (var_name) \ + << "=" << (entry).getfn< var_type >(var_name) \ + << " to be " #relationship " to " << (value) << "\n" \ + << __FILE__ << ":" << __LINE__ << ": " \ + << "with tolerance of " << (eps_factor) * (value) \ + << " (" << (eps_factor)*100. << "%), " \ + << "but delta was " << ((entry).getfn< var_type >(var_name) - (value)) \ + << " (" << (((entry).getfn< var_type >(var_name) - (value)) \ + / \ + ((value) > 1.e-5 || value < -1.e-5 ? value : 1.e-5)*100.) \ + << "%)" + +#define CHECK_RESULT_VALUE(entry, var_type, var_name, relationship, value) \ + _CHECK_RESULT_VALUE(entry, GetAs, var_type, var_name, relationship, value) + +#define CHECK_COUNTER_VALUE(entry, var_type, var_name, relationship, value) \ + _CHECK_RESULT_VALUE(entry, GetCounterAs, var_type, var_name, relationship, value) + +#define CHECK_FLOAT_RESULT_VALUE(entry, var_name, relationship, value, eps_factor) \ + _CHECK_FLOAT_RESULT_VALUE(entry, GetAs, double, var_name, relationship, value, eps_factor) + +#define CHECK_FLOAT_COUNTER_VALUE(entry, var_name, relationship, value, eps_factor) \ + _CHECK_FLOAT_RESULT_VALUE(entry, GetCounterAs, double, var_name, relationship, value, eps_factor) + +// ========================================================================= // +// --------------------------- Misc Utilities ------------------------------ // +// ========================================================================= // + +namespace { + +const char* const dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; + +} // end namespace + +#endif // TEST_OUTPUT_TEST_H diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc new file mode 100644 index 0000000..24746f6 --- /dev/null +++ b/test/output_test_helper.cc @@ -0,0 +1,423 @@ +#include +#include +#include +#include +#include + +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include "../src/re.h" // NOTE: re.h is for internal use only +#include "output_test.h" +#include "../src/benchmark_api_internal.h" + +// ========================================================================= // +// ------------------------------ Internals -------------------------------- // +// ========================================================================= // +namespace internal { +namespace { + +using TestCaseList = std::vector; + +// Use a vector because the order elements are added matters during iteration. +// std::map/unordered_map don't guarantee that. +// For example: +// SetSubstitutions({{"%HelloWorld", "Hello"}, {"%Hello", "Hi"}}); +// Substitute("%HelloWorld") // Always expands to Hello. +using SubMap = std::vector>; + +TestCaseList& GetTestCaseList(TestCaseID ID) { + // Uses function-local statics to ensure initialization occurs + // before first use. + static TestCaseList lists[TC_NumID]; + return lists[ID]; +} + +SubMap& GetSubstitutions() { + // Don't use 'dec_re' from header because it may not yet be initialized. + static std::string safe_dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; + static SubMap map = { + {"%float", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"}, + // human-readable float + {"%hrfloat", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?[kMGTPEZYmunpfazy]?"}, + {"%int", "[ ]*[0-9]+"}, + {" %s ", "[ ]+"}, + {"%time", "[ ]*[0-9]{1,5} ns"}, + {"%console_report", "[ ]*[0-9]{1,5} ns [ ]*[0-9]{1,5} ns [ ]*[0-9]+"}, + {"%console_us_report", "[ ]*[0-9] us [ ]*[0-9] us [ ]*[0-9]+"}, + {"%csv_header", + "name,iterations,real_time,cpu_time,time_unit,bytes_per_second," + "items_per_second,label,error_occurred,error_message"}, + {"%csv_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,,,,,"}, + {"%csv_us_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",us,,,,,"}, + {"%csv_bytes_report", + "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re + ",,,,"}, + {"%csv_items_report", + "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,," + safe_dec_re + ",,,"}, + {"%csv_bytes_items_report", + "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re + + "," + safe_dec_re + ",,,"}, + {"%csv_label_report_begin", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,,,"}, + {"%csv_label_report_end", ",,"}}; + return map; +} + +std::string PerformSubstitutions(std::string source) { + SubMap const& subs = GetSubstitutions(); + using SizeT = std::string::size_type; + for (auto const& KV : subs) { + SizeT pos; + SizeT next_start = 0; + while ((pos = source.find(KV.first, next_start)) != std::string::npos) { + next_start = pos + KV.second.size(); + source.replace(pos, KV.first.size(), KV.second); + } + } + return source; +} + +void CheckCase(std::stringstream& remaining_output, TestCase const& TC, + TestCaseList const& not_checks) { + std::string first_line; + bool on_first = true; + std::string line; + while (remaining_output.eof() == false) { + CHECK(remaining_output.good()); + std::getline(remaining_output, line); + if (on_first) { + first_line = line; + on_first = false; + } + for (const auto& NC : not_checks) { + CHECK(!NC.regex->Match(line)) + << "Unexpected match for line \"" << line << "\" for MR_Not regex \"" + << NC.regex_str << "\"" + << "\n actual regex string \"" << TC.substituted_regex << "\"" + << "\n started matching near: " << first_line; + } + if (TC.regex->Match(line)) return; + CHECK(TC.match_rule != MR_Next) + << "Expected line \"" << line << "\" to match regex \"" << TC.regex_str + << "\"" + << "\n actual regex string \"" << TC.substituted_regex << "\"" + << "\n started matching near: " << first_line; + } + CHECK(remaining_output.eof() == false) + << "End of output reached before match for regex \"" << TC.regex_str + << "\" was found" + << "\n actual regex string \"" << TC.substituted_regex << "\"" + << "\n started matching near: " << first_line; +} + +void CheckCases(TestCaseList const& checks, std::stringstream& output) { + std::vector not_checks; + for (size_t i = 0; i < checks.size(); ++i) { + const auto& TC = checks[i]; + if (TC.match_rule == MR_Not) { + not_checks.push_back(TC); + continue; + } + CheckCase(output, TC, not_checks); + not_checks.clear(); + } +} + +class TestReporter : public benchmark::BenchmarkReporter { + public: + TestReporter(std::vector reps) + : reporters_(reps) {} + + virtual bool ReportContext(const Context& context) { + bool last_ret = false; + bool first = true; + for (auto rep : reporters_) { + bool new_ret = rep->ReportContext(context); + CHECK(first || new_ret == last_ret) + << "Reports return different values for ReportContext"; + first = false; + last_ret = new_ret; + } + (void)first; + return last_ret; + } + + void ReportRuns(const std::vector& report) { + for (auto rep : reporters_) rep->ReportRuns(report); + } + void Finalize() { + for (auto rep : reporters_) rep->Finalize(); + } + + private: + std::vector reporters_; +}; +} + +} // end namespace internal + +// ========================================================================= // +// -------------------------- Results checking ----------------------------- // +// ========================================================================= // + +namespace internal { + +// Utility class to manage subscribers for checking benchmark results. +// It works by parsing the CSV output to read the results. +class ResultsChecker { + public: + + struct PatternAndFn : public TestCase { // reusing TestCase for its regexes + PatternAndFn(const std::string& rx, ResultsCheckFn fn_) + : TestCase(rx), fn(fn_) {} + ResultsCheckFn fn; + }; + + std::vector< PatternAndFn > check_patterns; + std::vector< Results > results; + std::vector< std::string > field_names; + + void Add(const std::string& entry_pattern, ResultsCheckFn fn); + + void CheckResults(std::stringstream& output); + + private: + + void SetHeader_(const std::string& csv_header); + void SetValues_(const std::string& entry_csv_line); + + std::vector< std::string > SplitCsv_(const std::string& line); + +}; + +// store the static ResultsChecker in a function to prevent initialization +// order problems +ResultsChecker& GetResultsChecker() { + static ResultsChecker rc; + return rc; +} + +// add a results checker for a benchmark +void ResultsChecker::Add(const std::string& entry_pattern, ResultsCheckFn fn) { + check_patterns.emplace_back(entry_pattern, fn); +} + +// check the results of all subscribed benchmarks +void ResultsChecker::CheckResults(std::stringstream& output) { + // first reset the stream to the start + { + auto start = std::ios::streampos(0); + // clear before calling tellg() + output.clear(); + // seek to zero only when needed + if(output.tellg() > start) output.seekg(start); + // and just in case + output.clear(); + } + // now go over every line and publish it to the ResultsChecker + std::string line; + bool on_first = true; + while (output.eof() == false) { + CHECK(output.good()); + std::getline(output, line); + if (on_first) { + SetHeader_(line); // this is important + on_first = false; + continue; + } + SetValues_(line); + } + // finally we can call the subscribed check functions + for(const auto& p : check_patterns) { + VLOG(2) << "--------------------------------\n"; + VLOG(2) << "checking for benchmarks matching " << p.regex_str << "...\n"; + for(const auto& r : results) { + if(!p.regex->Match(r.name)) { + VLOG(2) << p.regex_str << " is not matched by " << r.name << "\n"; + continue; + } else { + VLOG(2) << p.regex_str << " is matched by " << r.name << "\n"; + } + VLOG(1) << "Checking results of " << r.name << ": ... \n"; + p.fn(r); + VLOG(1) << "Checking results of " << r.name << ": OK.\n"; + } + } +} + +// prepare for the names in this header +void ResultsChecker::SetHeader_(const std::string& csv_header) { + field_names = SplitCsv_(csv_header); +} + +// set the values for a benchmark +void ResultsChecker::SetValues_(const std::string& entry_csv_line) { + if(entry_csv_line.empty()) return; // some lines are empty + CHECK(!field_names.empty()); + auto vals = SplitCsv_(entry_csv_line); + CHECK_EQ(vals.size(), field_names.size()); + results.emplace_back(vals[0]); // vals[0] is the benchmark name + auto &entry = results.back(); + for (size_t i = 1, e = vals.size(); i < e; ++i) { + entry.values[field_names[i]] = vals[i]; + } +} + +// a quick'n'dirty csv splitter (eliminating quotes) +std::vector< std::string > ResultsChecker::SplitCsv_(const std::string& line) { + std::vector< std::string > out; + if(line.empty()) return out; + if(!field_names.empty()) out.reserve(field_names.size()); + size_t prev = 0, pos = line.find_first_of(','), curr = pos; + while(pos != line.npos) { + CHECK(curr > 0); + if(line[prev] == '"') ++prev; + if(line[curr-1] == '"') --curr; + out.push_back(line.substr(prev, curr-prev)); + prev = pos + 1; + pos = line.find_first_of(',', pos + 1); + curr = pos; + } + curr = line.size(); + if(line[prev] == '"') ++prev; + if(line[curr-1] == '"') --curr; + out.push_back(line.substr(prev, curr-prev)); + return out; +} + +} // end namespace internal + +size_t AddChecker(const char* bm_name, ResultsCheckFn fn) +{ + auto &rc = internal::GetResultsChecker(); + rc.Add(bm_name, fn); + return rc.results.size(); +} + +int Results::NumThreads() const { + auto pos = name.find("/threads:"); + if(pos == name.npos) return 1; + auto end = name.find('/', pos + 9); + std::stringstream ss; + ss << name.substr(pos + 9, end); + int num = 1; + ss >> num; + CHECK(!ss.fail()); + return num; +} + +double Results::GetTime(BenchmarkTime which) const { + CHECK(which == kCpuTime || which == kRealTime); + const char *which_str = which == kCpuTime ? "cpu_time" : "real_time"; + double val = GetAs< double >(which_str); + auto unit = Get("time_unit"); + CHECK(unit); + if(*unit == "ns") { + return val * 1.e-9; + } else if(*unit == "us") { + return val * 1.e-6; + } else if(*unit == "ms") { + return val * 1.e-3; + } else if(*unit == "s") { + return val; + } else { + CHECK(1 == 0) << "unknown time unit: " << *unit; + return 0; + } +} + +// ========================================================================= // +// -------------------------- Public API Definitions------------------------ // +// ========================================================================= // + +TestCase::TestCase(std::string re, int rule) + : regex_str(std::move(re)), + match_rule(rule), + substituted_regex(internal::PerformSubstitutions(regex_str)), + regex(std::make_shared()) { + std::string err_str; + regex->Init(substituted_regex,& err_str); + CHECK(err_str.empty()) << "Could not construct regex \"" << substituted_regex + << "\"" + << "\n originally \"" << regex_str << "\"" + << "\n got error: " << err_str; +} + +int AddCases(TestCaseID ID, std::initializer_list il) { + auto& L = internal::GetTestCaseList(ID); + L.insert(L.end(), il); + return 0; +} + +int SetSubstitutions( + std::initializer_list> il) { + auto& subs = internal::GetSubstitutions(); + for (auto KV : il) { + bool exists = false; + KV.second = internal::PerformSubstitutions(KV.second); + for (auto& EKV : subs) { + if (EKV.first == KV.first) { + EKV.second = std::move(KV.second); + exists = true; + break; + } + } + if (!exists) subs.push_back(std::move(KV)); + } + return 0; +} + +void RunOutputTests(int argc, char* argv[]) { + using internal::GetTestCaseList; + benchmark::Initialize(&argc, argv); + auto options = benchmark::internal::GetOutputOptions(/*force_no_color*/true); + benchmark::ConsoleReporter CR(options); + benchmark::JSONReporter JR; + benchmark::CSVReporter CSVR; + struct ReporterTest { + const char* name; + std::vector& output_cases; + std::vector& error_cases; + benchmark::BenchmarkReporter& reporter; + std::stringstream out_stream; + std::stringstream err_stream; + + ReporterTest(const char* n, std::vector& out_tc, + std::vector& err_tc, + benchmark::BenchmarkReporter& br) + : name(n), output_cases(out_tc), error_cases(err_tc), reporter(br) { + reporter.SetOutputStream(&out_stream); + reporter.SetErrorStream(&err_stream); + } + } TestCases[] = { + {"ConsoleReporter", GetTestCaseList(TC_ConsoleOut), + GetTestCaseList(TC_ConsoleErr), CR}, + {"JSONReporter", GetTestCaseList(TC_JSONOut), GetTestCaseList(TC_JSONErr), + JR}, + {"CSVReporter", GetTestCaseList(TC_CSVOut), GetTestCaseList(TC_CSVErr), + CSVR}, + }; + + // Create the test reporter and run the benchmarks. + std::cout << "Running benchmarks...\n"; + internal::TestReporter test_rep({&CR, &JR, &CSVR}); + benchmark::RunSpecifiedBenchmarks(&test_rep); + + for (auto& rep_test : TestCases) { + std::string msg = std::string("\nTesting ") + rep_test.name + " Output\n"; + std::string banner(msg.size() - 1, '-'); + std::cout << banner << msg << banner << "\n"; + + std::cerr << rep_test.err_stream.str(); + std::cout << rep_test.out_stream.str(); + + internal::CheckCases(rep_test.error_cases, rep_test.err_stream); + internal::CheckCases(rep_test.output_cases, rep_test.out_stream); + + std::cout << "\n"; + } + + // now that we know the output is as expected, we can dispatch + // the checks to subscribees. + auto &csv = TestCases[2]; + // would use == but gcc spits a warning + CHECK(std::strcmp(csv.name, "CSVReporter") == 0); + internal::GetResultsChecker().CheckResults(csv.out_stream); +} diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc new file mode 100644 index 0000000..2769b7a --- /dev/null +++ b/test/register_benchmark_test.cc @@ -0,0 +1,182 @@ + +#undef NDEBUG +#include +#include + +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include "benchmark/benchmark.h" + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual void ReportRuns(const std::vector& report) { + all_runs_.insert(all_runs_.end(), begin(report), end(report)); + ConsoleReporter::ReportRuns(report); + } + + std::vector all_runs_; +}; + +struct TestCase { + std::string name; + const char* label; + // Note: not explicit as we rely on it being converted through ADD_CASES. + TestCase(const char* xname) : TestCase(xname, nullptr) {} + TestCase(const char* xname, const char* xlabel) + : name(xname), label(xlabel) {} + + typedef benchmark::BenchmarkReporter::Run Run; + + void CheckRun(Run const& run) const { + CHECK(name == run.benchmark_name) << "expected " << name << " got " + << run.benchmark_name; + if (label) { + CHECK(run.report_label == label) << "expected " << label << " got " + << run.report_label; + } else { + CHECK(run.report_label == ""); + } + } +}; + +std::vector ExpectedResults; + +int AddCases(std::initializer_list const& v) { + for (auto N : v) { + ExpectedResults.push_back(N); + } + return 0; +} + +#define CONCAT(x, y) CONCAT2(x, y) +#define CONCAT2(x, y) x##y +#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) + +} // end namespace + +typedef benchmark::internal::Benchmark* ReturnVal; + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with no additional arguments +//----------------------------------------------------------------------------// +void BM_function(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_function); +ReturnVal dummy = benchmark::RegisterBenchmark( + "BM_function_manual_registration", BM_function); +ADD_CASES({"BM_function"}, {"BM_function_manual_registration"}); + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with additional arguments +// Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they +// reject the variadic pack expansion of lambda captures. +//----------------------------------------------------------------------------// +#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + +void BM_extra_args(benchmark::State& st, const char* label) { + while (st.KeepRunning()) { + } + st.SetLabel(label); +} +int RegisterFromFunction() { + std::pair cases[] = { + {"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}}; + for (auto const& c : cases) + benchmark::RegisterBenchmark(c.first, &BM_extra_args, c.second); + return 0; +} +int dummy2 = RegisterFromFunction(); +ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}); + +#endif // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with different callable types +//----------------------------------------------------------------------------// + +struct CustomFixture { + void operator()(benchmark::State& st) { + while (st.KeepRunning()) { + } + } +}; + +void TestRegistrationAtRuntime() { +#ifdef BENCHMARK_HAS_CXX11 + { + CustomFixture fx; + benchmark::RegisterBenchmark("custom_fixture", fx); + AddCases({"custom_fixture"}); + } +#endif +#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + { + const char* x = "42"; + auto capturing_lam = [=](benchmark::State& st) { + while (st.KeepRunning()) { + } + st.SetLabel(x); + }; + benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam); + AddCases({{"lambda_benchmark", x}}); + } +#endif +} + +// Test that all benchmarks, registered at either during static init or runtime, +// are run and the results are passed to the reported. +void RunTestOne() { + TestRegistrationAtRuntime(); + + TestReporter test_reporter; + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); +} + +// Test that ClearRegisteredBenchmarks() clears all previously registered +// benchmarks. +// Also test that new benchmarks can be registered and ran afterwards. +void RunTestTwo() { + assert(ExpectedResults.size() != 0 && + "must have at least one registered benchmark"); + ExpectedResults.clear(); + benchmark::ClearRegisteredBenchmarks(); + + TestReporter test_reporter; + size_t num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter); + assert(num_ran == 0); + assert(test_reporter.all_runs_.begin() == test_reporter.all_runs_.end()); + + TestRegistrationAtRuntime(); + num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter); + assert(num_ran == ExpectedResults.size()); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); +} + +int main(int argc, char* argv[]) { + benchmark::Initialize(&argc, argv); + + RunTestOne(); + RunTestTwo(); +} diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc new file mode 100644 index 0000000..4a48143 --- /dev/null +++ b/test/reporter_output_test.cc @@ -0,0 +1,256 @@ + +#undef NDEBUG +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// ========================================================================= // +// ---------------------- Testing Prologue Output -------------------------- // +// ========================================================================= // + +ADD_CASES(TC_ConsoleOut, + {{"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations$", MR_Next}, + {"^[-]+$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"%csv_header"}}); + +// ========================================================================= // +// ------------------------ Testing Basic Output --------------------------- // +// ========================================================================= // + +void BM_basic(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_basic); + +ADD_CASES(TC_ConsoleOut, {{"^BM_basic %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_basic\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\"$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_basic\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Bytes per Second Output ---------------- // +// ========================================================================= // + +void BM_bytes_per_second(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.SetBytesProcessed(1); +} +BENCHMARK(BM_bytes_per_second); + +ADD_CASES(TC_ConsoleOut, + {{"^BM_bytes_per_second %console_report +%floatB/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_bytes_per_second\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bytes_per_second\": %int$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_bytes_per_second\",%csv_bytes_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Items per Second Output ---------------- // +// ========================================================================= // + +void BM_items_per_second(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.SetItemsProcessed(1); +} +BENCHMARK(BM_items_per_second); + +ADD_CASES(TC_ConsoleOut, + {{"^BM_items_per_second %console_report +%float items/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_items_per_second\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"items_per_second\": %int$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_items_per_second\",%csv_items_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Label Output --------------------------- // +// ========================================================================= // + +void BM_label(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.SetLabel("some label"); +} +BENCHMARK(BM_label); + +ADD_CASES(TC_ConsoleOut, {{"^BM_label %console_report some label$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_label\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"label\": \"some label\"$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_label\",%csv_label_report_begin\"some " + "label\"%csv_label_report_end$"}}); + +// ========================================================================= // +// ------------------------ Testing Error Output --------------------------- // +// ========================================================================= // + +void BM_error(benchmark::State& state) { + state.SkipWithError("message"); + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_error); +ADD_CASES(TC_ConsoleOut, {{"^BM_error[ ]+ERROR OCCURRED: 'message'$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_error\",$"}, + {"\"error_occurred\": true,$", MR_Next}, + {"\"error_message\": \"message\",$", MR_Next}}); + +ADD_CASES(TC_CSVOut, {{"^\"BM_error\",,,,,,,,true,\"message\"$"}}); + +// ========================================================================= // +// ------------------------ Testing No Arg Name Output ----------------------- +// // +// ========================================================================= // + +void BM_no_arg_name(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_no_arg_name)->Arg(3); +ADD_CASES(TC_ConsoleOut, {{"^BM_no_arg_name/3 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_no_arg_name/3\",$"}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_no_arg_name/3\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Arg Name Output ----------------------- // +// ========================================================================= // + +void BM_arg_name(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_arg_name)->ArgName("first")->Arg(3); +ADD_CASES(TC_ConsoleOut, {{"^BM_arg_name/first:3 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_arg_name/first:3\",$"}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_arg_name/first:3\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Arg Names Output ----------------------- // +// ========================================================================= // + +void BM_arg_names(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_arg_names)->Args({2, 5, 4})->ArgNames({"first", "", "third"}); +ADD_CASES(TC_ConsoleOut, + {{"^BM_arg_names/first:2/5/third:4 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_arg_names/first:2/5/third:4\",$"}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_arg_names/first:2/5/third:4\",%csv_report$"}}); + +// ========================================================================= // +// ----------------------- Testing Complexity Output ----------------------- // +// ========================================================================= // + +void BM_Complexity_O1(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1); +SET_SUBSTITUTIONS({{"%bigOStr", "[ ]* %float \\([0-9]+\\)"}, + {"%RMS", "[ ]*[0-9]+ %"}}); +ADD_CASES(TC_ConsoleOut, {{"^BM_Complexity_O1_BigO %bigOStr %bigOStr[ ]*$"}, + {"^BM_Complexity_O1_RMS %RMS %RMS[ ]*$"}}); + +// ========================================================================= // +// ----------------------- Testing Aggregate Output ------------------------ // +// ========================================================================= // + +// Test that non-aggregate data is printed by default +void BM_Repeat(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_Repeat)->Repetitions(3); +ADD_CASES(TC_ConsoleOut, {{"^BM_Repeat/repeats:3 %console_report$"}, + {"^BM_Repeat/repeats:3 %console_report$"}, + {"^BM_Repeat/repeats:3 %console_report$"}, + {"^BM_Repeat/repeats:3_mean %console_report$"}, + {"^BM_Repeat/repeats:3_stddev %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Repeat/repeats:3\",$"}, + {"\"name\": \"BM_Repeat/repeats:3\",$"}, + {"\"name\": \"BM_Repeat/repeats:3\",$"}, + {"\"name\": \"BM_Repeat/repeats:3_mean\",$"}, + {"\"name\": \"BM_Repeat/repeats:3_stddev\",$"}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Repeat/repeats:3\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3_mean\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3_stddev\",%csv_report$"}}); + +// Test that a non-repeated test still prints non-aggregate results even when +// only-aggregate reports have been requested +void BM_RepeatOnce(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_RepeatOnce)->Repetitions(1)->ReportAggregatesOnly(); +ADD_CASES(TC_ConsoleOut, {{"^BM_RepeatOnce/repeats:1 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_RepeatOnce/repeats:1\",$"}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_RepeatOnce/repeats:1\",%csv_report$"}}); + +// Test that non-aggregate data is not reported +void BM_SummaryRepeat(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->ReportAggregatesOnly(); +ADD_CASES(TC_ConsoleOut, + {{".*BM_SummaryRepeat/repeats:3 ", MR_Not}, + {"^BM_SummaryRepeat/repeats:3_mean %console_report$"}, + {"^BM_SummaryRepeat/repeats:3_stddev %console_report$"}}); +ADD_CASES(TC_JSONOut, {{".*BM_SummaryRepeat/repeats:3 ", MR_Not}, + {"\"name\": \"BM_SummaryRepeat/repeats:3_mean\",$"}, + {"\"name\": \"BM_SummaryRepeat/repeats:3_stddev\",$"}}); +ADD_CASES(TC_CSVOut, {{".*BM_SummaryRepeat/repeats:3 ", MR_Not}, + {"^\"BM_SummaryRepeat/repeats:3_mean\",%csv_report$"}, + {"^\"BM_SummaryRepeat/repeats:3_stddev\",%csv_report$"}}); + +void BM_RepeatTimeUnit(benchmark::State& state) { + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_RepeatTimeUnit) + ->Repetitions(3) + ->ReportAggregatesOnly() + ->Unit(benchmark::kMicrosecond); +ADD_CASES(TC_ConsoleOut, + {{".*BM_RepeatTimeUnit/repeats:3 ", MR_Not}, + {"^BM_RepeatTimeUnit/repeats:3_mean %console_us_report$"}, + {"^BM_RepeatTimeUnit/repeats:3_stddev %console_us_report$"}}); +ADD_CASES(TC_JSONOut, {{".*BM_RepeatTimeUnit/repeats:3 ", MR_Not}, + {"\"name\": \"BM_RepeatTimeUnit/repeats:3_mean\",$"}, + {"\"time_unit\": \"us\",?$"}, + {"\"name\": \"BM_RepeatTimeUnit/repeats:3_stddev\",$"}, + {"\"time_unit\": \"us\",?$"}}); +ADD_CASES(TC_CSVOut, + {{".*BM_RepeatTimeUnit/repeats:3 ", MR_Not}, + {"^\"BM_RepeatTimeUnit/repeats:3_mean\",%csv_us_report$"}, + {"^\"BM_RepeatTimeUnit/repeats:3_stddev\",%csv_us_report$"}}); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc new file mode 100644 index 0000000..b74d33c --- /dev/null +++ b/test/skip_with_error_test.cc @@ -0,0 +1,150 @@ + +#undef NDEBUG +#include +#include + +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include "benchmark/benchmark.h" + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual bool ReportContext(const Context& context) { + return ConsoleReporter::ReportContext(context); + }; + + virtual void ReportRuns(const std::vector& report) { + all_runs_.insert(all_runs_.end(), begin(report), end(report)); + ConsoleReporter::ReportRuns(report); + } + + TestReporter() {} + virtual ~TestReporter() {} + + mutable std::vector all_runs_; +}; + +struct TestCase { + std::string name; + bool error_occurred; + std::string error_message; + + typedef benchmark::BenchmarkReporter::Run Run; + + void CheckRun(Run const& run) const { + CHECK(name == run.benchmark_name) << "expected " << name << " got " + << run.benchmark_name; + CHECK(error_occurred == run.error_occurred); + CHECK(error_message == run.error_message); + if (error_occurred) { + // CHECK(run.iterations == 0); + } else { + CHECK(run.iterations != 0); + } + } +}; + +std::vector ExpectedResults; + +int AddCases(const char* base_name, std::initializer_list const& v) { + for (auto TC : v) { + TC.name = base_name + TC.name; + ExpectedResults.push_back(std::move(TC)); + } + return 0; +} + +#define CONCAT(x, y) CONCAT2(x, y) +#define CONCAT2(x, y) x##y +#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__) + +} // end namespace + +void BM_error_before_running(benchmark::State& state) { + state.SkipWithError("error message"); + while (state.KeepRunning()) { + assert(false); + } +} +BENCHMARK(BM_error_before_running); +ADD_CASES("BM_error_before_running", {{"", true, "error message"}}); + +void BM_error_during_running(benchmark::State& state) { + int first_iter = true; + while (state.KeepRunning()) { + if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) { + assert(first_iter); + first_iter = false; + state.SkipWithError("error message"); + } else { + state.PauseTiming(); + state.ResumeTiming(); + } + } +} +BENCHMARK(BM_error_during_running)->Arg(1)->Arg(2)->ThreadRange(1, 8); +ADD_CASES("BM_error_during_running", {{"/1/threads:1", true, "error message"}, + {"/1/threads:2", true, "error message"}, + {"/1/threads:4", true, "error message"}, + {"/1/threads:8", true, "error message"}, + {"/2/threads:1", false, ""}, + {"/2/threads:2", false, ""}, + {"/2/threads:4", false, ""}, + {"/2/threads:8", false, ""}}); + +void BM_error_after_running(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(state.iterations()); + } + if (state.thread_index <= (state.threads / 2)) + state.SkipWithError("error message"); +} +BENCHMARK(BM_error_after_running)->ThreadRange(1, 8); +ADD_CASES("BM_error_after_running", {{"/threads:1", true, "error message"}, + {"/threads:2", true, "error message"}, + {"/threads:4", true, "error message"}, + {"/threads:8", true, "error message"}}); + +void BM_error_while_paused(benchmark::State& state) { + bool first_iter = true; + while (state.KeepRunning()) { + if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) { + assert(first_iter); + first_iter = false; + state.PauseTiming(); + state.SkipWithError("error message"); + } else { + state.PauseTiming(); + state.ResumeTiming(); + } + } +} +BENCHMARK(BM_error_while_paused)->Arg(1)->Arg(2)->ThreadRange(1, 8); +ADD_CASES("BM_error_while_paused", {{"/1/threads:1", true, "error message"}, + {"/1/threads:2", true, "error message"}, + {"/1/threads:4", true, "error message"}, + {"/1/threads:8", true, "error message"}, + {"/2/threads:1", false, ""}, + {"/2/threads:2", false, ""}, + {"/2/threads:4", false, ""}, + {"/2/threads:8", false, ""}}); + +int main(int argc, char* argv[]) { + benchmark::Initialize(&argc, argv); + + TestReporter test_reporter; + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); + + return 0; +} diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc new file mode 100644 index 0000000..5fc5b4d --- /dev/null +++ b/test/user_counters_tabular_test.cc @@ -0,0 +1,250 @@ + +#undef NDEBUG + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// @todo: this checks the full output at once; the rule for +// CounterSet1 was failing because it was not matching "^[-]+$". +// @todo: check that the counters are vertically aligned. +ADD_CASES(TC_ConsoleOut, { +// keeping these lines long improves readability, so: +// clang-format off + {"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations %s Bar %s Bat %s Baz %s Foo %s Frob %s Lob$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations %s Bar %s Baz %s Foo$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations %s Bat %s Baz %s Foo$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$"}, +// clang-format on +}); +ADD_CASES(TC_CSVOut, {{"%csv_header," + "\"Bar\",\"Bat\",\"Baz\",\"Foo\",\"Frob\",\"Lob\""}}); + +// ========================================================================= // +// ------------------------- Tabular Counters Output ----------------------- // +// ========================================================================= // + +void BM_Counters_Tabular(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", { 1, bm::Counter::kAvgThreads}}, + {"Bar", { 2, bm::Counter::kAvgThreads}}, + {"Baz", { 4, bm::Counter::kAvgThreads}}, + {"Bat", { 8, bm::Counter::kAvgThreads}}, + {"Frob", {16, bm::Counter::kAvgThreads}}, + {"Lob", {32, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_Counters_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Tabular/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Bat\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float,$", MR_Next}, + {"\"Frob\": %float,$", MR_Next}, + {"\"Lob\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Tabular/threads:%int\",%csv_report," + "%float,%float,%float,%float,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckTabular(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 2); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 4); + CHECK_COUNTER_VALUE(e, int, "Bat", EQ, 8); + CHECK_COUNTER_VALUE(e, int, "Frob", EQ, 16); + CHECK_COUNTER_VALUE(e, int, "Lob", EQ, 32); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/threads:%int", &CheckTabular); + +// ========================================================================= // +// -------------------- Tabular+Rate Counters Output ----------------------- // +// ========================================================================= // + +void BM_CounterRates_Tabular(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", { 1, bm::Counter::kAvgThreadsRate}}, + {"Bar", { 2, bm::Counter::kAvgThreadsRate}}, + {"Baz", { 4, bm::Counter::kAvgThreadsRate}}, + {"Bat", { 8, bm::Counter::kAvgThreadsRate}}, + {"Frob", {16, bm::Counter::kAvgThreadsRate}}, + {"Lob", {32, bm::Counter::kAvgThreadsRate}}, + }); +} +BENCHMARK(BM_CounterRates_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_CounterRates_Tabular/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Bat\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float,$", MR_Next}, + {"\"Frob\": %float,$", MR_Next}, + {"\"Lob\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterRates_Tabular/threads:%int\",%csv_report," + "%float,%float,%float,%float,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckTabularRate(Results const& e) { + double t = e.DurationCPUTime(); + CHECK_FLOAT_COUNTER_VALUE(e, "Foo", EQ, 1./t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Bar", EQ, 2./t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Baz", EQ, 4./t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Bat", EQ, 8./t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Frob", EQ, 16./t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Lob", EQ, 32./t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_CounterRates_Tabular/threads:%int", + &CheckTabularRate); + +// ========================================================================= // +// ------------------------- Tabular Counters Output ----------------------- // +// ========================================================================= // + +// set only some of the counters +void BM_CounterSet0_Tabular(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {10, bm::Counter::kAvgThreads}}, + {"Bar", {20, bm::Counter::kAvgThreads}}, + {"Baz", {40, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_CounterSet0_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_CounterSet0_Tabular/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet0_Tabular/threads:%int\",%csv_report," + "%float,,%float,%float,,"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSet0(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 10); + CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 20); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40); +} +CHECK_BENCHMARK_RESULTS("BM_CounterSet0_Tabular", &CheckSet0); + +// again. +void BM_CounterSet1_Tabular(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {15, bm::Counter::kAvgThreads}}, + {"Bar", {25, bm::Counter::kAvgThreads}}, + {"Baz", {45, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_CounterSet1_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_CounterSet1_Tabular/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet1_Tabular/threads:%int\",%csv_report," + "%float,,%float,%float,,"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSet1(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 15); + CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 25); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 45); +} +CHECK_BENCHMARK_RESULTS("BM_CounterSet1_Tabular/threads:%int", &CheckSet1); + +// ========================================================================= // +// ------------------------- Tabular Counters Output ----------------------- // +// ========================================================================= // + +// set only some of the counters, different set now. +void BM_CounterSet2_Tabular(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {10, bm::Counter::kAvgThreads}}, + {"Bat", {30, bm::Counter::kAvgThreads}}, + {"Baz", {40, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_CounterSet2_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_CounterSet2_Tabular/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bat\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet2_Tabular/threads:%int\",%csv_report," + ",%float,%float,%float,,"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSet2(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 10); + CHECK_COUNTER_VALUE(e, int, "Bat", EQ, 30); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40); +} +CHECK_BENCHMARK_RESULTS("BM_CounterSet2_Tabular", &CheckSet2); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc new file mode 100644 index 0000000..66df48b --- /dev/null +++ b/test/user_counters_test.cc @@ -0,0 +1,217 @@ + +#undef NDEBUG + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// ========================================================================= // +// ---------------------- Testing Prologue Output -------------------------- // +// ========================================================================= // + +ADD_CASES(TC_ConsoleOut, + {{"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations UserCounters...$", MR_Next}, + {"^[-]+$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"%csv_header,\"bar\",\"foo\""}}); + +// ========================================================================= // +// ------------------------- Simple Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_Simple(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.counters["foo"] = 1; + state.counters["bar"] = 2 * (double)state.iterations(); +} +BENCHMARK(BM_Counters_Simple); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Simple %console_report bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Simple\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Simple\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSimple(Results const& e) { + double its = e.GetAs< double >("iterations"); + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + // check that the value of bar is within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2.*its, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Simple", &CheckSimple); + +// ========================================================================= // +// --------------------- Counters+Items+Bytes/s Output --------------------- // +// ========================================================================= // + +namespace { int num_calls1 = 0; } +void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.counters["foo"] = 1; + state.counters["bar"] = ++num_calls1; + state.SetBytesProcessed(364); + state.SetItemsProcessed(150); +} +BENCHMARK(BM_Counters_WithBytesAndItemsPSec); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_WithBytesAndItemsPSec %console_report " + "bar=%hrfloat foo=%hrfloat +%hrfloatB/s +%hrfloat items/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_WithBytesAndItemsPSec\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bytes_per_second\": %int,$", MR_Next}, + {"\"items_per_second\": %int,$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec\"," + "%csv_bytes_items_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckBytesAndItemsPSec(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, num_calls1); + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ, 364./t, 0.001); + CHECK_FLOAT_RESULT_VALUE(e, "items_per_second", EQ, 150./t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec", + &CheckBytesAndItemsPSec); + +// ========================================================================= // +// ------------------------- Rate Counters Output -------------------------- // +// ========================================================================= // + +void BM_Counters_Rate(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kIsRate}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kIsRate}; +} +BENCHMARK(BM_Counters_Rate); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Rate %console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Rate\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Rate\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckRate(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1./t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2./t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate); + +// ========================================================================= // +// ------------------------- Thread Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_Threads(benchmark::State& state) { + while (state.KeepRunning()) { + } + state.counters["foo"] = 1; + state.counters["bar"] = 2; +} +BENCHMARK(BM_Counters_Threads)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Threads/threads:%int %console_report bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Threads/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Threads/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckThreads(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "foo", EQ, e.NumThreads()); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2 * e.NumThreads()); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Threads/threads:%int", &CheckThreads); + +// ========================================================================= // +// ---------------------- ThreadAvg Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_AvgThreads(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreads}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreads}; +} +BENCHMARK(BM_Counters_AvgThreads)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreads/threads:%int %console_report bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_AvgThreads/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreads/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgThreads(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", + &CheckAvgThreads); + +// ========================================================================= // +// ---------------------- ThreadAvg Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_AvgThreadsRate(benchmark::State& state) { + while (state.KeepRunning()) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreadsRate}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreadsRate}; +} +BENCHMARK(BM_Counters_AvgThreadsRate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreadsRate/threads:%int %console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$"}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %int,$", MR_Next}, + {"\"cpu_time\": %int,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgThreadsRate(Results const& e) { + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1./e.DurationCPUTime(), 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2./e.DurationCPUTime(), 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int", + &CheckAvgThreadsRate); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/tools/compare_bench.py b/tools/compare_bench.py new file mode 100755 index 0000000..d54baaa --- /dev/null +++ b/tools/compare_bench.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +""" +compare_bench.py - Compare two benchmarks or their results and report the + difference. +""" +import argparse +from argparse import ArgumentParser +import sys +import gbench +from gbench import util, report +from gbench.util import * + +def check_inputs(in1, in2, flags): + """ + Perform checking on the user provided inputs and diagnose any abnormalities + """ + in1_kind, in1_err = classify_input_file(in1) + in2_kind, in2_err = classify_input_file(in2) + output_file = find_benchmark_flag('--benchmark_out=', flags) + output_type = find_benchmark_flag('--benchmark_out_format=', flags) + if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file: + print(("WARNING: '--benchmark_out=%s' will be passed to both " + "benchmarks causing it to be overwritten") % output_file) + if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0: + print("WARNING: passing --benchmark flags has no effect since both " + "inputs are JSON") + if output_type is not None and output_type != 'json': + print(("ERROR: passing '--benchmark_out_format=%s' to 'compare_bench.py`" + " is not supported.") % output_type) + sys.exit(1) + + +def main(): + parser = ArgumentParser( + description='compare the results of two benchmarks') + parser.add_argument( + 'test1', metavar='test1', type=str, nargs=1, + help='A benchmark executable or JSON output file') + parser.add_argument( + 'test2', metavar='test2', type=str, nargs=1, + help='A benchmark executable or JSON output file') + # FIXME this is a dummy argument which will never actually match + # any --benchmark flags but it helps generate a better usage message + parser.add_argument( + 'benchmark_options', metavar='benchmark_option', nargs='*', + help='Arguments to pass when running benchmark executables' + ) + args, unknown_args = parser.parse_known_args() + # Parse the command line flags + test1 = args.test1[0] + test2 = args.test2[0] + if args.benchmark_options: + print("Unrecognized positional argument arguments: '%s'" + % args.benchmark_options) + exit(1) + benchmark_options = unknown_args + check_inputs(test1, test2, benchmark_options) + # Run the benchmarks and report the results + json1 = gbench.util.run_or_load_benchmark(test1, benchmark_options) + json2 = gbench.util.run_or_load_benchmark(test2, benchmark_options) + output_lines = gbench.report.generate_difference_report(json1, json2) + print('Comparing %s to %s' % (test1, test2)) + for ln in output_lines: + print(ln) + + +if __name__ == '__main__': + main() diff --git a/tools/gbench/Inputs/test1_run1.json b/tools/gbench/Inputs/test1_run1.json new file mode 100644 index 0000000..37faed4 --- /dev/null +++ b/tools/gbench/Inputs/test1_run1.json @@ -0,0 +1,60 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_SameTimes", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_2xFaster", + "iterations": 1000, + "real_time": 50, + "cpu_time": 50, + "time_unit": "ns" + }, + { + "name": "BM_2xSlower", + "iterations": 1000, + "real_time": 50, + "cpu_time": 50, + "time_unit": "ns" + }, + { + "name": "BM_10PercentFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentSlower", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_100xSlower", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_100xFaster", + "iterations": 1000, + "real_time": 10000, + "cpu_time": 10000, + "time_unit": "ns" + } + ] +} \ No newline at end of file diff --git a/tools/gbench/Inputs/test1_run2.json b/tools/gbench/Inputs/test1_run2.json new file mode 100644 index 0000000..aed5151 --- /dev/null +++ b/tools/gbench/Inputs/test1_run2.json @@ -0,0 +1,60 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_SameTimes", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_2xFaster", + "iterations": 1000, + "real_time": 25, + "cpu_time": 25, + "time_unit": "ns" + }, + { + "name": "BM_2xSlower", + "iterations": 20833333, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentFaster", + "iterations": 1000, + "real_time": 90, + "cpu_time": 90, + "time_unit": "ns" + }, + { + "name": "BM_10PercentSlower", + "iterations": 1000, + "real_time": 110, + "cpu_time": 110, + "time_unit": "ns" + }, + { + "name": "BM_100xSlower", + "iterations": 1000, + "real_time": 10000, + "cpu_time": 10000, + "time_unit": "ns" + }, + { + "name": "BM_100xFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + } + ] +} \ No newline at end of file diff --git a/tools/gbench/__init__.py b/tools/gbench/__init__.py new file mode 100644 index 0000000..fce1a1a --- /dev/null +++ b/tools/gbench/__init__.py @@ -0,0 +1,8 @@ +"""Google Benchmark tooling""" + +__author__ = 'Eric Fiselier' +__email__ = 'eric@efcs.ca' +__versioninfo__ = (0, 5, 0) +__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' + +__all__ = [] diff --git a/tools/gbench/report.py b/tools/gbench/report.py new file mode 100644 index 0000000..015d33d --- /dev/null +++ b/tools/gbench/report.py @@ -0,0 +1,146 @@ +"""report.py - Utilities for reporting statistics about benchmark results +""" +import os + +class BenchmarkColor(object): + def __init__(self, name, code): + self.name = name + self.code = code + + def __repr__(self): + return '%s%r' % (self.__class__.__name__, + (self.name, self.code)) + + def __format__(self, format): + return self.code + +# Benchmark Colors Enumeration +BC_NONE = BenchmarkColor('NONE', '') +BC_MAGENTA = BenchmarkColor('MAGENTA', '\033[95m') +BC_CYAN = BenchmarkColor('CYAN', '\033[96m') +BC_OKBLUE = BenchmarkColor('OKBLUE', '\033[94m') +BC_HEADER = BenchmarkColor('HEADER', '\033[92m') +BC_WARNING = BenchmarkColor('WARNING', '\033[93m') +BC_WHITE = BenchmarkColor('WHITE', '\033[97m') +BC_FAIL = BenchmarkColor('FAIL', '\033[91m') +BC_ENDC = BenchmarkColor('ENDC', '\033[0m') +BC_BOLD = BenchmarkColor('BOLD', '\033[1m') +BC_UNDERLINE = BenchmarkColor('UNDERLINE', '\033[4m') + +def color_format(use_color, fmt_str, *args, **kwargs): + """ + Return the result of 'fmt_str.format(*args, **kwargs)' after transforming + 'args' and 'kwargs' according to the value of 'use_color'. If 'use_color' + is False then all color codes in 'args' and 'kwargs' are replaced with + the empty string. + """ + assert use_color is True or use_color is False + if not use_color: + args = [arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for arg in args] + kwargs = {key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for key, arg in kwargs.items()} + return fmt_str.format(*args, **kwargs) + + +def find_longest_name(benchmark_list): + """ + Return the length of the longest benchmark name in a given list of + benchmark JSON objects + """ + longest_name = 1 + for bc in benchmark_list: + if len(bc['name']) > longest_name: + longest_name = len(bc['name']) + return longest_name + + +def calculate_change(old_val, new_val): + """ + Return a float representing the decimal change between old_val and new_val. + """ + if old_val == 0 and new_val == 0: + return 0.0 + if old_val == 0: + return float(new_val - old_val) / (float(old_val + new_val) / 2) + return float(new_val - old_val) / abs(old_val) + + +def generate_difference_report(json1, json2, use_color=True): + """ + Calculate and report the difference between each test of two benchmarks + runs specified as 'json1' and 'json2'. + """ + first_col_width = find_longest_name(json1['benchmarks']) + 5 + def find_test(name): + for b in json2['benchmarks']: + if b['name'] == name: + return b + return None + first_line = "{:<{}s} Time CPU Old New".format( + 'Benchmark', first_col_width) + output_strs = [first_line, '-' * len(first_line)] + + gen = (bn for bn in json1['benchmarks'] if 'real_time' in bn and 'cpu_time' in bn) + for bn in gen: + other_bench = find_test(bn['name']) + if not other_bench: + continue + + def get_color(res): + if res > 0.05: + return BC_FAIL + elif res > -0.07: + return BC_WHITE + else: + return BC_CYAN + fmt_str = "{}{:<{}s}{endc}{}{:+9.2f}{endc}{}{:+14.2f}{endc}{:14d}{:14d}" + tres = calculate_change(bn['real_time'], other_bench['real_time']) + cpures = calculate_change(bn['cpu_time'], other_bench['cpu_time']) + output_strs += [color_format(use_color, fmt_str, + BC_HEADER, bn['name'], first_col_width, + get_color(tres), tres, get_color(cpures), cpures, + bn['cpu_time'], other_bench['cpu_time'], + endc=BC_ENDC)] + return output_strs + +############################################################################### +# Unit tests + +import unittest + +class TestReportDifference(unittest.TestCase): + def load_results(self): + import json + testInputs = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Inputs') + testOutput1 = os.path.join(testInputs, 'test1_run1.json') + testOutput2 = os.path.join(testInputs, 'test1_run2.json') + with open(testOutput1, 'r') as f: + json1 = json.load(f) + with open(testOutput2, 'r') as f: + json2 = json.load(f) + return json1, json2 + + def test_basic(self): + expect_lines = [ + ['BM_SameTimes', '+0.00', '+0.00', '10', '10'], + ['BM_2xFaster', '-0.50', '-0.50', '50', '25'], + ['BM_2xSlower', '+1.00', '+1.00', '50', '100'], + ['BM_10PercentFaster', '-0.10', '-0.10', '100', '90'], + ['BM_10PercentSlower', '+0.10', '+0.10', '100', '110'], + ['BM_100xSlower', '+99.00', '+99.00', '100', '10000'], + ['BM_100xFaster', '-0.99', '-0.99', '10000', '100'], + ] + json1, json2 = self.load_results() + output_lines_with_header = generate_difference_report(json1, json2, use_color=False) + output_lines = output_lines_with_header[2:] + print("\n".join(output_lines_with_header)) + self.assertEqual(len(output_lines), len(expect_lines)) + for i in xrange(0, len(output_lines)): + parts = [x for x in output_lines[i].split(' ') if x] + self.assertEqual(len(parts), 5) + self.assertEqual(parts, expect_lines[i]) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/gbench/util.py b/tools/gbench/util.py new file mode 100644 index 0000000..07c2377 --- /dev/null +++ b/tools/gbench/util.py @@ -0,0 +1,159 @@ +"""util.py - General utilities for running, loading, and processing benchmarks +""" +import json +import os +import tempfile +import subprocess +import sys + +# Input file type enumeration +IT_Invalid = 0 +IT_JSON = 1 +IT_Executable = 2 + +_num_magic_bytes = 2 if sys.platform.startswith('win') else 4 +def is_executable_file(filename): + """ + Return 'True' if 'filename' names a valid file which is likely + an executable. A file is considered an executable if it starts with the + magic bytes for a EXE, Mach O, or ELF file. + """ + if not os.path.isfile(filename): + return False + with open(filename, mode='rb') as f: + magic_bytes = f.read(_num_magic_bytes) + if sys.platform == 'darwin': + return magic_bytes in [ + b'\xfe\xed\xfa\xce', # MH_MAGIC + b'\xce\xfa\xed\xfe', # MH_CIGAM + b'\xfe\xed\xfa\xcf', # MH_MAGIC_64 + b'\xcf\xfa\xed\xfe', # MH_CIGAM_64 + b'\xca\xfe\xba\xbe', # FAT_MAGIC + b'\xbe\xba\xfe\xca' # FAT_CIGAM + ] + elif sys.platform.startswith('win'): + return magic_bytes == b'MZ' + else: + return magic_bytes == b'\x7FELF' + + +def is_json_file(filename): + """ + Returns 'True' if 'filename' names a valid JSON output file. + 'False' otherwise. + """ + try: + with open(filename, 'r') as f: + json.load(f) + return True + except: + pass + return False + + +def classify_input_file(filename): + """ + Return a tuple (type, msg) where 'type' specifies the classified type + of 'filename'. If 'type' is 'IT_Invalid' then 'msg' is a human readable + string represeting the error. + """ + ftype = IT_Invalid + err_msg = None + if not os.path.exists(filename): + err_msg = "'%s' does not exist" % filename + elif not os.path.isfile(filename): + err_msg = "'%s' does not name a file" % filename + elif is_executable_file(filename): + ftype = IT_Executable + elif is_json_file(filename): + ftype = IT_JSON + else: + err_msg = "'%s' does not name a valid benchmark executable or JSON file" % filename + return ftype, err_msg + + +def check_input_file(filename): + """ + Classify the file named by 'filename' and return the classification. + If the file is classified as 'IT_Invalid' print an error message and exit + the program. + """ + ftype, msg = classify_input_file(filename) + if ftype == IT_Invalid: + print("Invalid input file: %s" % msg) + sys.exit(1) + return ftype + +def find_benchmark_flag(prefix, benchmark_flags): + """ + Search the specified list of flags for a flag matching `` and + if it is found return the arg it specifies. If specified more than once the + last value is returned. If the flag is not found None is returned. + """ + assert prefix.startswith('--') and prefix.endswith('=') + result = None + for f in benchmark_flags: + if f.startswith(prefix): + result = f[len(prefix):] + return result + +def remove_benchmark_flags(prefix, benchmark_flags): + """ + Return a new list containing the specified benchmark_flags except those + with the specified prefix. + """ + assert prefix.startswith('--') and prefix.endswith('=') + return [f for f in benchmark_flags if not f.startswith(prefix)] + +def load_benchmark_results(fname): + """ + Read benchmark output from a file and return the JSON object. + REQUIRES: 'fname' names a file containing JSON benchmark output. + """ + with open(fname, 'r') as f: + return json.load(f) + + +def run_benchmark(exe_name, benchmark_flags): + """ + Run a benchmark specified by 'exe_name' with the specified + 'benchmark_flags'. The benchmark is run directly as a subprocess to preserve + real time console output. + RETURNS: A JSON object representing the benchmark output + """ + output_name = find_benchmark_flag('--benchmark_out=', + benchmark_flags) + is_temp_output = False + if output_name is None: + is_temp_output = True + thandle, output_name = tempfile.mkstemp() + os.close(thandle) + benchmark_flags = list(benchmark_flags) + \ + ['--benchmark_out=%s' % output_name] + + cmd = [exe_name] + benchmark_flags + print("RUNNING: %s" % ' '.join(cmd)) + exitCode = subprocess.call(cmd) + if exitCode != 0: + print('TEST FAILED...') + sys.exit(exitCode) + json_res = load_benchmark_results(output_name) + if is_temp_output: + os.unlink(output_name) + return json_res + + +def run_or_load_benchmark(filename, benchmark_flags): + """ + Get the results for a specified benchmark. If 'filename' specifies + an executable benchmark then the results are generated by running the + benchmark. Otherwise 'filename' must name a valid JSON output file, + which is loaded and the result returned. + """ + ftype = check_input_file(filename) + if ftype == IT_JSON: + return load_benchmark_results(filename) + elif ftype == IT_Executable: + return run_benchmark(filename, benchmark_flags) + else: + assert False # This branch is unreachable \ No newline at end of file From 8de46c0bd5b46213021fcb573da57b3ac17f6541 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 6 Aug 2017 22:36:28 -0400 Subject: [PATCH 22/25] Squashed 'vendor/github.com/google/googletest/' content from commit a3ac2d7f git-subtree-dir: vendor/github.com/google/googletest git-subtree-split: a3ac2d7faa9cc6d38d69321f293925f72edf6727 --- .gitignore | 2 + .travis.yml | 46 + CMakeLists.txt | 16 + README.md | 142 + appveyor.yml | 71 + googlemock/CHANGES | 126 + googlemock/CMakeLists.txt | 202 + googlemock/CONTRIBUTORS | 40 + googlemock/LICENSE | 28 + googlemock/Makefile.am | 224 + googlemock/README.md | 333 + googlemock/build-aux/.keep | 0 googlemock/configure.ac | 146 + googlemock/docs/CheatSheet.md | 562 ++ googlemock/docs/CookBook.md | 3675 ++++++++ googlemock/docs/DesignDoc.md | 280 + googlemock/docs/DevGuide.md | 132 + googlemock/docs/Documentation.md | 12 + googlemock/docs/ForDummies.md | 439 + googlemock/docs/FrequentlyAskedQuestions.md | 628 ++ googlemock/docs/KnownIssues.md | 19 + googlemock/docs/v1_5/CheatSheet.md | 525 ++ googlemock/docs/v1_5/CookBook.md | 3250 +++++++ googlemock/docs/v1_5/Documentation.md | 11 + googlemock/docs/v1_5/ForDummies.md | 439 + .../docs/v1_5/FrequentlyAskedQuestions.md | 624 ++ googlemock/docs/v1_6/CheatSheet.md | 534 ++ googlemock/docs/v1_6/CookBook.md | 3342 +++++++ googlemock/docs/v1_6/Documentation.md | 12 + googlemock/docs/v1_6/ForDummies.md | 439 + .../docs/v1_6/FrequentlyAskedQuestions.md | 628 ++ googlemock/docs/v1_7/CheatSheet.md | 556 ++ googlemock/docs/v1_7/CookBook.md | 3432 ++++++++ googlemock/docs/v1_7/Documentation.md | 12 + googlemock/docs/v1_7/ForDummies.md | 439 + .../docs/v1_7/FrequentlyAskedQuestions.md | 628 ++ googlemock/include/gmock/gmock-actions.h | 1205 +++ .../include/gmock/gmock-cardinalities.h | 147 + .../include/gmock/gmock-generated-actions.h | 2377 +++++ .../gmock/gmock-generated-actions.h.pump | 794 ++ .../gmock/gmock-generated-function-mockers.h | 1095 +++ .../gmock-generated-function-mockers.h.pump | 291 + .../include/gmock/gmock-generated-matchers.h | 2179 +++++ .../gmock/gmock-generated-matchers.h.pump | 672 ++ .../gmock/gmock-generated-nice-strict.h | 397 + .../gmock/gmock-generated-nice-strict.h.pump | 161 + googlemock/include/gmock/gmock-matchers.h | 4399 ++++++++++ googlemock/include/gmock/gmock-more-actions.h | 246 + .../include/gmock/gmock-more-matchers.h | 58 + .../include/gmock/gmock-spec-builders.h | 1847 ++++ googlemock/include/gmock/gmock.h | 94 + .../internal/custom/gmock-generated-actions.h | 8 + .../custom/gmock-generated-actions.h.pump | 10 + .../gmock/internal/custom/gmock-matchers.h | 39 + .../gmock/internal/custom/gmock-port.h | 46 + .../internal/gmock-generated-internal-utils.h | 279 + .../gmock-generated-internal-utils.h.pump | 136 + .../gmock/internal/gmock-internal-utils.h | 511 ++ .../include/gmock/internal/gmock-port.h | 91 + googlemock/make/Makefile | 101 + googlemock/msvc/2005/gmock.sln | 32 + googlemock/msvc/2005/gmock.vcproj | 191 + googlemock/msvc/2005/gmock_config.vsprops | 15 + googlemock/msvc/2005/gmock_main.vcproj | 187 + googlemock/msvc/2005/gmock_test.vcproj | 201 + googlemock/msvc/2010/gmock.sln | 32 + googlemock/msvc/2010/gmock.vcxproj | 82 + googlemock/msvc/2010/gmock_config.props | 19 + googlemock/msvc/2010/gmock_main.vcxproj | 88 + googlemock/msvc/2010/gmock_test.vcxproj | 101 + googlemock/msvc/2015/gmock.sln | 32 + googlemock/msvc/2015/gmock.vcxproj | 84 + googlemock/msvc/2015/gmock_config.props | 19 + googlemock/msvc/2015/gmock_main.vcxproj | 90 + googlemock/msvc/2015/gmock_test.vcxproj | 103 + googlemock/scripts/fuse_gmock_files.py | 240 + googlemock/scripts/generator/LICENSE | 203 + googlemock/scripts/generator/README | 35 + googlemock/scripts/generator/README.cppclean | 115 + googlemock/scripts/generator/cpp/__init__.py | 0 googlemock/scripts/generator/cpp/ast.py | 1733 ++++ .../scripts/generator/cpp/gmock_class.py | 227 + .../scripts/generator/cpp/gmock_class_test.py | 448 + googlemock/scripts/generator/cpp/keywords.py | 59 + googlemock/scripts/generator/cpp/tokenize.py | 287 + googlemock/scripts/generator/cpp/utils.py | 41 + googlemock/scripts/generator/gmock_gen.py | 31 + googlemock/scripts/gmock-config.in | 303 + googlemock/scripts/gmock_doctor.py | 640 ++ googlemock/scripts/upload.py | 1387 +++ googlemock/scripts/upload_gmock.py | 78 + googlemock/src/gmock-all.cc | 47 + googlemock/src/gmock-cardinalities.cc | 156 + googlemock/src/gmock-internal-utils.cc | 174 + googlemock/src/gmock-matchers.cc | 498 ++ googlemock/src/gmock-spec-builders.cc | 823 ++ googlemock/src/gmock.cc | 183 + googlemock/src/gmock_main.cc | 54 + googlemock/test/gmock-actions_test.cc | 1411 +++ googlemock/test/gmock-cardinalities_test.cc | 428 + .../test/gmock-generated-actions_test.cc | 1228 +++ .../gmock-generated-function-mockers_test.cc | 622 ++ .../gmock-generated-internal-utils_test.cc | 127 + .../test/gmock-generated-matchers_test.cc | 1286 +++ googlemock/test/gmock-internal-utils_test.cc | 699 ++ googlemock/test/gmock-matchers_test.cc | 5652 ++++++++++++ googlemock/test/gmock-more-actions_test.cc | 708 ++ googlemock/test/gmock-nice-strict_test.cc | 424 + googlemock/test/gmock-port_test.cc | 43 + googlemock/test/gmock-spec-builders_test.cc | 2644 ++++++ googlemock/test/gmock_all_test.cc | 51 + googlemock/test/gmock_ex_test.cc | 81 + googlemock/test/gmock_leak_test.py | 108 + googlemock/test/gmock_leak_test_.cc | 100 + googlemock/test/gmock_link2_test.cc | 40 + googlemock/test/gmock_link_test.cc | 40 + googlemock/test/gmock_link_test.h | 669 ++ googlemock/test/gmock_output_test.py | 180 + googlemock/test/gmock_output_test_.cc | 291 + googlemock/test/gmock_output_test_golden.txt | 310 + googlemock/test/gmock_stress_test.cc | 322 + googlemock/test/gmock_test.cc | 220 + googlemock/test/gmock_test_utils.py | 112 + googletest/.gitignore | 2 + googletest/CHANGES | 157 + googletest/CMakeLists.txt | 286 + googletest/CONTRIBUTORS | 37 + googletest/LICENSE | 28 + googletest/Makefile.am | 310 + googletest/README.md | 280 + googletest/build-aux/.keep | 0 googletest/cmake/internal_utils.cmake | 254 + googletest/codegear/gtest.cbproj | 138 + googletest/codegear/gtest.groupproj | 54 + googletest/codegear/gtest_all.cc | 38 + googletest/codegear/gtest_link.cc | 40 + googletest/codegear/gtest_main.cbproj | 82 + googletest/codegear/gtest_unittest.cbproj | 88 + googletest/configure.ac | 68 + googletest/docs/AdvancedGuide.md | 2182 +++++ googletest/docs/DevGuide.md | 126 + googletest/docs/Documentation.md | 14 + googletest/docs/FAQ.md | 1087 +++ googletest/docs/Primer.md | 502 ++ googletest/docs/PumpManual.md | 177 + googletest/docs/Samples.md | 14 + googletest/docs/V1_5_AdvancedGuide.md | 2096 +++++ googletest/docs/V1_5_Documentation.md | 12 + googletest/docs/V1_5_FAQ.md | 886 ++ googletest/docs/V1_5_Primer.md | 497 ++ googletest/docs/V1_5_PumpManual.md | 177 + googletest/docs/V1_5_XcodeGuide.md | 93 + googletest/docs/V1_6_AdvancedGuide.md | 2178 +++++ googletest/docs/V1_6_Documentation.md | 14 + googletest/docs/V1_6_FAQ.md | 1038 +++ googletest/docs/V1_6_Primer.md | 501 ++ googletest/docs/V1_6_PumpManual.md | 177 + googletest/docs/V1_6_Samples.md | 14 + googletest/docs/V1_6_XcodeGuide.md | 93 + googletest/docs/V1_7_AdvancedGuide.md | 2181 +++++ googletest/docs/V1_7_Documentation.md | 14 + googletest/docs/V1_7_FAQ.md | 1082 +++ googletest/docs/V1_7_Primer.md | 501 ++ googletest/docs/V1_7_PumpManual.md | 177 + googletest/docs/V1_7_Samples.md | 14 + googletest/docs/V1_7_XcodeGuide.md | 93 + googletest/docs/XcodeGuide.md | 93 + googletest/include/gtest/gtest-death-test.h | 294 + googletest/include/gtest/gtest-message.h | 250 + googletest/include/gtest/gtest-param-test.h | 1444 +++ .../include/gtest/gtest-param-test.h.pump | 510 ++ googletest/include/gtest/gtest-printers.h | 993 +++ googletest/include/gtest/gtest-spi.h | 232 + googletest/include/gtest/gtest-test-part.h | 179 + googletest/include/gtest/gtest-typed-test.h | 263 + googletest/include/gtest/gtest.h | 2236 +++++ googletest/include/gtest/gtest_pred_impl.h | 358 + googletest/include/gtest/gtest_prod.h | 58 + .../gtest/internal/custom/gtest-port.h | 69 + .../gtest/internal/custom/gtest-printers.h | 42 + .../include/gtest/internal/custom/gtest.h | 41 + .../internal/gtest-death-test-internal.h | 319 + .../include/gtest/internal/gtest-filepath.h | 206 + .../include/gtest/internal/gtest-internal.h | 1238 +++ .../include/gtest/internal/gtest-linked_ptr.h | 243 + .../internal/gtest-param-util-generated.h | 5146 +++++++++++ .../gtest-param-util-generated.h.pump | 286 + .../include/gtest/internal/gtest-param-util.h | 731 ++ .../include/gtest/internal/gtest-port-arch.h | 93 + .../include/gtest/internal/gtest-port.h | 2554 ++++++ .../include/gtest/internal/gtest-string.h | 167 + .../include/gtest/internal/gtest-tuple.h | 1020 +++ .../include/gtest/internal/gtest-tuple.h.pump | 347 + .../include/gtest/internal/gtest-type-util.h | 3331 +++++++ .../gtest/internal/gtest-type-util.h.pump | 297 + googletest/m4/acx_pthread.m4 | 363 + googletest/m4/gtest.m4 | 74 + googletest/make/Makefile | 82 + googletest/msvc/gtest-md.sln | 45 + googletest/msvc/gtest-md.vcproj | 126 + googletest/msvc/gtest.sln | 45 + googletest/msvc/gtest.vcproj | 126 + googletest/msvc/gtest_main-md.vcproj | 129 + googletest/msvc/gtest_main.vcproj | 129 + googletest/msvc/gtest_prod_test-md.vcproj | 164 + googletest/msvc/gtest_prod_test.vcproj | 164 + googletest/msvc/gtest_unittest-md.vcproj | 147 + googletest/msvc/gtest_unittest.vcproj | 147 + googletest/samples/prime_tables.h | 123 + googletest/samples/sample1.cc | 68 + googletest/samples/sample1.h | 43 + googletest/samples/sample10_unittest.cc | 144 + googletest/samples/sample1_unittest.cc | 153 + googletest/samples/sample2.cc | 56 + googletest/samples/sample2.h | 85 + googletest/samples/sample2_unittest.cc | 109 + googletest/samples/sample3-inl.h | 172 + googletest/samples/sample3_unittest.cc | 151 + googletest/samples/sample4.cc | 46 + googletest/samples/sample4.h | 53 + googletest/samples/sample4_unittest.cc | 45 + googletest/samples/sample5_unittest.cc | 199 + googletest/samples/sample6_unittest.cc | 224 + googletest/samples/sample7_unittest.cc | 130 + googletest/samples/sample8_unittest.cc | 173 + googletest/samples/sample9_unittest.cc | 160 + googletest/scripts/common.py | 83 + googletest/scripts/fuse_gtest_files.py | 253 + googletest/scripts/gen_gtest_pred_impl.py | 730 ++ googletest/scripts/gtest-config.in | 274 + googletest/scripts/pump.py | 855 ++ googletest/scripts/release_docs.py | 158 + googletest/scripts/test/Makefile | 59 + googletest/scripts/upload.py | 1387 +++ googletest/scripts/upload_gtest.py | 78 + googletest/src/gtest-all.cc | 48 + googletest/src/gtest-death-test.cc | 1342 +++ googletest/src/gtest-filepath.cc | 387 + googletest/src/gtest-internal-inl.h | 1183 +++ googletest/src/gtest-port.cc | 1259 +++ googletest/src/gtest-printers.cc | 373 + googletest/src/gtest-test-part.cc | 110 + googletest/src/gtest-typed-test.cc | 118 + googletest/src/gtest.cc | 5388 ++++++++++++ googletest/src/gtest_main.cc | 38 + googletest/test/gtest-death-test_ex_test.cc | 93 + googletest/test/gtest-death-test_test.cc | 1427 +++ googletest/test/gtest-filepath_test.cc | 662 ++ googletest/test/gtest-linked_ptr_test.cc | 154 + googletest/test/gtest-listener_test.cc | 311 + googletest/test/gtest-message_test.cc | 159 + googletest/test/gtest-options_test.cc | 215 + googletest/test/gtest-param-test2_test.cc | 65 + googletest/test/gtest-param-test_test.cc | 1055 +++ googletest/test/gtest-param-test_test.h | 57 + googletest/test/gtest-port_test.cc | 1304 +++ googletest/test/gtest-printers_test.cc | 1635 ++++ googletest/test/gtest-test-part_test.cc | 208 + googletest/test/gtest-tuple_test.cc | 320 + googletest/test/gtest-typed-test2_test.cc | 45 + googletest/test/gtest-typed-test_test.cc | 380 + googletest/test/gtest-typed-test_test.h | 66 + googletest/test/gtest-unittest-api_test.cc | 341 + googletest/test/gtest_all_test.cc | 47 + .../test/gtest_break_on_failure_unittest.py | 212 + .../test/gtest_break_on_failure_unittest_.cc | 88 + .../test/gtest_catch_exceptions_test.py | 237 + .../test/gtest_catch_exceptions_test_.cc | 311 + googletest/test/gtest_color_test.py | 130 + googletest/test/gtest_color_test_.cc | 71 + googletest/test/gtest_env_var_test.py | 117 + googletest/test/gtest_env_var_test_.cc | 126 + googletest/test/gtest_environment_test.cc | 192 + googletest/test/gtest_filter_unittest.py | 636 ++ googletest/test/gtest_filter_unittest_.cc | 140 + googletest/test/gtest_help_test.py | 172 + googletest/test/gtest_help_test_.cc | 46 + googletest/test/gtest_list_tests_unittest.py | 207 + googletest/test/gtest_list_tests_unittest_.cc | 157 + googletest/test/gtest_main_unittest.cc | 45 + googletest/test/gtest_no_test_unittest.cc | 56 + googletest/test/gtest_output_test.py | 340 + googletest/test/gtest_output_test_.cc | 1062 +++ .../test/gtest_output_test_golden_lin.txt | 743 ++ googletest/test/gtest_pred_impl_unittest.cc | 2427 ++++++ googletest/test/gtest_premature_exit_test.cc | 127 + googletest/test/gtest_prod_test.cc | 57 + googletest/test/gtest_repeat_test.cc | 253 + googletest/test/gtest_shuffle_test.py | 325 + googletest/test/gtest_shuffle_test_.cc | 103 + googletest/test/gtest_sole_header_test.cc | 57 + googletest/test/gtest_stress_test.cc | 256 + googletest/test/gtest_test_utils.py | 320 + .../test/gtest_throw_on_failure_ex_test.cc | 92 + .../test/gtest_throw_on_failure_test.py | 171 + .../test/gtest_throw_on_failure_test_.cc | 72 + googletest/test/gtest_uninitialized_test.py | 70 + googletest/test/gtest_uninitialized_test_.cc | 43 + googletest/test/gtest_unittest.cc | 7706 +++++++++++++++++ googletest/test/gtest_xml_outfile1_test_.cc | 49 + googletest/test/gtest_xml_outfile2_test_.cc | 49 + googletest/test/gtest_xml_outfiles_test.py | 132 + googletest/test/gtest_xml_output_unittest.py | 308 + googletest/test/gtest_xml_output_unittest_.cc | 181 + googletest/test/gtest_xml_test_utils.py | 194 + googletest/test/production.cc | 36 + googletest/test/production.h | 55 + googletest/xcode/Config/DebugProject.xcconfig | 30 + .../xcode/Config/FrameworkTarget.xcconfig | 17 + googletest/xcode/Config/General.xcconfig | 41 + .../xcode/Config/ReleaseProject.xcconfig | 32 + .../xcode/Config/StaticLibraryTarget.xcconfig | 18 + googletest/xcode/Config/TestTarget.xcconfig | 8 + googletest/xcode/Resources/Info.plist | 30 + .../xcode/Samples/FrameworkSample/Info.plist | 28 + .../WidgetFramework.xcodeproj/project.pbxproj | 457 + .../xcode/Samples/FrameworkSample/runtests.sh | 62 + .../xcode/Samples/FrameworkSample/widget.cc | 63 + .../xcode/Samples/FrameworkSample/widget.h | 59 + .../Samples/FrameworkSample/widget_test.cc | 68 + googletest/xcode/Scripts/runtests.sh | 65 + googletest/xcode/Scripts/versiongenerate.py | 100 + .../xcode/gtest.xcodeproj/project.pbxproj | 1135 +++ travis.sh | 15 + 324 files changed, 153794 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 appveyor.yml create mode 100644 googlemock/CHANGES create mode 100644 googlemock/CMakeLists.txt create mode 100644 googlemock/CONTRIBUTORS create mode 100644 googlemock/LICENSE create mode 100644 googlemock/Makefile.am create mode 100644 googlemock/README.md create mode 100644 googlemock/build-aux/.keep create mode 100644 googlemock/configure.ac create mode 100644 googlemock/docs/CheatSheet.md create mode 100644 googlemock/docs/CookBook.md create mode 100644 googlemock/docs/DesignDoc.md create mode 100644 googlemock/docs/DevGuide.md create mode 100644 googlemock/docs/Documentation.md create mode 100644 googlemock/docs/ForDummies.md create mode 100644 googlemock/docs/FrequentlyAskedQuestions.md create mode 100644 googlemock/docs/KnownIssues.md create mode 100644 googlemock/docs/v1_5/CheatSheet.md create mode 100644 googlemock/docs/v1_5/CookBook.md create mode 100644 googlemock/docs/v1_5/Documentation.md create mode 100644 googlemock/docs/v1_5/ForDummies.md create mode 100644 googlemock/docs/v1_5/FrequentlyAskedQuestions.md create mode 100644 googlemock/docs/v1_6/CheatSheet.md create mode 100644 googlemock/docs/v1_6/CookBook.md create mode 100644 googlemock/docs/v1_6/Documentation.md create mode 100644 googlemock/docs/v1_6/ForDummies.md create mode 100644 googlemock/docs/v1_6/FrequentlyAskedQuestions.md create mode 100644 googlemock/docs/v1_7/CheatSheet.md create mode 100644 googlemock/docs/v1_7/CookBook.md create mode 100644 googlemock/docs/v1_7/Documentation.md create mode 100644 googlemock/docs/v1_7/ForDummies.md create mode 100644 googlemock/docs/v1_7/FrequentlyAskedQuestions.md create mode 100644 googlemock/include/gmock/gmock-actions.h create mode 100644 googlemock/include/gmock/gmock-cardinalities.h create mode 100644 googlemock/include/gmock/gmock-generated-actions.h create mode 100644 googlemock/include/gmock/gmock-generated-actions.h.pump create mode 100644 googlemock/include/gmock/gmock-generated-function-mockers.h create mode 100644 googlemock/include/gmock/gmock-generated-function-mockers.h.pump create mode 100644 googlemock/include/gmock/gmock-generated-matchers.h create mode 100644 googlemock/include/gmock/gmock-generated-matchers.h.pump create mode 100644 googlemock/include/gmock/gmock-generated-nice-strict.h create mode 100644 googlemock/include/gmock/gmock-generated-nice-strict.h.pump create mode 100644 googlemock/include/gmock/gmock-matchers.h create mode 100644 googlemock/include/gmock/gmock-more-actions.h create mode 100644 googlemock/include/gmock/gmock-more-matchers.h create mode 100644 googlemock/include/gmock/gmock-spec-builders.h create mode 100644 googlemock/include/gmock/gmock.h create mode 100644 googlemock/include/gmock/internal/custom/gmock-generated-actions.h create mode 100644 googlemock/include/gmock/internal/custom/gmock-generated-actions.h.pump create mode 100644 googlemock/include/gmock/internal/custom/gmock-matchers.h create mode 100644 googlemock/include/gmock/internal/custom/gmock-port.h create mode 100644 googlemock/include/gmock/internal/gmock-generated-internal-utils.h create mode 100644 googlemock/include/gmock/internal/gmock-generated-internal-utils.h.pump create mode 100644 googlemock/include/gmock/internal/gmock-internal-utils.h create mode 100644 googlemock/include/gmock/internal/gmock-port.h create mode 100644 googlemock/make/Makefile create mode 100644 googlemock/msvc/2005/gmock.sln create mode 100644 googlemock/msvc/2005/gmock.vcproj create mode 100644 googlemock/msvc/2005/gmock_config.vsprops create mode 100644 googlemock/msvc/2005/gmock_main.vcproj create mode 100644 googlemock/msvc/2005/gmock_test.vcproj create mode 100644 googlemock/msvc/2010/gmock.sln create mode 100644 googlemock/msvc/2010/gmock.vcxproj create mode 100644 googlemock/msvc/2010/gmock_config.props create mode 100644 googlemock/msvc/2010/gmock_main.vcxproj create mode 100644 googlemock/msvc/2010/gmock_test.vcxproj create mode 100644 googlemock/msvc/2015/gmock.sln create mode 100644 googlemock/msvc/2015/gmock.vcxproj create mode 100644 googlemock/msvc/2015/gmock_config.props create mode 100644 googlemock/msvc/2015/gmock_main.vcxproj create mode 100644 googlemock/msvc/2015/gmock_test.vcxproj create mode 100755 googlemock/scripts/fuse_gmock_files.py create mode 100644 googlemock/scripts/generator/LICENSE create mode 100644 googlemock/scripts/generator/README create mode 100644 googlemock/scripts/generator/README.cppclean create mode 100755 googlemock/scripts/generator/cpp/__init__.py create mode 100755 googlemock/scripts/generator/cpp/ast.py create mode 100755 googlemock/scripts/generator/cpp/gmock_class.py create mode 100755 googlemock/scripts/generator/cpp/gmock_class_test.py create mode 100755 googlemock/scripts/generator/cpp/keywords.py create mode 100755 googlemock/scripts/generator/cpp/tokenize.py create mode 100755 googlemock/scripts/generator/cpp/utils.py create mode 100755 googlemock/scripts/generator/gmock_gen.py create mode 100755 googlemock/scripts/gmock-config.in create mode 100755 googlemock/scripts/gmock_doctor.py create mode 100755 googlemock/scripts/upload.py create mode 100755 googlemock/scripts/upload_gmock.py create mode 100644 googlemock/src/gmock-all.cc create mode 100644 googlemock/src/gmock-cardinalities.cc create mode 100644 googlemock/src/gmock-internal-utils.cc create mode 100644 googlemock/src/gmock-matchers.cc create mode 100644 googlemock/src/gmock-spec-builders.cc create mode 100644 googlemock/src/gmock.cc create mode 100644 googlemock/src/gmock_main.cc create mode 100644 googlemock/test/gmock-actions_test.cc create mode 100644 googlemock/test/gmock-cardinalities_test.cc create mode 100644 googlemock/test/gmock-generated-actions_test.cc create mode 100644 googlemock/test/gmock-generated-function-mockers_test.cc create mode 100644 googlemock/test/gmock-generated-internal-utils_test.cc create mode 100644 googlemock/test/gmock-generated-matchers_test.cc create mode 100644 googlemock/test/gmock-internal-utils_test.cc create mode 100644 googlemock/test/gmock-matchers_test.cc create mode 100644 googlemock/test/gmock-more-actions_test.cc create mode 100644 googlemock/test/gmock-nice-strict_test.cc create mode 100644 googlemock/test/gmock-port_test.cc create mode 100644 googlemock/test/gmock-spec-builders_test.cc create mode 100644 googlemock/test/gmock_all_test.cc create mode 100644 googlemock/test/gmock_ex_test.cc create mode 100755 googlemock/test/gmock_leak_test.py create mode 100644 googlemock/test/gmock_leak_test_.cc create mode 100644 googlemock/test/gmock_link2_test.cc create mode 100644 googlemock/test/gmock_link_test.cc create mode 100644 googlemock/test/gmock_link_test.h create mode 100755 googlemock/test/gmock_output_test.py create mode 100644 googlemock/test/gmock_output_test_.cc create mode 100644 googlemock/test/gmock_output_test_golden.txt create mode 100644 googlemock/test/gmock_stress_test.cc create mode 100644 googlemock/test/gmock_test.cc create mode 100755 googlemock/test/gmock_test_utils.py create mode 100644 googletest/.gitignore create mode 100644 googletest/CHANGES create mode 100644 googletest/CMakeLists.txt create mode 100644 googletest/CONTRIBUTORS create mode 100644 googletest/LICENSE create mode 100644 googletest/Makefile.am create mode 100644 googletest/README.md create mode 100644 googletest/build-aux/.keep create mode 100644 googletest/cmake/internal_utils.cmake create mode 100644 googletest/codegear/gtest.cbproj create mode 100644 googletest/codegear/gtest.groupproj create mode 100644 googletest/codegear/gtest_all.cc create mode 100644 googletest/codegear/gtest_link.cc create mode 100644 googletest/codegear/gtest_main.cbproj create mode 100644 googletest/codegear/gtest_unittest.cbproj create mode 100644 googletest/configure.ac create mode 100644 googletest/docs/AdvancedGuide.md create mode 100644 googletest/docs/DevGuide.md create mode 100644 googletest/docs/Documentation.md create mode 100644 googletest/docs/FAQ.md create mode 100644 googletest/docs/Primer.md create mode 100644 googletest/docs/PumpManual.md create mode 100644 googletest/docs/Samples.md create mode 100644 googletest/docs/V1_5_AdvancedGuide.md create mode 100644 googletest/docs/V1_5_Documentation.md create mode 100644 googletest/docs/V1_5_FAQ.md create mode 100644 googletest/docs/V1_5_Primer.md create mode 100644 googletest/docs/V1_5_PumpManual.md create mode 100644 googletest/docs/V1_5_XcodeGuide.md create mode 100644 googletest/docs/V1_6_AdvancedGuide.md create mode 100644 googletest/docs/V1_6_Documentation.md create mode 100644 googletest/docs/V1_6_FAQ.md create mode 100644 googletest/docs/V1_6_Primer.md create mode 100644 googletest/docs/V1_6_PumpManual.md create mode 100644 googletest/docs/V1_6_Samples.md create mode 100644 googletest/docs/V1_6_XcodeGuide.md create mode 100644 googletest/docs/V1_7_AdvancedGuide.md create mode 100644 googletest/docs/V1_7_Documentation.md create mode 100644 googletest/docs/V1_7_FAQ.md create mode 100644 googletest/docs/V1_7_Primer.md create mode 100644 googletest/docs/V1_7_PumpManual.md create mode 100644 googletest/docs/V1_7_Samples.md create mode 100644 googletest/docs/V1_7_XcodeGuide.md create mode 100644 googletest/docs/XcodeGuide.md create mode 100644 googletest/include/gtest/gtest-death-test.h create mode 100644 googletest/include/gtest/gtest-message.h create mode 100644 googletest/include/gtest/gtest-param-test.h create mode 100644 googletest/include/gtest/gtest-param-test.h.pump create mode 100644 googletest/include/gtest/gtest-printers.h create mode 100644 googletest/include/gtest/gtest-spi.h create mode 100644 googletest/include/gtest/gtest-test-part.h create mode 100644 googletest/include/gtest/gtest-typed-test.h create mode 100644 googletest/include/gtest/gtest.h create mode 100644 googletest/include/gtest/gtest_pred_impl.h create mode 100644 googletest/include/gtest/gtest_prod.h create mode 100644 googletest/include/gtest/internal/custom/gtest-port.h create mode 100644 googletest/include/gtest/internal/custom/gtest-printers.h create mode 100644 googletest/include/gtest/internal/custom/gtest.h create mode 100644 googletest/include/gtest/internal/gtest-death-test-internal.h create mode 100644 googletest/include/gtest/internal/gtest-filepath.h create mode 100644 googletest/include/gtest/internal/gtest-internal.h create mode 100644 googletest/include/gtest/internal/gtest-linked_ptr.h create mode 100644 googletest/include/gtest/internal/gtest-param-util-generated.h create mode 100644 googletest/include/gtest/internal/gtest-param-util-generated.h.pump create mode 100644 googletest/include/gtest/internal/gtest-param-util.h create mode 100644 googletest/include/gtest/internal/gtest-port-arch.h create mode 100644 googletest/include/gtest/internal/gtest-port.h create mode 100644 googletest/include/gtest/internal/gtest-string.h create mode 100644 googletest/include/gtest/internal/gtest-tuple.h create mode 100644 googletest/include/gtest/internal/gtest-tuple.h.pump create mode 100644 googletest/include/gtest/internal/gtest-type-util.h create mode 100644 googletest/include/gtest/internal/gtest-type-util.h.pump create mode 100644 googletest/m4/acx_pthread.m4 create mode 100644 googletest/m4/gtest.m4 create mode 100644 googletest/make/Makefile create mode 100644 googletest/msvc/gtest-md.sln create mode 100644 googletest/msvc/gtest-md.vcproj create mode 100644 googletest/msvc/gtest.sln create mode 100644 googletest/msvc/gtest.vcproj create mode 100644 googletest/msvc/gtest_main-md.vcproj create mode 100644 googletest/msvc/gtest_main.vcproj create mode 100644 googletest/msvc/gtest_prod_test-md.vcproj create mode 100644 googletest/msvc/gtest_prod_test.vcproj create mode 100644 googletest/msvc/gtest_unittest-md.vcproj create mode 100644 googletest/msvc/gtest_unittest.vcproj create mode 100644 googletest/samples/prime_tables.h create mode 100644 googletest/samples/sample1.cc create mode 100644 googletest/samples/sample1.h create mode 100644 googletest/samples/sample10_unittest.cc create mode 100644 googletest/samples/sample1_unittest.cc create mode 100644 googletest/samples/sample2.cc create mode 100644 googletest/samples/sample2.h create mode 100644 googletest/samples/sample2_unittest.cc create mode 100644 googletest/samples/sample3-inl.h create mode 100644 googletest/samples/sample3_unittest.cc create mode 100644 googletest/samples/sample4.cc create mode 100644 googletest/samples/sample4.h create mode 100644 googletest/samples/sample4_unittest.cc create mode 100644 googletest/samples/sample5_unittest.cc create mode 100644 googletest/samples/sample6_unittest.cc create mode 100644 googletest/samples/sample7_unittest.cc create mode 100644 googletest/samples/sample8_unittest.cc create mode 100644 googletest/samples/sample9_unittest.cc create mode 100644 googletest/scripts/common.py create mode 100755 googletest/scripts/fuse_gtest_files.py create mode 100755 googletest/scripts/gen_gtest_pred_impl.py create mode 100755 googletest/scripts/gtest-config.in create mode 100755 googletest/scripts/pump.py create mode 100755 googletest/scripts/release_docs.py create mode 100644 googletest/scripts/test/Makefile create mode 100755 googletest/scripts/upload.py create mode 100755 googletest/scripts/upload_gtest.py create mode 100644 googletest/src/gtest-all.cc create mode 100644 googletest/src/gtest-death-test.cc create mode 100644 googletest/src/gtest-filepath.cc create mode 100644 googletest/src/gtest-internal-inl.h create mode 100644 googletest/src/gtest-port.cc create mode 100644 googletest/src/gtest-printers.cc create mode 100644 googletest/src/gtest-test-part.cc create mode 100644 googletest/src/gtest-typed-test.cc create mode 100644 googletest/src/gtest.cc create mode 100644 googletest/src/gtest_main.cc create mode 100644 googletest/test/gtest-death-test_ex_test.cc create mode 100644 googletest/test/gtest-death-test_test.cc create mode 100644 googletest/test/gtest-filepath_test.cc create mode 100644 googletest/test/gtest-linked_ptr_test.cc create mode 100644 googletest/test/gtest-listener_test.cc create mode 100644 googletest/test/gtest-message_test.cc create mode 100644 googletest/test/gtest-options_test.cc create mode 100644 googletest/test/gtest-param-test2_test.cc create mode 100644 googletest/test/gtest-param-test_test.cc create mode 100644 googletest/test/gtest-param-test_test.h create mode 100644 googletest/test/gtest-port_test.cc create mode 100644 googletest/test/gtest-printers_test.cc create mode 100644 googletest/test/gtest-test-part_test.cc create mode 100644 googletest/test/gtest-tuple_test.cc create mode 100644 googletest/test/gtest-typed-test2_test.cc create mode 100644 googletest/test/gtest-typed-test_test.cc create mode 100644 googletest/test/gtest-typed-test_test.h create mode 100644 googletest/test/gtest-unittest-api_test.cc create mode 100644 googletest/test/gtest_all_test.cc create mode 100755 googletest/test/gtest_break_on_failure_unittest.py create mode 100644 googletest/test/gtest_break_on_failure_unittest_.cc create mode 100755 googletest/test/gtest_catch_exceptions_test.py create mode 100644 googletest/test/gtest_catch_exceptions_test_.cc create mode 100755 googletest/test/gtest_color_test.py create mode 100644 googletest/test/gtest_color_test_.cc create mode 100755 googletest/test/gtest_env_var_test.py create mode 100644 googletest/test/gtest_env_var_test_.cc create mode 100644 googletest/test/gtest_environment_test.cc create mode 100755 googletest/test/gtest_filter_unittest.py create mode 100644 googletest/test/gtest_filter_unittest_.cc create mode 100755 googletest/test/gtest_help_test.py create mode 100644 googletest/test/gtest_help_test_.cc create mode 100755 googletest/test/gtest_list_tests_unittest.py create mode 100644 googletest/test/gtest_list_tests_unittest_.cc create mode 100644 googletest/test/gtest_main_unittest.cc create mode 100644 googletest/test/gtest_no_test_unittest.cc create mode 100755 googletest/test/gtest_output_test.py create mode 100644 googletest/test/gtest_output_test_.cc create mode 100644 googletest/test/gtest_output_test_golden_lin.txt create mode 100644 googletest/test/gtest_pred_impl_unittest.cc create mode 100644 googletest/test/gtest_premature_exit_test.cc create mode 100644 googletest/test/gtest_prod_test.cc create mode 100644 googletest/test/gtest_repeat_test.cc create mode 100755 googletest/test/gtest_shuffle_test.py create mode 100644 googletest/test/gtest_shuffle_test_.cc create mode 100644 googletest/test/gtest_sole_header_test.cc create mode 100644 googletest/test/gtest_stress_test.cc create mode 100755 googletest/test/gtest_test_utils.py create mode 100644 googletest/test/gtest_throw_on_failure_ex_test.cc create mode 100755 googletest/test/gtest_throw_on_failure_test.py create mode 100644 googletest/test/gtest_throw_on_failure_test_.cc create mode 100755 googletest/test/gtest_uninitialized_test.py create mode 100644 googletest/test/gtest_uninitialized_test_.cc create mode 100644 googletest/test/gtest_unittest.cc create mode 100644 googletest/test/gtest_xml_outfile1_test_.cc create mode 100644 googletest/test/gtest_xml_outfile2_test_.cc create mode 100755 googletest/test/gtest_xml_outfiles_test.py create mode 100755 googletest/test/gtest_xml_output_unittest.py create mode 100644 googletest/test/gtest_xml_output_unittest_.cc create mode 100755 googletest/test/gtest_xml_test_utils.py create mode 100644 googletest/test/production.cc create mode 100644 googletest/test/production.h create mode 100644 googletest/xcode/Config/DebugProject.xcconfig create mode 100644 googletest/xcode/Config/FrameworkTarget.xcconfig create mode 100644 googletest/xcode/Config/General.xcconfig create mode 100644 googletest/xcode/Config/ReleaseProject.xcconfig create mode 100644 googletest/xcode/Config/StaticLibraryTarget.xcconfig create mode 100644 googletest/xcode/Config/TestTarget.xcconfig create mode 100644 googletest/xcode/Resources/Info.plist create mode 100644 googletest/xcode/Samples/FrameworkSample/Info.plist create mode 100644 googletest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj create mode 100644 googletest/xcode/Samples/FrameworkSample/runtests.sh create mode 100644 googletest/xcode/Samples/FrameworkSample/widget.cc create mode 100644 googletest/xcode/Samples/FrameworkSample/widget.h create mode 100644 googletest/xcode/Samples/FrameworkSample/widget_test.cc create mode 100644 googletest/xcode/Scripts/runtests.sh create mode 100755 googletest/xcode/Scripts/versiongenerate.py create mode 100644 googletest/xcode/gtest.xcodeproj/project.pbxproj create mode 100755 travis.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce310bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore CI build directory +build/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3204dfa --- /dev/null +++ b/.travis.yml @@ -0,0 +1,46 @@ +# Build matrix / environment variable are explained on: +# http://about.travis-ci.org/docs/user/build-configuration/ +# This file can be validated on: +# http://lint.travis-ci.org/ + +install: +# /usr/bin/gcc is 4.6 always, but gcc-X.Y is available. +- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi +# /usr/bin/clang is 3.4, lets override with modern one. +- if [ "$CXX" = "clang++" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi +- echo ${PATH} +- echo ${CXX} +- ${CXX} --version +- ${CXX} -v +addons: + apt: + # List of whitelisted in travis packages for ubuntu-precise can be found here: + # https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise + # List of whitelisted in travis apt-sources: + # https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - gcc-4.9 + - g++-4.9 + - clang-3.7 + - valgrind +os: + - linux + - osx +language: cpp +compiler: + - gcc + - clang +script: ./travis.sh +env: + matrix: + - GTEST_TARGET=googletest SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE + - GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE + - GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug CXX_FLAGS=-std=c++11 VERBOSE_MAKE=true VERBOSE +# - GTEST_TARGET=googletest SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false +# - GTEST_TARGET=googlemock SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false +notifications: + email: false +sudo: false diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8d2b552 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.6.2) + +project( googletest-distribution ) + +enable_testing() + +option(BUILD_GTEST "Builds the googletest subproject" OFF) + +#Note that googlemock target already builds googletest +option(BUILD_GMOCK "Builds the googlemock subproject" ON) + +if(BUILD_GMOCK) + add_subdirectory( googlemock ) +elseif(BUILD_GTEST) + add_subdirectory( googletest ) +endif() diff --git a/README.md b/README.md new file mode 100644 index 0000000..076484e --- /dev/null +++ b/README.md @@ -0,0 +1,142 @@ + +# Google Test # + +[![Build Status](https://travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest) +[![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/BillyDonahue/googletest/branch/master) + +Welcome to **Google Test**, Google's C++ test framework! + +This repository is a merger of the formerly separate GoogleTest and +GoogleMock projects. These were so closely related that it makes sense to +maintain and release them together. + +Please see the project page above for more information as well as the +mailing list for questions, discussions, and development. There is +also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please +join us! + +Getting started information for **Google Test** is available in the +[Google Test Primer](googletest/docs/Primer.md) documentation. + +**Google Mock** is an extension to Google Test for writing and using C++ mock +classes. See the separate [Google Mock documentation](googlemock/README.md). + +More detailed documentation for googletest (including build instructions) are +in its interior [googletest/README.md](googletest/README.md) file. + +## Features ## + + * An [XUnit](https://en.wikipedia.org/wiki/XUnit) test framework. + * Test discovery. + * A rich set of assertions. + * User-defined assertions. + * Death tests. + * Fatal and non-fatal failures. + * Value-parameterized tests. + * Type-parameterized tests. + * Various options for running the tests. + * XML test report generation. + +## Platforms ## + +Google test has been used on a variety of platforms: + + * Linux + * Mac OS X + * Windows + * Cygwin + * MinGW + * Windows Mobile + * Symbian + +## Who Is Using Google Test? ## + +In addition to many internal projects at Google, Google Test is also used by +the following notable projects: + + * The [Chromium projects](http://www.chromium.org/) (behind the Chrome + browser and Chrome OS). + * The [LLVM](http://llvm.org/) compiler. + * [Protocol Buffers](https://github.com/google/protobuf), Google's data + interchange format. + * The [OpenCV](http://opencv.org/) computer vision library. + +## Related Open Source Projects ## + +[Google Test UI](https://github.com/ospector/gtest-gbar) is test runner that runs +your test binary, allows you to track its progress via a progress bar, and +displays a list of test failures. Clicking on one shows failure text. Google +Test UI is written in C#. + +[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event +listener for Google Test that implements the +[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test +result output. If your test runner understands TAP, you may find it useful. + +## Requirements ## + +Google Test is designed to have fairly minimal requirements to build +and use with your projects, but there are some. Currently, we support +Linux, Windows, Mac OS X, and Cygwin. We will also make our best +effort to support other platforms (e.g. Solaris, AIX, and z/OS). +However, since core members of the Google Test project have no access +to these platforms, Google Test may have outstanding issues there. If +you notice any problems on your platform, please notify +. Patches for fixing them are +even more welcome! + +### Linux Requirements ### + +These are the base requirements to build and use Google Test from a source +package (as described below): + + * GNU-compatible Make or gmake + * POSIX-standard shell + * POSIX(-2) Regular Expressions (regex.h) + * A C++98-standard-compliant compiler + +### Windows Requirements ### + + * Microsoft Visual C++ v7.1 or newer + +### Cygwin Requirements ### + + * Cygwin v1.5.25-14 or newer + +### Mac OS X Requirements ### + + * Mac OS X v10.4 Tiger or newer + * Xcode Developer Tools + +### Requirements for Contributors ### + +We welcome patches. If you plan to contribute a patch, you need to +build Google Test and its own tests from a git checkout (described +below), which has further requirements: + + * [Python](https://www.python.org/) v2.3 or newer (for running some of + the tests and re-generating certain source files from templates) + * [CMake](https://cmake.org/) v2.6.4 or newer + +## Regenerating Source Files ## + +Some of Google Test's source files are generated from templates (not +in the C++ sense) using a script. +For example, the +file include/gtest/internal/gtest-type-util.h.pump is used to generate +gtest-type-util.h in the same directory. + +You don't need to worry about regenerating the source files +unless you need to modify them. You would then modify the +corresponding `.pump` files and run the '[pump.py](googletest/scripts/pump.py)' +generator script. See the [Pump Manual](googletest/docs/PumpManual.md). + +### Contributing Code ### + +We welcome patches. Please read the +[Developer's Guide](googletest/docs/DevGuide.md) +for how you can contribute. In particular, make sure you have signed +the Contributor License Agreement, or we won't be able to accept the +patch. + +Happy testing! diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..d613fd6 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,71 @@ +version: '{build}' + +os: Visual Studio 2015 + +environment: + matrix: + - Toolset: v140 + - Toolset: v120 + - Toolset: v110 + - Toolset: v100 + +platform: + - Win32 + - x64 + +configuration: +# - Release + - Debug + +build: + verbosity: minimal + +artifacts: + - path: '_build/Testing/Temporary/*' + name: test_results + +before_build: +- ps: | + Write-Output "Configuration: $env:CONFIGURATION" + Write-Output "Platform: $env:PLATFORM" + $generator = switch ($env:TOOLSET) + { + "v140" {"Visual Studio 14 2015"} + "v120" {"Visual Studio 12 2013"} + "v110" {"Visual Studio 11 2012"} + "v100" {"Visual Studio 10 2010"} + } + if ($env:PLATFORM -eq "x64") + { + $generator = "$generator Win64" + } + +build_script: +- ps: | + if (($env:TOOLSET -eq "v100") -and ($env:PLATFORM -eq "x64")) + { + return + } + md _build -Force | Out-Null + cd _build + + & cmake -G "$generator" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -Dgtest_build_tests=ON -Dgtest_build_samples=ON -Dgmock_build_tests=ON .. + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + & cmake --build . --config $env:CONFIGURATION + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + +test_script: +- ps: | + if (($env:Toolset -eq "v100") -and ($env:PLATFORM -eq "x64")) + { + return + } + + & ctest -C $env:CONFIGURATION --output-on-failure + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } diff --git a/googlemock/CHANGES b/googlemock/CHANGES new file mode 100644 index 0000000..d6f2f76 --- /dev/null +++ b/googlemock/CHANGES @@ -0,0 +1,126 @@ +Changes for 1.7.0: + +* All new improvements in Google Test 1.7.0. +* New feature: matchers DoubleNear(), FloatNear(), + NanSensitiveDoubleNear(), NanSensitiveFloatNear(), + UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(), + WhenSortedBy(), IsEmpty(), and SizeIs(). +* Improvement: Google Mock can now be built as a DLL. +* Improvement: when compiled by a C++11 compiler, matchers AllOf() + and AnyOf() can accept an arbitrary number of matchers. +* Improvement: when compiled by a C++11 compiler, matchers + ElementsAreArray() can accept an initializer list. +* Improvement: when exceptions are enabled, a mock method with no + default action now throws instead crashing the test. +* Improvement: added class testing::StringMatchResultListener to aid + definition of composite matchers. +* Improvement: function return types used in MOCK_METHOD*() macros can + now contain unprotected commas. +* Improvement (potentially breaking): EXPECT_THAT() and ASSERT_THAT() + are now more strict in ensuring that the value type and the matcher + type are compatible, catching potential bugs in tests. +* Improvement: Pointee() now works on an optional. +* Improvement: the ElementsAreArray() matcher can now take a vector or + iterator range as input, and makes a copy of its input elements + before the conversion to a Matcher. +* Improvement: the Google Mock Generator can now generate mocks for + some class templates. +* Bug fix: mock object destruction triggerred by another mock object's + destruction no longer hangs. +* Improvement: Google Mock Doctor works better with newer Clang and + GCC now. +* Compatibility fixes. +* Bug/warning fixes. + +Changes for 1.6.0: + +* Compilation is much faster and uses much less memory, especially + when the constructor and destructor of a mock class are moved out of + the class body. +* New matchers: Pointwise(), Each(). +* New actions: ReturnPointee() and ReturnRefOfCopy(). +* CMake support. +* Project files for Visual Studio 2010. +* AllOf() and AnyOf() can handle up-to 10 arguments now. +* Google Mock doctor understands Clang error messages now. +* SetArgPointee<> now accepts string literals. +* gmock_gen.py handles storage specifier macros and template return + types now. +* Compatibility fixes. +* Bug fixes and implementation clean-ups. +* Potentially incompatible changes: disables the harmful 'make install' + command in autotools. + +Potentially breaking changes: + +* The description string for MATCHER*() changes from Python-style + interpolation to an ordinary C++ string expression. +* SetArgumentPointee is deprecated in favor of SetArgPointee. +* Some non-essential project files for Visual Studio 2005 are removed. + +Changes for 1.5.0: + + * New feature: Google Mock can be safely used in multi-threaded tests + on platforms having pthreads. + * New feature: function for printing a value of arbitrary type. + * New feature: function ExplainMatchResult() for easy definition of + composite matchers. + * The new matcher API lets user-defined matchers generate custom + explanations more directly and efficiently. + * Better failure messages all around. + * NotNull() and IsNull() now work with smart pointers. + * Field() and Property() now work when the matcher argument is a pointer + passed by reference. + * Regular expression matchers on all platforms. + * Added GCC 4.0 support for Google Mock Doctor. + * Added gmock_all_test.cc for compiling most Google Mock tests + in a single file. + * Significantly cleaned up compiler warnings. + * Bug fixes, better test coverage, and implementation clean-ups. + + Potentially breaking changes: + + * Custom matchers defined using MatcherInterface or MakePolymorphicMatcher() + need to be updated after upgrading to Google Mock 1.5.0; matchers defined + using MATCHER or MATCHER_P* aren't affected. + * Dropped support for 'make install'. + +Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of +Google Test): + + * Works in more environments: Symbian and minGW, Visual C++ 7.1. + * Lighter weight: comes with our own implementation of TR1 tuple (no + more dependency on Boost!). + * New feature: --gmock_catch_leaked_mocks for detecting leaked mocks. + * New feature: ACTION_TEMPLATE for defining templatized actions. + * New feature: the .After() clause for specifying expectation order. + * New feature: the .With() clause for for specifying inter-argument + constraints. + * New feature: actions ReturnArg(), ReturnNew(...), and + DeleteArg(). + * New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(), + and Contains(). + * New feature: utility class MockFunction, useful for checkpoints, etc. + * New feature: functions Value(x, m) and SafeMatcherCast(m). + * New feature: copying a mock object is rejected at compile time. + * New feature: a script for fusing all Google Mock and Google Test + source files for easy deployment. + * Improved the Google Mock doctor to diagnose more diseases. + * Improved the Google Mock generator script. + * Compatibility fixes for Mac OS X and gcc. + * Bug fixes and implementation clean-ups. + +Changes for 1.1.0: + + * New feature: ability to use Google Mock with any testing framework. + * New feature: macros for easily defining new matchers + * New feature: macros for easily defining new actions. + * New feature: more container matchers. + * New feature: actions for accessing function arguments and throwing + exceptions. + * Improved the Google Mock doctor script for diagnosing compiler errors. + * Bug fixes and implementation clean-ups. + +Changes for 1.0.0: + + * Initial Open Source release of Google Mock diff --git a/googlemock/CMakeLists.txt b/googlemock/CMakeLists.txt new file mode 100644 index 0000000..beb259a --- /dev/null +++ b/googlemock/CMakeLists.txt @@ -0,0 +1,202 @@ +######################################################################## +# CMake build script for Google Mock. +# +# To run the tests for Google Mock itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. + +# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to +# make it prominent in the GUI. +option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) + +option(gmock_build_tests "Build all of Google Mock's own tests." OFF) + +# A directory to find Google Test sources. +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") + set(gtest_dir gtest) +else() + set(gtest_dir ../googletest) +endif() + +# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). +include("${gtest_dir}/cmake/hermetic_build.cmake" OPTIONAL) + +if (COMMAND pre_project_set_up_hermetic_build) + # Google Test also calls hermetic setup functions from add_subdirectory, + # although its changes will not affect things at the current scope. + pre_project_set_up_hermetic_build() +endif() + +######################################################################## +# +# Project-wide settings + +# Name of the project. +# +# CMake files in this project can refer to the root source directory +# as ${gmock_SOURCE_DIR} and to the root binary directory as +# ${gmock_BINARY_DIR}. +# Language "C" is required for find_package(Threads). +project(gmock CXX C) +cmake_minimum_required(VERSION 2.6.2) + +if (COMMAND set_up_hermetic_build) + set_up_hermetic_build() +endif() + +# Instructs CMake to process Google Test's CMakeLists.txt and add its +# targets to the current scope. We are placing Google Test's binary +# directory in a subdirectory of our own as VC compilation may break +# if they are the same (the default). +add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/gtest") + +# Although Google Test's CMakeLists.txt calls this function, the +# changes there don't affect the current scope. Therefore we have to +# call it again here. +config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake + +# Adds Google Mock's and Google Test's header directories to the search path. +include_directories("${gmock_SOURCE_DIR}/include" + "${gmock_SOURCE_DIR}" + "${gtest_SOURCE_DIR}/include" + # This directory is needed to build directly from Google + # Test sources. + "${gtest_SOURCE_DIR}") + +# Summary of tuple support for Microsoft Visual Studio: +# Compiler version(MS) version(cmake) Support +# ---------- ----------- -------------- ----------------------------- +# <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple. +# VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10 +# VS 2013 12 1800 std::tr1::tuple +if (MSVC AND MSVC_VERSION EQUAL 1700) + add_definitions(/D _VARIADIC_MAX=10) +endif() + +######################################################################## +# +# Defines the gmock & gmock_main libraries. User tests should link +# with one of them. + +# Google Mock libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that Google Mock can be compiled by +# a user aggressive about warnings. +cxx_library(gmock + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc) + +cxx_library(gmock_main + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc + src/gmock_main.cc) + +# If the CMake version supports it, attach header directory information +# to the targets for when we are part of a parent build (ie being pulled +# in via add_subdirectory() rather than being a standalone build). +if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_include_directories(gmock INTERFACE "${gmock_SOURCE_DIR}/include") + target_include_directories(gmock_main INTERFACE "${gmock_SOURCE_DIR}/include") +endif() + +######################################################################## +# +# Install rules +install(TARGETS gmock gmock_main + DESTINATION lib) +install(DIRECTORY ${gmock_SOURCE_DIR}/include/gmock + DESTINATION include) + +######################################################################## +# +# Google Mock's own tests. +# +# You can skip this section if you aren't interested in testing +# Google Mock itself. +# +# The tests are not built by default. To build them, set the +# gmock_build_tests option to ON. You can do it by running ccmake +# or specifying the -Dgmock_build_tests=ON flag when running cmake. + +if (gmock_build_tests) + # This must be set in the root directory for the tests to be run by + # 'make test' or ctest. + enable_testing() + + ############################################################ + # C++ tests built with standard compiler flags. + + cxx_test(gmock-actions_test gmock_main) + cxx_test(gmock-cardinalities_test gmock_main) + cxx_test(gmock_ex_test gmock_main) + cxx_test(gmock-generated-actions_test gmock_main) + cxx_test(gmock-generated-function-mockers_test gmock_main) + cxx_test(gmock-generated-internal-utils_test gmock_main) + cxx_test(gmock-generated-matchers_test gmock_main) + cxx_test(gmock-internal-utils_test gmock_main) + cxx_test(gmock-matchers_test gmock_main) + cxx_test(gmock-more-actions_test gmock_main) + cxx_test(gmock-nice-strict_test gmock_main) + cxx_test(gmock-port_test gmock_main) + cxx_test(gmock-spec-builders_test gmock_main) + cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) + cxx_test(gmock_test gmock_main) + + if (CMAKE_USE_PTHREADS_INIT) + cxx_test(gmock_stress_test gmock) + endif() + + # gmock_all_test is commented to save time building and running tests. + # Uncomment if necessary. + # cxx_test(gmock_all_test gmock_main) + + ############################################################ + # C++ tests built with non-standard compiler flags. + + cxx_library(gmock_main_no_exception "${cxx_no_exception}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010. + # Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that + # conflict with our own definitions. Therefore using our own tuple does not + # work on those compilers. + cxx_library(gmock_main_use_own_tuple "${cxx_use_own_tuple}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + cxx_test_with_flags(gmock_use_own_tuple_test "${cxx_use_own_tuple}" + gmock_main_use_own_tuple test/gmock-spec-builders_test.cc) + endif() + + cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" + gmock_main_no_exception test/gmock-more-actions_test.cc) + + cxx_test_with_flags(gmock_no_rtti_test "${cxx_no_rtti}" + gmock_main_no_rtti test/gmock-spec-builders_test.cc) + + cxx_shared_library(shared_gmock_main "${cxx_default}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + # Tests that a binary can be built with Google Mock as a shared library. On + # some system configurations, it may not possible to run the binary without + # knowing more details about the system configurations. We do not try to run + # this binary. To get a more robust shared library coverage, configure with + # -DBUILD_SHARED_LIBS=ON. + cxx_executable_with_flags(shared_gmock_test_ "${cxx_default}" + shared_gmock_main test/gmock-spec-builders_test.cc) + set_target_properties(shared_gmock_test_ + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + + ############################################################ + # Python tests. + + cxx_executable(gmock_leak_test_ test gmock_main) + py_test(gmock_leak_test) + + cxx_executable(gmock_output_test_ test gmock) + py_test(gmock_output_test) +endif() diff --git a/googlemock/CONTRIBUTORS b/googlemock/CONTRIBUTORS new file mode 100644 index 0000000..6e9ae36 --- /dev/null +++ b/googlemock/CONTRIBUTORS @@ -0,0 +1,40 @@ +# This file contains a list of people who've made non-trivial +# contribution to the Google C++ Mocking Framework project. People +# who commit code to the project are encouraged to add their names +# here. Please keep the list sorted by first names. + +Benoit Sigoure +Bogdan Piloca +Chandler Carruth +Dave MacLachlan +David Anderson +Dean Sturtevant +Gene Volovich +Hal Burch +Jeffrey Yasskin +Jim Keller +Joe Walnes +Jon Wray +Keir Mierle +Keith Ray +Kostya Serebryany +Lev Makhlis +Manuel Klimek +Mario Tanev +Mark Paskin +Markus Heule +Matthew Simmons +Mike Bland +Neal Norwitz +Nermin Ozkiranartli +Owen Carlsen +Paneendra Ba +Paul Menage +Piotr Kaminski +Russ Rufer +Sverre Sundsdal +Takeshi Yoshino +Vadim Berman +Vlad Losev +Wolfgang Klier +Zhanyong Wan diff --git a/googlemock/LICENSE b/googlemock/LICENSE new file mode 100644 index 0000000..1941a11 --- /dev/null +++ b/googlemock/LICENSE @@ -0,0 +1,28 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/googlemock/Makefile.am b/googlemock/Makefile.am new file mode 100644 index 0000000..9adbc51 --- /dev/null +++ b/googlemock/Makefile.am @@ -0,0 +1,224 @@ +# Automake file + +# Nonstandard package files for distribution. +EXTRA_DIST = LICENSE + +# We may need to build our internally packaged gtest. If so, it will be +# included in the 'subdirs' variable. +SUBDIRS = $(subdirs) + +# This is generated by the configure script, so clean it for distribution. +DISTCLEANFILES = scripts/gmock-config + +# We define the global AM_CPPFLAGS as everything we compile includes from these +# directories. +AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include + +# Modifies compiler and linker flags for pthreads compatibility. +if HAVE_PTHREADS + AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 + AM_LIBS = @PTHREAD_LIBS@ +endif + +# Build rules for libraries. +lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la + +lib_libgmock_la_SOURCES = src/gmock-all.cc + +pkginclude_HEADERS = \ + include/gmock/gmock-actions.h \ + include/gmock/gmock-cardinalities.h \ + include/gmock/gmock-generated-actions.h \ + include/gmock/gmock-generated-function-mockers.h \ + include/gmock/gmock-generated-matchers.h \ + include/gmock/gmock-generated-nice-strict.h \ + include/gmock/gmock-matchers.h \ + include/gmock/gmock-more-actions.h \ + include/gmock/gmock-more-matchers.h \ + include/gmock/gmock-spec-builders.h \ + include/gmock/gmock.h + +pkginclude_internaldir = $(pkgincludedir)/internal +pkginclude_internal_HEADERS = \ + include/gmock/internal/gmock-generated-internal-utils.h \ + include/gmock/internal/gmock-internal-utils.h \ + include/gmock/internal/gmock-port.h \ + include/gmock/internal/custom/gmock-generated-actions.h \ + include/gmock/internal/custom/gmock-matchers.h \ + include/gmock/internal/custom/gmock-port.h + +lib_libgmock_main_la_SOURCES = src/gmock_main.cc +lib_libgmock_main_la_LIBADD = lib/libgmock.la + +# Build rules for tests. Automake's naming for some of these variables isn't +# terribly obvious, so this is a brief reference: +# +# TESTS -- Programs run automatically by "make check" +# check_PROGRAMS -- Programs built by "make check" but not necessarily run + +TESTS= +check_PROGRAMS= +AM_LDFLAGS = $(GTEST_LDFLAGS) + +# This exercises all major components of Google Mock. It also +# verifies that libgmock works. +TESTS += test/gmock-spec-builders_test +check_PROGRAMS += test/gmock-spec-builders_test +test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc +test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la + +# This tests using Google Mock in multiple translation units. It also +# verifies that libgmock_main and libgmock work. +TESTS += test/gmock_link_test +check_PROGRAMS += test/gmock_link_test +test_gmock_link_test_SOURCES = \ + test/gmock_link2_test.cc \ + test/gmock_link_test.cc \ + test/gmock_link_test.h +test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la + +if HAVE_PYTHON + # Tests that fused gmock files compile and work. + TESTS += test/gmock_fused_test + check_PROGRAMS += test/gmock_fused_test + test_gmock_fused_test_SOURCES = \ + fused-src/gmock-gtest-all.cc \ + fused-src/gmock/gmock.h \ + fused-src/gmock_main.cc \ + fused-src/gtest/gtest.h \ + test/gmock_test.cc + test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src" +endif + +# Google Mock source files that we don't compile directly. +GMOCK_SOURCE_INGLUDES = \ + src/gmock-cardinalities.cc \ + src/gmock-internal-utils.cc \ + src/gmock-matchers.cc \ + src/gmock-spec-builders.cc \ + src/gmock.cc + +EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES) + +# C++ tests that we don't compile using autotools. +EXTRA_DIST += \ + test/gmock-actions_test.cc \ + test/gmock_all_test.cc \ + test/gmock-cardinalities_test.cc \ + test/gmock_ex_test.cc \ + test/gmock-generated-actions_test.cc \ + test/gmock-generated-function-mockers_test.cc \ + test/gmock-generated-internal-utils_test.cc \ + test/gmock-generated-matchers_test.cc \ + test/gmock-internal-utils_test.cc \ + test/gmock-matchers_test.cc \ + test/gmock-more-actions_test.cc \ + test/gmock-nice-strict_test.cc \ + test/gmock-port_test.cc \ + test/gmock_stress_test.cc + +# Python tests, which we don't run using autotools. +EXTRA_DIST += \ + test/gmock_leak_test.py \ + test/gmock_leak_test_.cc \ + test/gmock_output_test.py \ + test/gmock_output_test_.cc \ + test/gmock_output_test_golden.txt \ + test/gmock_test_utils.py + +# Nonstandard package files for distribution. +EXTRA_DIST += \ + CHANGES \ + CONTRIBUTORS \ + make/Makefile + +# Pump scripts for generating Google Mock headers. +# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump. +EXTRA_DIST += \ + include/gmock/gmock-generated-actions.h.pump \ + include/gmock/gmock-generated-function-mockers.h.pump \ + include/gmock/gmock-generated-matchers.h.pump \ + include/gmock/gmock-generated-nice-strict.h.pump \ + include/gmock/internal/gmock-generated-internal-utils.h.pump \ + include/gmock/internal/custom/gmock-generated-actions.h.pump + +# Script for fusing Google Mock and Google Test source files. +EXTRA_DIST += scripts/fuse_gmock_files.py + +# The Google Mock Generator tool from the cppclean project. +EXTRA_DIST += \ + scripts/generator/LICENSE \ + scripts/generator/README \ + scripts/generator/README.cppclean \ + scripts/generator/cpp/__init__.py \ + scripts/generator/cpp/ast.py \ + scripts/generator/cpp/gmock_class.py \ + scripts/generator/cpp/keywords.py \ + scripts/generator/cpp/tokenize.py \ + scripts/generator/cpp/utils.py \ + scripts/generator/gmock_gen.py + +# Script for diagnosing compiler errors in programs that use Google +# Mock. +EXTRA_DIST += scripts/gmock_doctor.py + +# CMake scripts. +EXTRA_DIST += \ + CMakeLists.txt + +# Microsoft Visual Studio 2005 projects. +EXTRA_DIST += \ + msvc/2005/gmock.sln \ + msvc/2005/gmock.vcproj \ + msvc/2005/gmock_config.vsprops \ + msvc/2005/gmock_main.vcproj \ + msvc/2005/gmock_test.vcproj + +# Microsoft Visual Studio 2010 projects. +EXTRA_DIST += \ + msvc/2010/gmock.sln \ + msvc/2010/gmock.vcxproj \ + msvc/2010/gmock_config.props \ + msvc/2010/gmock_main.vcxproj \ + msvc/2010/gmock_test.vcxproj + +if HAVE_PYTHON +# gmock_test.cc does not really depend on files generated by the +# fused-gmock-internal rule. However, gmock_test.o does, and it is +# important to include test/gmock_test.cc as part of this rule in order to +# prevent compiling gmock_test.o until all dependent files have been +# generated. +$(test_gmock_fused_test_SOURCES): fused-gmock-internal + +# TODO(vladl@google.com): Find a way to add Google Tests's sources here. +fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ + $(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \ + $(lib_libgmock_main_la_SOURCES) \ + scripts/fuse_gmock_files.py + mkdir -p "$(srcdir)/fused-src" + chmod -R u+w "$(srcdir)/fused-src" + rm -f "$(srcdir)/fused-src/gtest/gtest.h" + rm -f "$(srcdir)/fused-src/gmock/gmock.h" + rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc" + "$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src" + cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src" + +maintainer-clean-local: + rm -rf "$(srcdir)/fused-src" +endif + +# Death tests may produce core dumps in the build directory. In case +# this happens, clean them to keep distcleancheck happy. +CLEANFILES = core + +# Disables 'make install' as installing a compiled version of Google +# Mock can lead to undefined behavior due to violation of the +# One-Definition Rule. + +install-exec-local: + echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system." + false + +install-data-local: + echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system." + false diff --git a/googlemock/README.md b/googlemock/README.md new file mode 100644 index 0000000..332beab --- /dev/null +++ b/googlemock/README.md @@ -0,0 +1,333 @@ +## Google Mock ## + +The Google C++ mocking framework. + +### Overview ### + +Google's framework for writing and using C++ mock classes. +It can help you derive better designs of your system and write better tests. + +It is inspired by: + + * [jMock](http://www.jmock.org/), + * [EasyMock](http://www.easymock.org/), and + * [Hamcrest](http://code.google.com/p/hamcrest/), + +and designed with C++'s specifics in mind. + +Google mock: + + * lets you create mock classes trivially using simple macros. + * supports a rich set of matchers and actions. + * handles unordered, partially ordered, or completely ordered expectations. + * is extensible by users. + +We hope you find it useful! + +### Features ### + + * Provides a declarative syntax for defining mocks. + * Can easily define partial (hybrid) mocks, which are a cross of real + and mock objects. + * Handles functions of arbitrary types and overloaded functions. + * Comes with a rich set of matchers for validating function arguments. + * Uses an intuitive syntax for controlling the behavior of a mock. + * Does automatic verification of expectations (no record-and-replay needed). + * Allows arbitrary (partial) ordering constraints on + function calls to be expressed,. + * Lets a user extend it by defining new matchers and actions. + * Does not use exceptions. + * Is easy to learn and use. + +Please see the project page above for more information as well as the +mailing list for questions, discussions, and development. There is +also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please +join us! + +Please note that code under [scripts/generator](scripts/generator/) is +from [cppclean](http://code.google.com/p/cppclean/) and released under +the Apache License, which is different from Google Mock's license. + +## Getting Started ## + +If you are new to the project, we suggest that you read the user +documentation in the following order: + + * Learn the [basics](../googletest/docs/Primer.md) of + Google Test, if you choose to use Google Mock with it (recommended). + * Read [Google Mock for Dummies](docs/ForDummies.md). + * Read the instructions below on how to build Google Mock. + +You can also watch Zhanyong's [talk](http://www.youtube.com/watch?v=sYpCyLI47rM) on Google Mock's usage and implementation. + +Once you understand the basics, check out the rest of the docs: + + * [CheatSheet](docs/CheatSheet.md) - all the commonly used stuff + at a glance. + * [CookBook](docs/CookBook.md) - recipes for getting things done, + including advanced techniques. + +If you need help, please check the +[KnownIssues](docs/KnownIssues.md) and +[FrequentlyAskedQuestions](docs/FrequentlyAskedQuestions.md) before +posting a question on the +[discussion group](http://groups.google.com/group/googlemock). + + +### Using Google Mock Without Google Test ### + +Google Mock is not a testing framework itself. Instead, it needs a +testing framework for writing tests. Google Mock works seamlessly +with [Google Test](http://code.google.com/p/googletest/), but +you can also use it with [any C++ testing framework](googlemock/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework). + +### Requirements for End Users ### + +Google Mock is implemented on top of [Google Test]( +http://github.com/google/googletest/), and depends on it. +You must use the bundled version of Google Test when using Google Mock. + +You can also easily configure Google Mock to work with another testing +framework, although it will still need Google Test. Please read +["Using_Google_Mock_with_Any_Testing_Framework"]( + docs/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework) +for instructions. + +Google Mock depends on advanced C++ features and thus requires a more +modern compiler. The following are needed to use Google Mock: + +#### Linux Requirements #### + + * GNU-compatible Make or "gmake" + * POSIX-standard shell + * POSIX(-2) Regular Expressions (regex.h) + * C++98-standard-compliant compiler (e.g. GCC 3.4 or newer) + +#### Windows Requirements #### + + * Microsoft Visual C++ 8.0 SP1 or newer + +#### Mac OS X Requirements #### + + * Mac OS X 10.4 Tiger or newer + * Developer Tools Installed + +### Requirements for Contributors ### + +We welcome patches. If you plan to contribute a patch, you need to +build Google Mock and its tests, which has further requirements: + + * Automake version 1.9 or newer + * Autoconf version 2.59 or newer + * Libtool / Libtoolize + * Python version 2.3 or newer (for running some of the tests and + re-generating certain source files from templates) + +### Building Google Mock ### + +#### Preparing to Build (Unix only) #### + +If you are using a Unix system and plan to use the GNU Autotools build +system to build Google Mock (described below), you'll need to +configure it now. + +To prepare the Autotools build system: + + cd googlemock + autoreconf -fvi + +To build Google Mock and your tests that use it, you need to tell your +build system where to find its headers and source files. The exact +way to do it depends on which build system you use, and is usually +straightforward. + +This section shows how you can integrate Google Mock into your +existing build system. + +Suppose you put Google Mock in directory `${GMOCK_DIR}` and Google Test +in `${GTEST_DIR}` (the latter is `${GMOCK_DIR}/gtest` by default). To +build Google Mock, create a library build target (or a project as +called by Visual Studio and Xcode) to compile + + ${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc + +with + + ${GTEST_DIR}/include and ${GMOCK_DIR}/include + +in the system header search path, and + + ${GTEST_DIR} and ${GMOCK_DIR} + +in the normal header search path. Assuming a Linux-like system and gcc, +something like the following will do: + + g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ + -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \ + -pthread -c ${GTEST_DIR}/src/gtest-all.cc + g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ + -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \ + -pthread -c ${GMOCK_DIR}/src/gmock-all.cc + ar -rv libgmock.a gtest-all.o gmock-all.o + +(We need -pthread as Google Test and Google Mock use threads.) + +Next, you should compile your test source file with +${GTEST\_DIR}/include and ${GMOCK\_DIR}/include in the header search +path, and link it with gmock and any other necessary libraries: + + g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \ + -pthread path/to/your_test.cc libgmock.a -o your_test + +As an example, the make/ directory contains a Makefile that you can +use to build Google Mock on systems where GNU make is available +(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google +Mock's own tests. Instead, it just builds the Google Mock library and +a sample test. You can use it as a starting point for your own build +script. + +If the default settings are correct for your environment, the +following commands should succeed: + + cd ${GMOCK_DIR}/make + make + ./gmock_test + +If you see errors, try to tweak the contents of +[make/Makefile](make/Makefile) to make them go away. + +### Windows ### + +The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010 +directory contains VC++ 2010 projects for building Google Mock and +selected tests. + +Change to the appropriate directory and run "msbuild gmock.sln" to +build the library and tests (or open the gmock.sln in the MSVC IDE). +If you want to create your own project to use with Google Mock, you'll +have to configure it to use the `gmock_config` propety sheet. For that: + + * Open the Property Manager window (View | Other Windows | Property Manager) + * Right-click on your project and select "Add Existing Property Sheet..." + * Navigate to `gmock_config.vsprops` or `gmock_config.props` and select it. + * In Project Properties | Configuration Properties | General | Additional + Include Directories, type /include. + +### Tweaking Google Mock ### + +Google Mock can be used in diverse environments. The default +configuration may not work (or may not work well) out of the box in +some environments. However, you can easily tweak Google Mock by +defining control macros on the compiler command line. Generally, +these macros are named like `GTEST_XYZ` and you define them to either 1 +or 0 to enable or disable a certain feature. + +We list the most frequently used macros below. For a complete list, +see file [${GTEST\_DIR}/include/gtest/internal/gtest-port.h]( +../googletest/include/gtest/internal/gtest-port.h). + +### Choosing a TR1 Tuple Library ### + +Google Mock uses the C++ Technical Report 1 (TR1) tuple library +heavily. Unfortunately TR1 tuple is not yet widely available with all +compilers. The good news is that Google Test 1.4.0+ implements a +subset of TR1 tuple that's enough for Google Mock's need. Google Mock +will automatically use that implementation when the compiler doesn't +provide TR1 tuple. + +Usually you don't need to care about which tuple library Google Test +and Google Mock use. However, if your project already uses TR1 tuple, +you need to tell Google Test and Google Mock to use the same TR1 tuple +library the rest of your project uses, or the two tuple +implementations will clash. To do that, add + + -DGTEST_USE_OWN_TR1_TUPLE=0 + +to the compiler flags while compiling Google Test, Google Mock, and +your tests. If you want to force Google Test and Google Mock to use +their own tuple library, just add + + -DGTEST_USE_OWN_TR1_TUPLE=1 + +to the compiler flags instead. + +If you want to use Boost's TR1 tuple library with Google Mock, please +refer to the Boost website (http://www.boost.org/) for how to obtain +it and set it up. + +### As a Shared Library (DLL) ### + +Google Mock is compact, so most users can build and link it as a static +library for the simplicity. Google Mock can be used as a DLL, but the +same DLL must contain Google Test as well. See +[Google Test's README][gtest_readme] +for instructions on how to set up necessary compiler settings. + +### Tweaking Google Mock ### + +Most of Google Test's control macros apply to Google Mock as well. +Please see [Google Test's README][gtest_readme] for how to tweak them. + +### Upgrading from an Earlier Version ### + +We strive to keep Google Mock releases backward compatible. +Sometimes, though, we have to make some breaking changes for the +users' long-term benefits. This section describes what you'll need to +do if you are upgrading from an earlier version of Google Mock. + +#### Upgrading from 1.1.0 or Earlier #### + +You may need to explicitly enable or disable Google Test's own TR1 +tuple library. See the instructions in section "[Choosing a TR1 Tuple +Library](../googletest/#choosing-a-tr1-tuple-library)". + +#### Upgrading from 1.4.0 or Earlier #### + +On platforms where the pthread library is available, Google Test and +Google Mock use it in order to be thread-safe. For this to work, you +may need to tweak your compiler and/or linker flags. Please see the +"[Multi-threaded Tests](../googletest#multi-threaded-tests +)" section in file Google Test's README for what you may need to do. + +If you have custom matchers defined using `MatcherInterface` or +`MakePolymorphicMatcher()`, you'll need to update their definitions to +use the new matcher API ( +[monomorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers), +[polymorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers)). +Matchers defined using `MATCHER()` or `MATCHER_P*()` aren't affected. + +### Developing Google Mock ### + +This section discusses how to make your own changes to Google Mock. + +#### Testing Google Mock Itself #### + +To make sure your changes work as intended and don't break existing +functionality, you'll want to compile and run Google Test's own tests. +For that you'll need Autotools. First, make sure you have followed +the instructions above to configure Google Mock. +Then, create a build output directory and enter it. Next, + + ${GMOCK_DIR}/configure # try --help for more info + +Once you have successfully configured Google Mock, the build steps are +standard for GNU-style OSS packages. + + make # Standard makefile following GNU conventions + make check # Builds and runs all tests - all should pass. + +Note that when building your project against Google Mock, you are building +against Google Test as well. There is no need to configure Google Test +separately. + +#### Contributing a Patch #### + +We welcome patches. +Please read the [Developer's Guide](docs/DevGuide.md) +for how you can contribute. In particular, make sure you have signed +the Contributor License Agreement, or we won't be able to accept the +patch. + +Happy testing! + +[gtest_readme]: ../googletest/README.md "googletest" diff --git a/googlemock/build-aux/.keep b/googlemock/build-aux/.keep new file mode 100644 index 0000000..e69de29 diff --git a/googlemock/configure.ac b/googlemock/configure.ac new file mode 100644 index 0000000..3b740f2 --- /dev/null +++ b/googlemock/configure.ac @@ -0,0 +1,146 @@ +m4_include(../googletest/m4/acx_pthread.m4) + +AC_INIT([Google C++ Mocking Framework], + [1.7.0], + [googlemock@googlegroups.com], + [gmock]) + +# Provide various options to initialize the Autoconf and configure processes. +AC_PREREQ([2.59]) +AC_CONFIG_SRCDIR([./LICENSE]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([build-aux/config.h]) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([scripts/gmock-config], [chmod +x scripts/gmock-config]) + +# Initialize Automake with various options. We require at least v1.9, prevent +# pedantic complaints about package files, and enable various distribution +# targets. +AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects]) + +# Check for programs used in building Google Test. +AC_PROG_CC +AC_PROG_CXX +AC_LANG([C++]) +AC_PROG_LIBTOOL + +# TODO(chandlerc@google.com): Currently we aren't running the Python tests +# against the interpreter detected by AM_PATH_PYTHON, and so we condition +# HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's +# version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" +# hashbang. +PYTHON= # We *do not* allow the user to specify a python interpreter +AC_PATH_PROG([PYTHON],[python],[:]) +AS_IF([test "$PYTHON" != ":"], + [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) +AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) + +# TODO(chandlerc@google.com) Check for the necessary system headers. + +# Configure pthreads. +AC_ARG_WITH([pthreads], + [AS_HELP_STRING([--with-pthreads], + [use pthreads (default is yes)])], + [with_pthreads=$withval], + [with_pthreads=check]) + +have_pthreads=no +AS_IF([test "x$with_pthreads" != "xno"], + [ACX_PTHREAD( + [], + [AS_IF([test "x$with_pthreads" != "xcheck"], + [AC_MSG_FAILURE( + [--with-pthreads was specified, but unable to be used])])]) + have_pthreads="$acx_pthread_ok"]) +AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"]) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_LIBS) + +# GoogleMock currently has hard dependencies upon GoogleTest above and beyond +# running its own test suite, so we both provide our own version in +# a subdirectory and provide some logic to use a custom version or a system +# installed version. +AC_ARG_WITH([gtest], + [AS_HELP_STRING([--with-gtest], + [Specifies how to find the gtest package. If no + arguments are given, the default behavior, a + system installed gtest will be used if present, + and an internal version built otherwise. If a + path is provided, the gtest built or installed at + that prefix will be used.])], + [], + [with_gtest=yes]) +AC_ARG_ENABLE([external-gtest], + [AS_HELP_STRING([--disable-external-gtest], + [Disables any detection or use of a system + installed or user provided gtest. Any option to + '--with-gtest' is ignored. (Default is enabled.)]) + ], [], [enable_external_gtest=yes]) +AS_IF([test "x$with_gtest" == "xno"], + [AC_MSG_ERROR([dnl +Support for GoogleTest was explicitly disabled. Currently GoogleMock has a hard +dependency upon GoogleTest to build, please provide a version, or allow +GoogleMock to use any installed version and fall back upon its internal +version.])]) + +# Setup various GTEST variables. TODO(chandlerc@google.com): When these are +# used below, they should be used such that any pre-existing values always +# trump values we set them to, so that they can be used to selectively override +# details of the detection process. +AC_ARG_VAR([GTEST_CONFIG], + [The exact path of Google Test's 'gtest-config' script.]) +AC_ARG_VAR([GTEST_CPPFLAGS], + [C-like preprocessor flags for Google Test.]) +AC_ARG_VAR([GTEST_CXXFLAGS], + [C++ compile flags for Google Test.]) +AC_ARG_VAR([GTEST_LDFLAGS], + [Linker path and option flags for Google Test.]) +AC_ARG_VAR([GTEST_LIBS], + [Library linking flags for Google Test.]) +AC_ARG_VAR([GTEST_VERSION], + [The version of Google Test available.]) +HAVE_BUILT_GTEST="no" + +GTEST_MIN_VERSION="1.7.0" + +AS_IF([test "x${enable_external_gtest}" = "xyes"], + [# Begin filling in variables as we are able. + AS_IF([test "x${with_gtest}" != "xyes"], + [AS_IF([test -x "${with_gtest}/scripts/gtest-config"], + [GTEST_CONFIG="${with_gtest}/scripts/gtest-config"], + [GTEST_CONFIG="${with_gtest}/bin/gtest-config"]) + AS_IF([test -x "${GTEST_CONFIG}"], [], + [AC_MSG_ERROR([dnl +Unable to locate either a built or installed Google Test at '${with_gtest}'.]) + ])]) + + AS_IF([test -x "${GTEST_CONFIG}"], [], + [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])]) + AS_IF([test -x "${GTEST_CONFIG}"], + [AC_MSG_CHECKING([for Google Test version >= ${GTEST_MIN_VERSION}]) + AS_IF([${GTEST_CONFIG} --min-version=${GTEST_MIN_VERSION}], + [AC_MSG_RESULT([yes]) + HAVE_BUILT_GTEST="yes"], + [AC_MSG_RESULT([no])])])]) + +AS_IF([test "x${HAVE_BUILT_GTEST}" = "xyes"], + [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags` + GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags` + GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags` + GTEST_LIBS=`${GTEST_CONFIG} --libs` + GTEST_VERSION=`${GTEST_CONFIG} --version`], + [AC_CONFIG_SUBDIRS([../googletest]) + # GTEST_CONFIG needs to be executable both in a Makefile environmont and + # in a shell script environment, so resolve an absolute path for it here. + GTEST_CONFIG="`pwd -P`/../googletest/scripts/gtest-config" + GTEST_CPPFLAGS='-I$(top_srcdir)/../googletest/include' + GTEST_CXXFLAGS='-g' + GTEST_LDFLAGS='' + GTEST_LIBS='$(top_builddir)/../googletest/lib/libgtest.la' + GTEST_VERSION="${GTEST_MIN_VERSION}"]) + +# TODO(chandlerc@google.com) Check the types, structures, and other compiler +# and architecture characteristics. + +# Output the generated files. No further autoconf macros may be used. +AC_OUTPUT diff --git a/googlemock/docs/CheatSheet.md b/googlemock/docs/CheatSheet.md new file mode 100644 index 0000000..ef4451b --- /dev/null +++ b/googlemock/docs/CheatSheet.md @@ -0,0 +1,562 @@ + + +# Defining a Mock Class # + +## Mocking a Normal Class ## + +Given +``` +class Foo { + ... + virtual ~Foo(); + virtual int GetSize() const = 0; + virtual string Describe(const char* name) = 0; + virtual string Describe(int type) = 0; + virtual bool Process(Bar elem, int count) = 0; +}; +``` +(note that `~Foo()` **must** be virtual) we can define its mock as +``` +#include "gmock/gmock.h" + +class MockFoo : public Foo { + MOCK_CONST_METHOD0(GetSize, int()); + MOCK_METHOD1(Describe, string(const char* name)); + MOCK_METHOD1(Describe, string(int type)); + MOCK_METHOD2(Process, bool(Bar elem, int count)); +}; +``` + +To create a "nice" mock object which ignores all uninteresting calls, +or a "strict" mock object, which treats them as failures: +``` +NiceMock nice_foo; // The type is a subclass of MockFoo. +StrictMock strict_foo; // The type is a subclass of MockFoo. +``` + +## Mocking a Class Template ## + +To mock +``` +template +class StackInterface { + public: + ... + virtual ~StackInterface(); + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; +``` +(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: +``` +template +class MockStack : public StackInterface { + public: + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Specifying Calling Conventions for Mock Functions ## + +If your mock function doesn't use the default calling convention, you +can specify it by appending `_WITH_CALLTYPE` to any of the macros +described in the previous two sections and supplying the calling +convention as the first argument to the macro. For example, +``` + MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); + MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); +``` +where `STDMETHODCALLTYPE` is defined by `` on Windows. + +# Using Mocks in Tests # + +The typical flow is: + 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. + 1. Create the mock objects. + 1. Optionally, set the default actions of the mock objects. + 1. Set your expectations on the mock objects (How will they be called? What wil they do?). + 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](../../googletest/) assertions. + 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. + +Here is an example: +``` +using ::testing::Return; // #1 + +TEST(BarTest, DoesThis) { + MockFoo foo; // #2 + + ON_CALL(foo, GetSize()) // #3 + .WillByDefault(Return(1)); + // ... other default actions ... + + EXPECT_CALL(foo, Describe(5)) // #4 + .Times(3) + .WillRepeatedly(Return("Category 5")); + // ... other expectations ... + + EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 +} // #6 +``` + +# Setting Default Actions # + +Google Mock has a **built-in default action** for any function that +returns `void`, `bool`, a numeric value, or a pointer. + +To customize the default action for functions with return type `T` globally: +``` +using ::testing::DefaultValue; + +// Sets the default value to be returned. T must be CopyConstructible. +DefaultValue::Set(value); +// Sets a factory. Will be invoked on demand. T must be MoveConstructible. +// T MakeT(); +DefaultValue::SetFactory(&MakeT); +// ... use the mocks ... +// Resets the default value. +DefaultValue::Clear(); +``` + +To customize the default action for a particular method, use `ON_CALL()`: +``` +ON_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .WillByDefault(action); +``` + +# Setting Expectations # + +`EXPECT_CALL()` sets **expectations** on a mock method (How will it be +called? What will it do?): +``` +EXPECT_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .Times(cardinality) ? + .InSequence(sequences) * + .After(expectations) * + .WillOnce(action) * + .WillRepeatedly(action) ? + .RetiresOnSaturation(); ? +``` + +If `Times()` is omitted, the cardinality is assumed to be: + + * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; + * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or + * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. + +A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. + +# Matchers # + +A **matcher** matches a _single_ argument. You can use it inside +`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value +directly: + +| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | +|:------------------------------|:----------------------------------------| +| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | + +Built-in matchers (where `argument` is the function argument) are +divided into several categories: + +## Wildcard ## +|`_`|`argument` can be any value of the correct type.| +|:--|:-----------------------------------------------| +|`A()` or `An()`|`argument` can be any value of type `type`. | + +## Generic Comparison ## + +|`Eq(value)` or `value`|`argument == value`| +|:---------------------|:------------------| +|`Ge(value)` |`argument >= value`| +|`Gt(value)` |`argument > value` | +|`Le(value)` |`argument <= value`| +|`Lt(value)` |`argument < value` | +|`Ne(value)` |`argument != value`| +|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| +|`NotNull()` |`argument` is a non-null pointer (raw or smart).| +|`Ref(variable)` |`argument` is a reference to `variable`.| +|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| + +Except `Ref()`, these matchers make a _copy_ of `value` in case it's +modified or destructed later. If the compiler complains that `value` +doesn't have a public copy constructor, try wrap it in `ByRef()`, +e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure +`non_copyable_value` is not changed afterwards, or the meaning of your +matcher will be changed. + +## Floating-Point Matchers ## + +|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| +|:-------------------|:----------------------------------------------------------------------------------------------| +|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | +|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | +|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | + +The above matchers use ULP-based comparison (the same as used in +[Google Test](../../googletest/)). They +automatically pick a reasonable error bound based on the absolute +value of the expected value. `DoubleEq()` and `FloatEq()` conform to +the IEEE standard, which requires comparing two NaNs for equality to +return false. The `NanSensitive*` version instead treats two NaNs as +equal, which is often what a user wants. + +|`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.| +|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------| +|`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | +|`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | +|`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | + +## String Matchers ## + +The `argument` can be either a C string or a C++ string object: + +|`ContainsRegex(string)`|`argument` matches the given regular expression.| +|:----------------------|:-----------------------------------------------| +|`EndsWith(suffix)` |`argument` ends with string `suffix`. | +|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | +|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| +|`StartsWith(prefix)` |`argument` starts with string `prefix`. | +|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | +|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| +|`StrEq(string)` |`argument` is equal to `string`. | +|`StrNe(string)` |`argument` is not equal to `string`. | + +`ContainsRegex()` and `MatchesRegex()` use the regular expression +syntax defined +[here](../../googletest/docs/AdvancedGuide.md#regular-expression-syntax). +`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide +strings as well. + +## Container Matchers ## + +Most STL-style containers support `==`, so you can use +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. If you want to write the elements in-line, +match them more flexibly, or get more informative messages, you can use: + +| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | +|:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------| +| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | +| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | +| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | +| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. | +| `IsEmpty()` | `argument` is an empty container (`container.empty()`). | +| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | +| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | +| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. | +| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. | +| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. | +| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | + +Notes: + + * These matchers can also match: + 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and + 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). + * The array being matched may be multi-dimensional (i.e. its elements can be arrays). + * `m` in `Pointwise(m, ...)` should be a matcher for `::testing::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write: + +``` +using ::testing::get; +MATCHER(FooEq, "") { + return get<0>(arg).Equals(get<1>(arg)); +} +... +EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); +``` + +## Member Matchers ## + +|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| +|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| +|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| +|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | +|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| + +## Matching the Result of a Function or Functor ## + +|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| +|:---------------|:---------------------------------------------------------------------| + +## Pointer Matchers ## + +|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| +|:-----------|:-----------------------------------------------------------------------------------------------| +|`WhenDynamicCastTo(m)`| when `argument` is passed through `dynamic_cast()`, it matches matcher `m`. | + +## Multiargument Matchers ## + +Technically, all matchers match a _single_ value. A "multi-argument" +matcher is just one that matches a _tuple_. The following matchers can +be used to match a tuple `(x, y)`: + +|`Eq()`|`x == y`| +|:-----|:-------| +|`Ge()`|`x >= y`| +|`Gt()`|`x > y` | +|`Le()`|`x <= y`| +|`Lt()`|`x < y` | +|`Ne()`|`x != y`| + +You can use the following selectors to pick a subset of the arguments +(or reorder them) to participate in the matching: + +|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| +|:-----------|:-------------------------------------------------------------------| +|`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| + +## Composite Matchers ## + +You can make a matcher from one or more other matchers: + +|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| +|:-----------------------|:---------------------------------------------------| +|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| +|`Not(m)` |`argument` doesn't match matcher `m`. | + +## Adapters for Matchers ## + +|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| +|:------------------|:--------------------------------------| +|`SafeMatcherCast(m)`| [safely casts](CookBook.md#casting-matchers) matcher `m` to type `Matcher`. | +|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| + +## Matchers as Predicates ## + +|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| +|:------------------|:---------------------------------------------------------------------------------------------| +|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | +|`Value(value, m)` |evaluates to `true` if `value` matches `m`. | + +## Defining Matchers ## + +| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | +|:-------------------------------------------------|:------------------------------------------------------| +| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | +| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | + +**Notes:** + + 1. The `MATCHER*` macros cannot be used inside a function or class. + 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). + 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. + +## Matchers as Test Assertions ## + +|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](../../googletest/docs/Primer.md#assertions) if the value of `expression` doesn't match matcher `m`.| +|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| +|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | + +# Actions # + +**Actions** specify what a mock function should do when invoked. + +## Returning a Value ## + +|`Return()`|Return from a `void` mock function.| +|:---------|:----------------------------------| +|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| +|`ReturnArg()`|Return the `N`-th (0-based) argument.| +|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| +|`ReturnNull()`|Return a null pointer. | +|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| +|`ReturnRef(variable)`|Return a reference to `variable`. | +|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| + +## Side Effects ## + +|`Assign(&variable, value)`|Assign `value` to variable.| +|:-------------------------|:--------------------------| +| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | +| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | +| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | +| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | +|`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| +|`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| +|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| +|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| +|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| + +## Using a Function or a Functor as an Action ## + +|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| +|:----------|:-----------------------------------------------------------------------------------------------------------------| +|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | +|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | +|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | +|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| + +The return value of the invoked function is used as the return value +of the action. + +When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: +``` + double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } + ... + EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); +``` + +In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, +``` + InvokeArgument<2>(5, string("Hi"), ByRef(foo)) +``` +calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. + +## Default Action ## + +|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| +|:------------|:--------------------------------------------------------------------| + +**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. + +## Composite Actions ## + +|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | +|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| +|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | +|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | +|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | +|`WithoutArgs(a)` |Perform action `a` without any arguments. | + +## Defining Actions ## + +| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | +|:--------------------------------------|:---------------------------------------------------------------------------------------| +| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | +| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | + +The `ACTION*` macros cannot be used inside a function or class. + +# Cardinalities # + +These are used in `Times()` to specify how many times a mock function will be called: + +|`AnyNumber()`|The function can be called any number of times.| +|:------------|:----------------------------------------------| +|`AtLeast(n)` |The call is expected at least `n` times. | +|`AtMost(n)` |The call is expected at most `n` times. | +|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| +|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| + +# Expectation Order # + +By default, the expectations can be matched in _any_ order. If some +or all expectations must be matched in a given order, there are two +ways to specify it. They can be used either independently or +together. + +## The After Clause ## + +``` +using ::testing::Expectation; +... +Expectation init_x = EXPECT_CALL(foo, InitX()); +Expectation init_y = EXPECT_CALL(foo, InitY()); +EXPECT_CALL(foo, Bar()) + .After(init_x, init_y); +``` +says that `Bar()` can be called only after both `InitX()` and +`InitY()` have been called. + +If you don't know how many pre-requisites an expectation has when you +write it, you can use an `ExpectationSet` to collect them: + +``` +using ::testing::ExpectationSet; +... +ExpectationSet all_inits; +for (int i = 0; i < element_count; i++) { + all_inits += EXPECT_CALL(foo, InitElement(i)); +} +EXPECT_CALL(foo, Bar()) + .After(all_inits); +``` +says that `Bar()` can be called only after all elements have been +initialized (but we don't care about which elements get initialized +before the others). + +Modifying an `ExpectationSet` after using it in an `.After()` doesn't +affect the meaning of the `.After()`. + +## Sequences ## + +When you have a long chain of sequential expectations, it's easier to +specify the order using **sequences**, which don't require you to given +each expectation in the chain a different name. All expected
+calls
in the same sequence must occur in the order they are +specified. + +``` +using ::testing::Sequence; +Sequence s1, s2; +... +EXPECT_CALL(foo, Reset()) + .InSequence(s1, s2) + .WillOnce(Return(true)); +EXPECT_CALL(foo, GetSize()) + .InSequence(s1) + .WillOnce(Return(1)); +EXPECT_CALL(foo, Describe(A())) + .InSequence(s2) + .WillOnce(Return("dummy")); +``` +says that `Reset()` must be called before _both_ `GetSize()` _and_ +`Describe()`, and the latter two can occur in any order. + +To put many expectations in a sequence conveniently: +``` +using ::testing::InSequence; +{ + InSequence dummy; + + EXPECT_CALL(...)...; + EXPECT_CALL(...)...; + ... + EXPECT_CALL(...)...; +} +``` +says that all expected calls in the scope of `dummy` must occur in +strict order. The name `dummy` is irrelevant.) + +# Verifying and Resetting a Mock # + +Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: +``` +using ::testing::Mock; +... +// Verifies and removes the expectations on mock_obj; +// returns true iff successful. +Mock::VerifyAndClearExpectations(&mock_obj); +... +// Verifies and removes the expectations on mock_obj; +// also removes the default actions set by ON_CALL(); +// returns true iff successful. +Mock::VerifyAndClear(&mock_obj); +``` + +You can also tell Google Mock that a mock object can be leaked and doesn't +need to be verified: +``` +Mock::AllowLeak(&mock_obj); +``` + +# Mock Classes # + +Google Mock defines a convenient mock class template +``` +class MockFunction { + public: + MOCK_METHODn(Call, R(A1, ..., An)); +}; +``` +See this [recipe](CookBook.md#using-check-points) for one application of it. + +# Flags # + +| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | +|:-------------------------------|:----------------------------------------------| +| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | diff --git a/googlemock/docs/CookBook.md b/googlemock/docs/CookBook.md new file mode 100644 index 0000000..c52f100 --- /dev/null +++ b/googlemock/docs/CookBook.md @@ -0,0 +1,3675 @@ + + +You can find recipes for using Google Mock here. If you haven't yet, +please read the [ForDummies](ForDummies.md) document first to make sure you understand +the basics. + +**Note:** Google Mock lives in the `testing` name space. For +readability, it is recommended to write `using ::testing::Foo;` once in +your file before using the name `Foo` defined by Google Mock. We omit +such `using` statements in this page for brevity, but you should do it +in your own code. + +# Creating Mock Classes # + +## Mocking Private or Protected Methods ## + +You must always put a mock method definition (`MOCK_METHOD*`) in a +`public:` section of the mock class, regardless of the method being +mocked being `public`, `protected`, or `private` in the base class. +This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function +from outside of the mock class. (Yes, C++ allows a subclass to change +the access level of a virtual function in the base class.) Example: + +``` +class Foo { + public: + ... + virtual bool Transform(Gadget* g) = 0; + + protected: + virtual void Resume(); + + private: + virtual int GetTimeOut(); +}; + +class MockFoo : public Foo { + public: + ... + MOCK_METHOD1(Transform, bool(Gadget* g)); + + // The following must be in the public section, even though the + // methods are protected or private in the base class. + MOCK_METHOD0(Resume, void()); + MOCK_METHOD0(GetTimeOut, int()); +}; +``` + +## Mocking Overloaded Methods ## + +You can mock overloaded functions as usual. No special attention is required: + +``` +class Foo { + ... + + // Must be virtual as we'll inherit from Foo. + virtual ~Foo(); + + // Overloaded on the types and/or numbers of arguments. + virtual int Add(Element x); + virtual int Add(int times, Element x); + + // Overloaded on the const-ness of this object. + virtual Bar& GetBar(); + virtual const Bar& GetBar() const; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Add, int(Element x)); + MOCK_METHOD2(Add, int(int times, Element x); + + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +``` + +**Note:** if you don't mock all versions of the overloaded method, the +compiler will give you a warning about some methods in the base class +being hidden. To fix that, use `using` to bring them in scope: + +``` +class MockFoo : public Foo { + ... + using Foo::Add; + MOCK_METHOD1(Add, int(Element x)); + // We don't want to mock int Add(int times, Element x); + ... +}; +``` + +## Mocking Class Templates ## + +To mock a class template, append `_T` to the `MOCK_*` macros: + +``` +template +class StackInterface { + ... + // Must be virtual as we'll inherit from StackInterface. + virtual ~StackInterface(); + + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; + +template +class MockStack : public StackInterface { + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Mocking Nonvirtual Methods ## + +Google Mock can mock non-virtual functions to be used in what we call _hi-perf +dependency injection_. + +In this case, instead of sharing a common base class with the real +class, your mock class will be _unrelated_ to the real class, but +contain methods with the same signatures. The syntax for mocking +non-virtual methods is the _same_ as mocking virtual methods: + +``` +// A simple packet stream class. None of its members is virtual. +class ConcretePacketStream { + public: + void AppendPacket(Packet* new_packet); + const Packet* GetPacket(size_t packet_number) const; + size_t NumberOfPackets() const; + ... +}; + +// A mock packet stream class. It inherits from no other, but defines +// GetPacket() and NumberOfPackets(). +class MockPacketStream { + public: + MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); + MOCK_CONST_METHOD0(NumberOfPackets, size_t()); + ... +}; +``` + +Note that the mock class doesn't define `AppendPacket()`, unlike the +real class. That's fine as long as the test doesn't need to call it. + +Next, you need a way to say that you want to use +`ConcretePacketStream` in production code, and use `MockPacketStream` +in tests. Since the functions are not virtual and the two classes are +unrelated, you must specify your choice at _compile time_ (as opposed +to run time). + +One way to do it is to templatize your code that needs to use a packet +stream. More specifically, you will give your code a template type +argument for the type of the packet stream. In production, you will +instantiate your template with `ConcretePacketStream` as the type +argument. In tests, you will instantiate the same template with +`MockPacketStream`. For example, you may write: + +``` +template +void CreateConnection(PacketStream* stream) { ... } + +template +class PacketReader { + public: + void ReadPackets(PacketStream* stream, size_t packet_num); +}; +``` + +Then you can use `CreateConnection()` and +`PacketReader` in production code, and use +`CreateConnection()` and +`PacketReader` in tests. + +``` + MockPacketStream mock_stream; + EXPECT_CALL(mock_stream, ...)...; + .. set more expectations on mock_stream ... + PacketReader reader(&mock_stream); + ... exercise reader ... +``` + +## Mocking Free Functions ## + +It's possible to use Google Mock to mock a free function (i.e. a +C-style function or a static method). You just need to rewrite your +code to use an interface (abstract class). + +Instead of calling a free function (say, `OpenFile`) directly, +introduce an interface for it and have a concrete subclass that calls +the free function: + +``` +class FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) = 0; +}; + +class File : public FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) { + return OpenFile(path, mode); + } +}; +``` + +Your code should talk to `FileInterface` to open a file. Now it's +easy to mock out the function. + +This may seem much hassle, but in practice you often have multiple +related functions that you can put in the same interface, so the +per-function syntactic overhead will be much lower. + +If you are concerned about the performance overhead incurred by +virtual functions, and profiling confirms your concern, you can +combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). + +## The Nice, the Strict, and the Naggy ## + +If a mock method has no `EXPECT_CALL` spec but is called, Google Mock +will print a warning about the "uninteresting call". The rationale is: + + * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. + * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. + +However, sometimes you may want to suppress all "uninteresting call" +warnings, while sometimes you may want the opposite, i.e. to treat all +of them as errors. Google Mock lets you make the decision on a +per-mock-object basis. + +Suppose your test uses a mock class `MockFoo`: + +``` +TEST(...) { + MockFoo mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +If a method of `mock_foo` other than `DoThis()` is called, it will be +reported by Google Mock as a warning. However, if you rewrite your +test to use `NiceMock` instead, the warning will be gone, +resulting in a cleaner test output: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +`NiceMock` is a subclass of `MockFoo`, so it can be used +wherever `MockFoo` is accepted. + +It also works if `MockFoo`'s constructor takes some arguments, as +`NiceMock` "inherits" `MockFoo`'s constructors: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +The usage of `StrictMock` is similar, except that it makes all +uninteresting calls failures: + +``` +using ::testing::StrictMock; + +TEST(...) { + StrictMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... + + // The test will fail if a method of mock_foo other than DoThis() + // is called. +} +``` + +There are some caveats though (I don't like them just as much as the +next guy, but sadly they are side effects of C++'s limitations): + + 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. + 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). + 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) + +Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. + +## Simplifying the Interface without Breaking Existing Code ## + +Sometimes a method has a long list of arguments that is mostly +uninteresting. For example, + +``` +class LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const struct tm* tm_time, + const char* message, size_t message_len) = 0; +}; +``` + +This method's argument list is lengthy and hard to work with (let's +say that the `message` argument is not even 0-terminated). If we mock +it as is, using the mock will be awkward. If, however, we try to +simplify this interface, we'll need to fix all clients depending on +it, which is often infeasible. + +The trick is to re-dispatch the method in the mock class: + +``` +class ScopedMockLog : public LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, const tm* tm_time, + const char* message, size_t message_len) { + // We are only interested in the log severity, full file name, and + // log message. + Log(severity, full_filename, std::string(message, message_len)); + } + + // Implements the mock method: + // + // void Log(LogSeverity severity, + // const string& file_path, + // const string& message); + MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, + const string& message)); +}; +``` + +By defining a new mock method with a trimmed argument list, we make +the mock class much more user-friendly. + +## Alternative to Mocking Concrete Classes ## + +Often you may find yourself using classes that don't implement +interfaces. In order to test your code that uses such a class (let's +call it `Concrete`), you may be tempted to make the methods of +`Concrete` virtual and then mock it. + +Try not to do that. + +Making a non-virtual function virtual is a big decision. It creates an +extension point where subclasses can tweak your class' behavior. This +weakens your control on the class because now it's harder to maintain +the class' invariants. You should make a function virtual only when +there is a valid reason for a subclass to override it. + +Mocking concrete classes directly is problematic as it creates a tight +coupling between the class and the tests - any small change in the +class may invalidate your tests and make test maintenance a pain. + +To avoid such problems, many programmers have been practicing "coding +to interfaces": instead of talking to the `Concrete` class, your code +would define an interface and talk to it. Then you implement that +interface as an adaptor on top of `Concrete`. In tests, you can easily +mock that interface to observe how your code is doing. + +This technique incurs some overhead: + + * You pay the cost of virtual function calls (usually not a problem). + * There is more abstraction for the programmers to learn. + +However, it can also bring significant benefits in addition to better +testability: + + * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. + * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. + +Some people worry that if everyone is practicing this technique, they +will end up writing lots of redundant code. This concern is totally +understandable. However, there are two reasons why it may not be the +case: + + * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. + * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. + +You need to weigh the pros and cons carefully for your particular +problem, but I'd like to assure you that the Java community has been +practicing this for a long time and it's a proven effective technique +applicable in a wide variety of situations. :-) + +## Delegating Calls to a Fake ## + +Some times you have a non-trivial fake implementation of an +interface. For example: + +``` +class Foo { + public: + virtual ~Foo() {} + virtual char DoThis(int n) = 0; + virtual void DoThat(const char* s, int* p) = 0; +}; + +class FakeFoo : public Foo { + public: + virtual char DoThis(int n) { + return (n > 0) ? '+' : + (n < 0) ? '-' : '0'; + } + + virtual void DoThat(const char* s, int* p) { + *p = strlen(s); + } +}; +``` + +Now you want to mock this interface such that you can set expectations +on it. However, you also want to use `FakeFoo` for the default +behavior, as duplicating it in the mock object is, well, a lot of +work. + +When you define the mock class using Google Mock, you can have it +delegate its default action to a fake class you already have, using +this pattern: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + // Normal mock method definitions using Google Mock. + MOCK_METHOD1(DoThis, char(int n)); + MOCK_METHOD2(DoThat, void(const char* s, int* p)); + + // Delegates the default actions of the methods to a FakeFoo object. + // This must be called *before* the custom ON_CALL() statements. + void DelegateToFake() { + ON_CALL(*this, DoThis(_)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); + ON_CALL(*this, DoThat(_, _)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); + } + private: + FakeFoo fake_; // Keeps an instance of the fake in the mock. +}; +``` + +With that, you can use `MockFoo` in your tests as usual. Just remember +that if you don't explicitly set an action in an `ON_CALL()` or +`EXPECT_CALL()`, the fake will be called upon to do it: + +``` +using ::testing::_; + +TEST(AbcTest, Xyz) { + MockFoo foo; + foo.DelegateToFake(); // Enables the fake for delegation. + + // Put your ON_CALL(foo, ...)s here, if any. + + // No action specified, meaning to use the default action. + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(foo, DoThat(_, _)); + + int n = 0; + EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. + foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. + EXPECT_EQ(2, n); +} +``` + +**Some tips:** + + * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. + * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. + * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). + * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. + +Regarding the tip on mixing a mock and a fake, here's an example on +why it may be a bad sign: Suppose you have a class `System` for +low-level system operations. In particular, it does file and I/O +operations. And suppose you want to test how your code uses `System` +to do I/O, and you just want the file operations to work normally. If +you mock out the entire `System` class, you'll have to provide a fake +implementation for the file operation part, which suggests that +`System` is taking on too many roles. + +Instead, you can define a `FileOps` interface and an `IOOps` interface +and split `System`'s functionalities into the two. Then you can mock +`IOOps` without mocking `FileOps`. + +## Delegating Calls to a Real Object ## + +When using testing doubles (mocks, fakes, stubs, and etc), sometimes +their behaviors will differ from those of the real objects. This +difference could be either intentional (as in simulating an error such +that you can test the error handling code) or unintentional. If your +mocks have different behaviors than the real objects by mistake, you +could end up with code that passes the tests but fails in production. + +You can use the _delegating-to-real_ technique to ensure that your +mock has the same behavior as the real object while retaining the +ability to validate calls. This technique is very similar to the +delegating-to-fake technique, the difference being that we use a real +object instead of a fake. Here's an example: + +``` +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MockFoo() { + // By default, all calls are delegated to the real object. + ON_CALL(*this, DoThis()) + .WillByDefault(Invoke(&real_, &Foo::DoThis)); + ON_CALL(*this, DoThat(_)) + .WillByDefault(Invoke(&real_, &Foo::DoThat)); + ... + } + MOCK_METHOD0(DoThis, ...); + MOCK_METHOD1(DoThat, ...); + ... + private: + Foo real_; +}; +... + + MockFoo mock; + + EXPECT_CALL(mock, DoThis()) + .Times(3); + EXPECT_CALL(mock, DoThat("Hi")) + .Times(AtLeast(1)); + ... use mock in test ... +``` + +With this, Google Mock will verify that your code made the right calls +(with the right arguments, in the right order, called the right number +of times, etc), and a real object will answer the calls (so the +behavior will be the same as in production). This gives you the best +of both worlds. + +## Delegating Calls to a Parent Class ## + +Ideally, you should code to interfaces, whose methods are all pure +virtual. In reality, sometimes you do need to mock a virtual method +that is not pure (i.e, it already has an implementation). For example: + +``` +class Foo { + public: + virtual ~Foo(); + + virtual void Pure(int n) = 0; + virtual int Concrete(const char* str) { ... } +}; + +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); +}; +``` + +Sometimes you may want to call `Foo::Concrete()` instead of +`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub +action, or perhaps your test doesn't need to mock `Concrete()` at all +(but it would be oh-so painful to have to define a new mock class +whenever you don't need to mock one of its methods). + +The trick is to leave a back door in your mock class for accessing the +real methods in the base class: + +``` +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); + + // Use this to call Concrete() defined in Foo. + int FooConcrete(const char* str) { return Foo::Concrete(str); } +}; +``` + +Now, you can call `Foo::Concrete()` inside an action by: + +``` +using ::testing::_; +using ::testing::Invoke; +... + EXPECT_CALL(foo, Concrete(_)) + .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +or tell the mock object that you don't want to mock `Concrete()`: + +``` +using ::testing::Invoke; +... + ON_CALL(foo, Concrete(_)) + .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do +that, `MockFoo::Concrete()` will be called (and cause an infinite +recursion) since `Foo::Concrete()` is virtual. That's just how C++ +works.) + +# Using Matchers # + +## Matching Argument Values Exactly ## + +You can specify exactly which arguments a mock method is expecting: + +``` +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(5)) + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", bar)); +``` + +## Using Simple Matchers ## + +You can use matchers to match arguments that have a certain property: + +``` +using ::testing::Ge; +using ::testing::NotNull; +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", NotNull())); + // The second argument must not be NULL. +``` + +A frequently used matcher is `_`, which matches anything: + +``` +using ::testing::_; +using ::testing::NotNull; +... + EXPECT_CALL(foo, DoThat(_, NotNull())); +``` + +## Combining Matchers ## + +You can build complex matchers from existing ones using `AllOf()`, +`AnyOf()`, and `Not()`: + +``` +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::HasSubstr; +using ::testing::Ne; +using ::testing::Not; +... + // The argument must be > 5 and != 10. + EXPECT_CALL(foo, DoThis(AllOf(Gt(5), + Ne(10)))); + + // The first argument must not contain sub-string "blah". + EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), + NULL)); +``` + +## Casting Matchers ## + +Google Mock matchers are statically typed, meaning that the compiler +can catch your mistake if you use a matcher of the wrong type (for +example, if you use `Eq(5)` to match a `string` argument). Good for +you! + +Sometimes, however, you know what you're doing and want the compiler +to give you some slack. One example is that you have a matcher for +`long` and the argument you want to match is `int`. While the two +types aren't exactly the same, there is nothing really wrong with +using a `Matcher` to match an `int` - after all, we can first +convert the `int` argument to a `long` before giving it to the +matcher. + +To support this need, Google Mock gives you the +`SafeMatcherCast(m)` function. It casts a matcher `m` to type +`Matcher`. To ensure safety, Google Mock checks that (let `U` be the +type `m` accepts): + + 1. Type `T` can be implicitly cast to type `U`; + 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and + 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). + +The code won't compile if any of these conditions isn't met. + +Here's one example: + +``` +using ::testing::SafeMatcherCast; + +// A base class and a child class. +class Base { ... }; +class Derived : public Base { ... }; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(DoThis, void(Derived* derived)); +}; +... + + MockFoo foo; + // m is a Matcher we got from somewhere. + EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); +``` + +If you find `SafeMatcherCast(m)` too limiting, you can use a similar +function `MatcherCast(m)`. The difference is that `MatcherCast` works +as long as you can `static_cast` type `T` to type `U`. + +`MatcherCast` essentially lets you bypass C++'s type system +(`static_cast` isn't always safe as it could throw away information, +for example), so be careful not to misuse/abuse it. + +## Selecting Between Overloaded Functions ## + +If you expect an overloaded function to be called, the compiler may +need some help on which overloaded version it is. + +To disambiguate functions overloaded on the const-ness of this object, +use the `Const()` argument wrapper. + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + ... + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +... + + MockFoo foo; + Bar bar1, bar2; + EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). + .WillOnce(ReturnRef(bar1)); + EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). + .WillOnce(ReturnRef(bar2)); +``` + +(`Const()` is defined by Google Mock and returns a `const` reference +to its argument.) + +To disambiguate overloaded functions with the same number of arguments +but different argument types, you may need to specify the exact type +of a matcher, either by wrapping your matcher in `Matcher()`, or +using a matcher whose type is fixed (`TypedEq`, `An()`, +etc): + +``` +using ::testing::An; +using ::testing::Lt; +using ::testing::Matcher; +using ::testing::TypedEq; + +class MockPrinter : public Printer { + public: + MOCK_METHOD1(Print, void(int n)); + MOCK_METHOD1(Print, void(char c)); +}; + +TEST(PrinterTest, Print) { + MockPrinter printer; + + EXPECT_CALL(printer, Print(An())); // void Print(int); + EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); + EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); + + printer.Print(3); + printer.Print(6); + printer.Print('a'); +} +``` + +## Performing Different Actions Based on the Arguments ## + +When a mock method is called, the _last_ matching expectation that's +still active will be selected (think "newer overrides older"). So, you +can make a method do different things depending on its argument values +like this: + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Return; +... + // The default case. + EXPECT_CALL(foo, DoThis(_)) + .WillRepeatedly(Return('b')); + + // The more specific case. + EXPECT_CALL(foo, DoThis(Lt(5))) + .WillRepeatedly(Return('a')); +``` + +Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will +be returned; otherwise `'b'` will be returned. + +## Matching Multiple Arguments as a Whole ## + +Sometimes it's not enough to match the arguments individually. For +example, we may want to say that the first argument must be less than +the second argument. The `With()` clause allows us to match +all arguments of a mock function as a whole. For example, + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Ne; +... + EXPECT_CALL(foo, InRange(Ne(0), _)) + .With(Lt()); +``` + +says that the first argument of `InRange()` must not be 0, and must be +less than the second argument. + +The expression inside `With()` must be a matcher of type +`Matcher< ::testing::tuple >`, where `A1`, ..., `An` are the +types of the function arguments. + +You can also write `AllArgs(m)` instead of `m` inside `.With()`. The +two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable +than `.With(Lt())`. + +You can use `Args(m)` to match the `n` selected arguments +(as a tuple) against `m`. For example, + +``` +using ::testing::_; +using ::testing::AllOf; +using ::testing::Args; +using ::testing::Lt; +... + EXPECT_CALL(foo, Blah(_, _, _)) + .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); +``` + +says that `Blah()` will be called with arguments `x`, `y`, and `z` where +`x < y < z`. + +As a convenience and example, Google Mock provides some matchers for +2-tuples, including the `Lt()` matcher above. See the [CheatSheet](CheatSheet.md) for +the complete list. + +Note that if you want to pass the arguments to a predicate of your own +(e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be +written to take a `::testing::tuple` as its argument; Google Mock will pass the `n` selected arguments as _one_ single tuple to the predicate. + +## Using Matchers as Predicates ## + +Have you noticed that a matcher is just a fancy predicate that also +knows how to describe itself? Many existing algorithms take predicates +as arguments (e.g. those defined in STL's `` header), and +it would be a shame if Google Mock matchers are not allowed to +participate. + +Luckily, you can use a matcher where a unary predicate functor is +expected by wrapping it inside the `Matches()` function. For example, + +``` +#include +#include + +std::vector v; +... +// How many elements in v are >= 10? +const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); +``` + +Since you can build complex matchers from simpler ones easily using +Google Mock, this gives you a way to conveniently construct composite +predicates (doing the same using STL's `` header is just +painful). For example, here's a predicate that's satisfied by any +number that is >= 0, <= 100, and != 50: + +``` +Matches(AllOf(Ge(0), Le(100), Ne(50))) +``` + +## Using Matchers in Google Test Assertions ## + +Since matchers are basically predicates that also know how to describe +themselves, there is a way to take advantage of them in +[Google Test](../../googletest/) assertions. It's +called `ASSERT_THAT` and `EXPECT_THAT`: + +``` + ASSERT_THAT(value, matcher); // Asserts that value matches matcher. + EXPECT_THAT(value, matcher); // The non-fatal version. +``` + +For example, in a Google Test test you can write: + +``` +#include "gmock/gmock.h" + +using ::testing::AllOf; +using ::testing::Ge; +using ::testing::Le; +using ::testing::MatchesRegex; +using ::testing::StartsWith; +... + + EXPECT_THAT(Foo(), StartsWith("Hello")); + EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); + ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); +``` + +which (as you can probably guess) executes `Foo()`, `Bar()`, and +`Baz()`, and verifies that: + + * `Foo()` returns a string that starts with `"Hello"`. + * `Bar()` returns a string that matches regular expression `"Line \\d+"`. + * `Baz()` returns a number in the range [5, 10]. + +The nice thing about these macros is that _they read like +English_. They generate informative messages too. For example, if the +first `EXPECT_THAT()` above fails, the message will be something like: + +``` +Value of: Foo() + Actual: "Hi, world!" +Expected: starts with "Hello" +``` + +**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the +[Hamcrest](https://github.com/hamcrest/) project, which adds +`assertThat()` to JUnit. + +## Using Predicates as Matchers ## + +Google Mock provides a built-in set of matchers. In case you find them +lacking, you can use an arbitray unary predicate function or functor +as a matcher - as long as the predicate accepts a value of the type +you want. You do this by wrapping the predicate inside the `Truly()` +function, for example: + +``` +using ::testing::Truly; + +int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } +... + + // Bar() must be called with an even number. + EXPECT_CALL(foo, Bar(Truly(IsEven))); +``` + +Note that the predicate function / functor doesn't have to return +`bool`. It works as long as the return value can be used as the +condition in statement `if (condition) ...`. + +## Matching Arguments that Are Not Copyable ## + +When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves +away a copy of `bar`. When `Foo()` is called later, Google Mock +compares the argument to `Foo()` with the saved copy of `bar`. This +way, you don't need to worry about `bar` being modified or destroyed +after the `EXPECT_CALL()` is executed. The same is true when you use +matchers like `Eq(bar)`, `Le(bar)`, and so on. + +But what if `bar` cannot be copied (i.e. has no copy constructor)? You +could define your own matcher function and use it with `Truly()`, as +the previous couple of recipes have shown. Or, you may be able to get +away from it if you can guarantee that `bar` won't be changed after +the `EXPECT_CALL()` is executed. Just tell Google Mock that it should +save a reference to `bar`, instead of a copy of it. Here's how: + +``` +using ::testing::Eq; +using ::testing::ByRef; +using ::testing::Lt; +... + // Expects that Foo()'s argument == bar. + EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); + + // Expects that Foo()'s argument < bar. + EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); +``` + +Remember: if you do this, don't change `bar` after the +`EXPECT_CALL()`, or the result is undefined. + +## Validating a Member of an Object ## + +Often a mock function takes a reference to object as an argument. When +matching the argument, you may not want to compare the entire object +against a fixed object, as that may be over-specification. Instead, +you may need to validate a certain member variable or the result of a +certain getter method of the object. You can do this with `Field()` +and `Property()`. More specifically, + +``` +Field(&Foo::bar, m) +``` + +is a matcher that matches a `Foo` object whose `bar` member variable +satisfies matcher `m`. + +``` +Property(&Foo::baz, m) +``` + +is a matcher that matches a `Foo` object whose `baz()` method returns +a value that satisfies matcher `m`. + +For example: + +> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | +|:-----------------------------|:-----------------------------------| +> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | + +Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no +argument and be declared as `const`. + +BTW, `Field()` and `Property()` can also match plain pointers to +objects. For instance, + +``` +Field(&Foo::number, Ge(3)) +``` + +matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, +the match will always fail regardless of the inner matcher. + +What if you want to validate more than one members at the same time? +Remember that there is `AllOf()`. + +## Validating the Value Pointed to by a Pointer Argument ## + +C++ functions often take pointers as arguments. You can use matchers +like `IsNull()`, `NotNull()`, and other comparison matchers to match a +pointer, but what if you want to make sure the value _pointed to_ by +the pointer, instead of the pointer itself, has a certain property? +Well, you can use the `Pointee(m)` matcher. + +`Pointee(m)` matches a pointer iff `m` matches the value the pointer +points to. For example: + +``` +using ::testing::Ge; +using ::testing::Pointee; +... + EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); +``` + +expects `foo.Bar()` to be called with a pointer that points to a value +greater than or equal to 3. + +One nice thing about `Pointee()` is that it treats a `NULL` pointer as +a match failure, so you can write `Pointee(m)` instead of + +``` + AllOf(NotNull(), Pointee(m)) +``` + +without worrying that a `NULL` pointer will crash your test. + +Also, did we tell you that `Pointee()` works with both raw pointers +**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and +etc)? + +What if you have a pointer to pointer? You guessed it - you can use +nested `Pointee()` to probe deeper inside the value. For example, +`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer +that points to a number less than 3 (what a mouthful...). + +## Testing a Certain Property of an Object ## + +Sometimes you want to specify that an object argument has a certain +property, but there is no existing matcher that does this. If you want +good error messages, you should define a matcher. If you want to do it +quick and dirty, you could get away with writing an ordinary function. + +Let's say you have a mock function that takes an object of type `Foo`, +which has an `int bar()` method and an `int baz()` method, and you +want to constrain that the argument's `bar()` value plus its `baz()` +value is a given number. Here's how you can define a matcher to do it: + +``` +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class BarPlusBazEqMatcher : public MatcherInterface { + public: + explicit BarPlusBazEqMatcher(int expected_sum) + : expected_sum_(expected_sum) {} + + virtual bool MatchAndExplain(const Foo& foo, + MatchResultListener* listener) const { + return (foo.bar() + foo.baz()) == expected_sum_; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "bar() + baz() equals " << expected_sum_; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "bar() + baz() does not equal " << expected_sum_; + } + private: + const int expected_sum_; +}; + +inline Matcher BarPlusBazEq(int expected_sum) { + return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); +} + +... + + EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; +``` + +## Matching Containers ## + +Sometimes an STL container (e.g. list, vector, map, ...) is passed to +a mock function and you may want to validate it. Since most STL +containers support the `==` operator, you can write +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. + +Sometimes, though, you may want to be more flexible (for example, the +first element must be an exact match, but the second element can be +any positive number, and so on). Also, containers used in tests often +have a small number of elements, and having to define the expected +container out-of-line is a bit of a hassle. + +You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in +such cases: + +``` +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Gt; +... + + MOCK_METHOD1(Foo, void(const vector& numbers)); +... + + EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); +``` + +The above matcher says that the container must have 4 elements, which +must be 1, greater than 0, anything, and 5 respectively. + +If you instead write: + +``` +using ::testing::_; +using ::testing::Gt; +using ::testing::UnorderedElementsAre; +... + + MOCK_METHOD1(Foo, void(const vector& numbers)); +... + + EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); +``` + +It means that the container must have 4 elements, which under some +permutation must be 1, greater than 0, anything, and 5 respectively. + +`ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0 +to 10 arguments. If more are needed, you can place them in a C-style +array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` +instead: + +``` +using ::testing::ElementsAreArray; +... + + // ElementsAreArray accepts an array of element values. + const int expected_vector1[] = { 1, 5, 2, 4, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); + + // Or, an array of element matchers. + Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); +``` + +In case the array needs to be dynamically created (and therefore the +array size cannot be inferred by the compiler), you can give +`ElementsAreArray()` an additional argument to specify the array size: + +``` +using ::testing::ElementsAreArray; +... + int* const expected_vector3 = new int[count]; + ... fill expected_vector3 with values ... + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); +``` + +**Tips:** + + * `ElementsAre*()` can be used to match _any_ container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. + * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. + * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. + * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). + +## Sharing Matchers ## + +Under the hood, a Google Mock matcher object consists of a pointer to +a ref-counted implementation object. Copying matchers is allowed and +very efficient, as only the pointer is copied. When the last matcher +that references the implementation object dies, the implementation +object will be deleted. + +Therefore, if you have some complex matcher that you want to use again +and again, there is no need to build it everytime. Just assign it to a +matcher variable and use that variable repeatedly! For example, + +``` + Matcher in_range = AllOf(Gt(5), Le(10)); + ... use in_range as a matcher in multiple EXPECT_CALLs ... +``` + +# Setting Expectations # + +## Knowing When to Expect ## + +`ON_CALL` is likely the single most under-utilized construct in Google Mock. + +There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but _doesn't imply any expectation on the method being called._ `EXPECT_CALL` not only defines the behavior, but also sets an expectation that _the method will be called with the given arguments, for the given number of times_ (and _in the given order_ when you specify the order too). + +Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is _baaad_ - even worse than not having enough constraints. + +This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? + +The answer, lies in _what_ a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. + +Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. + +So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). + +If you are bothered by the "Uninteresting mock function call" message printed when a mock method without an `EXPECT_CALL` is called, you may use a `NiceMock` instead to suppress all such messages for the mock object, or suppress the message for specific methods by adding `EXPECT_CALL(...).Times(AnyNumber())`. DO NOT suppress it by blindly adding an `EXPECT_CALL(...)`, or you'll have a test that's a pain to maintain. + +## Ignoring Uninteresting Calls ## + +If you are not interested in how a mock method is called, just don't +say anything about it. In this case, if the method is ever called, +Google Mock will perform its default action to allow the test program +to continue. If you are not happy with the default action taken by +Google Mock, you can override it using `DefaultValue::Set()` +(described later in this document) or `ON_CALL()`. + +Please note that once you expressed interest in a particular mock +method (via `EXPECT_CALL()`), all invocations to it must match some +expectation. If this function is called but the arguments don't match +any `EXPECT_CALL()` statement, it will be an error. + +## Disallowing Unexpected Calls ## + +If a mock method shouldn't be called at all, explicitly say so: + +``` +using ::testing::_; +... + EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +If some calls to the method are allowed, but the rest are not, just +list all the expected calls: + +``` +using ::testing::AnyNumber; +using ::testing::Gt; +... + EXPECT_CALL(foo, Bar(5)); + EXPECT_CALL(foo, Bar(Gt(10))) + .Times(AnyNumber()); +``` + +A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` +statements will be an error. + +## Understanding Uninteresting vs Unexpected Calls ## + +_Uninteresting_ calls and _unexpected_ calls are different concepts in Google Mock. _Very_ different. + +A call `x.Y(...)` is **uninteresting** if there's _not even a single_ `EXPECT_CALL(x, Y(...))` set. In other words, the test isn't interested in the `x.Y()` method at all, as evident in that the test doesn't care to say anything about it. + +A call `x.Y(...)` is **unexpected** if there are some `EXPECT_CALL(x, Y(...))s` set, but none of them matches the call. Put another way, the test is interested in the `x.Y()` method (therefore it _explicitly_ sets some `EXPECT_CALL` to verify how it's called); however, the verification fails as the test doesn't expect this particular call to happen. + +**An unexpected call is always an error,** as the code under test doesn't behave the way the test expects it to behave. + +**By default, an uninteresting call is not an error,** as it violates no constraint specified by the test. (Google Mock's philosophy is that saying nothing means there is no constraint.) However, it leads to a warning, as it _might_ indicate a problem (e.g. the test author might have forgotten to specify a constraint). + +In Google Mock, `NiceMock` and `StrictMock` can be used to make a mock class "nice" or "strict". How does this affect uninteresting calls and unexpected calls? + +A **nice mock** suppresses uninteresting call warnings. It is less chatty than the default mock, but otherwise is the same. If a test fails with a default mock, it will also fail using a nice mock instead. And vice versa. Don't expect making a mock nice to change the test's result. + +A **strict mock** turns uninteresting call warnings into errors. So making a mock strict may change the test's result. + +Let's look at an example: + +``` +TEST(...) { + NiceMock mock_registry; + EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) + .WillRepeatedly(Return("Larry Page")); + + // Use mock_registry in code under test. + ... &mock_registry ... +} +``` + +The sole `EXPECT_CALL` here says that all calls to `GetDomainOwner()` must have `"google.com"` as the argument. If `GetDomainOwner("yahoo.com")` is called, it will be an unexpected call, and thus an error. Having a nice mock doesn't change the severity of an unexpected call. + +So how do we tell Google Mock that `GetDomainOwner()` can be called with some other arguments as well? The standard technique is to add a "catch all" `EXPECT_CALL`: + +``` + EXPECT_CALL(mock_registry, GetDomainOwner(_)) + .Times(AnyNumber()); // catches all other calls to this method. + EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) + .WillRepeatedly(Return("Larry Page")); +``` + +Remember that `_` is the wildcard matcher that matches anything. With this, if `GetDomainOwner("google.com")` is called, it will do what the second `EXPECT_CALL` says; if it is called with a different argument, it will do what the first `EXPECT_CALL` says. + +Note that the order of the two `EXPECT_CALLs` is important, as a newer `EXPECT_CALL` takes precedence over an older one. + +For more on uninteresting calls, nice mocks, and strict mocks, read ["The Nice, the Strict, and the Naggy"](#the-nice-the-strict-and-the-naggy). + +## Expecting Ordered Calls ## + +Although an `EXPECT_CALL()` statement defined earlier takes precedence +when Google Mock tries to match a function call with an expectation, +by default calls don't have to happen in the order `EXPECT_CALL()` +statements are written. For example, if the arguments match the +matchers in the third `EXPECT_CALL()`, but not those in the first two, +then the third expectation will be used. + +If you would rather have all calls occur in the order of the +expectations, put the `EXPECT_CALL()` statements in a block where you +define a variable of type `InSequence`: + +``` + using ::testing::_; + using ::testing::InSequence; + + { + InSequence s; + + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(bar, DoThat(_)) + .Times(2); + EXPECT_CALL(foo, DoThis(6)); + } +``` + +In this example, we expect a call to `foo.DoThis(5)`, followed by two +calls to `bar.DoThat()` where the argument can be anything, which are +in turn followed by a call to `foo.DoThis(6)`. If a call occurred +out-of-order, Google Mock will report an error. + +## Expecting Partially Ordered Calls ## + +Sometimes requiring everything to occur in a predetermined order can +lead to brittle tests. For example, we may care about `A` occurring +before both `B` and `C`, but aren't interested in the relative order +of `B` and `C`. In this case, the test should reflect our real intent, +instead of being overly constraining. + +Google Mock allows you to impose an arbitrary DAG (directed acyclic +graph) on the calls. One way to express the DAG is to use the +[After](CheatSheet.md#the-after-clause) clause of `EXPECT_CALL`. + +Another way is via the `InSequence()` clause (not the same as the +`InSequence` class), which we borrowed from jMock 2. It's less +flexible than `After()`, but more convenient when you have long chains +of sequential calls, as it doesn't require you to come up with +different names for the expectations in the chains. Here's how it +works: + +If we view `EXPECT_CALL()` statements as nodes in a graph, and add an +edge from node A to node B wherever A must occur before B, we can get +a DAG. We use the term "sequence" to mean a directed path in this +DAG. Now, if we decompose the DAG into sequences, we just need to know +which sequences each `EXPECT_CALL()` belongs to in order to be able to +reconstruct the orginal DAG. + +So, to specify the partial order on the expectations we need to do two +things: first to define some `Sequence` objects, and then for each +`EXPECT_CALL()` say which `Sequence` objects it is part +of. Expectations in the same sequence must occur in the order they are +written. For example, + +``` + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(foo, A()) + .InSequence(s1, s2); + EXPECT_CALL(bar, B()) + .InSequence(s1); + EXPECT_CALL(bar, C()) + .InSequence(s2); + EXPECT_CALL(foo, D()) + .InSequence(s2); +``` + +specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> +C -> D`): + +``` + +---> B + | + A ---| + | + +---> C ---> D +``` + +This means that A must occur before B and C, and C must occur before +D. There's no restriction about the order other than these. + +## Controlling When an Expectation Retires ## + +When a mock method is called, Google Mock only consider expectations +that are still active. An expectation is active when created, and +becomes inactive (aka _retires_) when a call that has to occur later +has occurred. For example, in + +``` + using ::testing::_; + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 + .Times(AnyNumber()) + .InSequence(s1, s2); + EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 + .InSequence(s1); + EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 + .InSequence(s2); +``` + +as soon as either #2 or #3 is matched, #1 will retire. If a warning +`"File too large."` is logged after this, it will be an error. + +Note that an expectation doesn't retire automatically when it's +saturated. For example, + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 +``` + +says that there will be exactly one warning with the message `"File +too large."`. If the second warning contains this message too, #2 will +match again and result in an upper-bound-violated error. + +If this is not what you want, you can ask an expectation to retire as +soon as it becomes saturated: + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 + .RetiresOnSaturation(); +``` + +Here #2 can be used only once, so if you have two warnings with the +message `"File too large."`, the first will match #2 and the second +will match #1 - there will be no error. + +# Using Actions # + +## Returning References from Mock Methods ## + +If a mock function's return type is a reference, you need to use +`ReturnRef()` instead of `Return()` to return a result: + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetBar, Bar&()); +}; +... + + MockFoo foo; + Bar bar; + EXPECT_CALL(foo, GetBar()) + .WillOnce(ReturnRef(bar)); +``` + +## Returning Live Values from Mock Methods ## + +The `Return(x)` action saves a copy of `x` when the action is +_created_, and always returns the same value whenever it's +executed. Sometimes you may want to instead return the _live_ value of +`x` (i.e. its value at the time when the action is _executed_.). + +If the mock function's return type is a reference, you can do it using +`ReturnRef(x)`, as shown in the previous recipe ("Returning References +from Mock Methods"). However, Google Mock doesn't let you use +`ReturnRef()` in a mock function whose return type is not a reference, +as doing that usually indicates a user error. So, what shall you do? + +You may be tempted to try `ByRef()`: + +``` +using testing::ByRef; +using testing::Return; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetValue, int()); +}; +... + int x = 0; + MockFoo foo; + EXPECT_CALL(foo, GetValue()) + .WillRepeatedly(Return(ByRef(x))); + x = 42; + EXPECT_EQ(42, foo.GetValue()); +``` + +Unfortunately, it doesn't work here. The above code will fail with error: + +``` +Value of: foo.GetValue() + Actual: 0 +Expected: 42 +``` + +The reason is that `Return(value)` converts `value` to the actual +return type of the mock function at the time when the action is +_created_, not when it is _executed_. (This behavior was chosen for +the action to be safe when `value` is a proxy object that references +some temporary objects.) As a result, `ByRef(x)` is converted to an +`int` value (instead of a `const int&`) when the expectation is set, +and `Return(ByRef(x))` will always return 0. + +`ReturnPointee(pointer)` was provided to solve this problem +specifically. It returns the value pointed to by `pointer` at the time +the action is _executed_: + +``` +using testing::ReturnPointee; +... + int x = 0; + MockFoo foo; + EXPECT_CALL(foo, GetValue()) + .WillRepeatedly(ReturnPointee(&x)); // Note the & here. + x = 42; + EXPECT_EQ(42, foo.GetValue()); // This will succeed now. +``` + +## Combining Actions ## + +Want to do more than one thing when a function is called? That's +fine. `DoAll()` allow you to do sequence of actions every time. Only +the return value of the last action in the sequence will be used. + +``` +using ::testing::DoAll; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Bar, bool(int n)); +}; +... + + EXPECT_CALL(foo, Bar(_)) + .WillOnce(DoAll(action_1, + action_2, + ... + action_n)); +``` + +## Mocking Side Effects ## + +Sometimes a method exhibits its effect not via returning a value but +via side effects. For example, it may change some global state or +modify an output argument. To mock side effects, in general you can +define your own action by implementing `::testing::ActionInterface`. + +If all you need to do is to change an output argument, the built-in +`SetArgPointee()` action is convenient: + +``` +using ::testing::SetArgPointee; + +class MockMutator : public Mutator { + public: + MOCK_METHOD2(Mutate, void(bool mutate, int* value)); + ... +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, Mutate(true, _)) + .WillOnce(SetArgPointee<1>(5)); +``` + +In this example, when `mutator.Mutate()` is called, we will assign 5 +to the `int` variable pointed to by argument #1 +(0-based). + +`SetArgPointee()` conveniently makes an internal copy of the +value you pass to it, removing the need to keep the value in scope and +alive. The implication however is that the value must have a copy +constructor and assignment operator. + +If the mock method also needs to return a value as well, you can chain +`SetArgPointee()` with `Return()` using `DoAll()`: + +``` +using ::testing::_; +using ::testing::Return; +using ::testing::SetArgPointee; + +class MockMutator : public Mutator { + public: + ... + MOCK_METHOD1(MutateInt, bool(int* value)); +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, MutateInt(_)) + .WillOnce(DoAll(SetArgPointee<0>(5), + Return(true))); +``` + +If the output argument is an array, use the +`SetArrayArgument(first, last)` action instead. It copies the +elements in source range `[first, last)` to the array pointed to by +the `N`-th (0-based) argument: + +``` +using ::testing::NotNull; +using ::testing::SetArrayArgument; + +class MockArrayMutator : public ArrayMutator { + public: + MOCK_METHOD2(Mutate, void(int* values, int num_values)); + ... +}; +... + + MockArrayMutator mutator; + int values[5] = { 1, 2, 3, 4, 5 }; + EXPECT_CALL(mutator, Mutate(NotNull(), 5)) + .WillOnce(SetArrayArgument<0>(values, values + 5)); +``` + +This also works when the argument is an output iterator: + +``` +using ::testing::_; +using ::testing::SeArrayArgument; + +class MockRolodex : public Rolodex { + public: + MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); + ... +}; +... + + MockRolodex rolodex; + vector names; + names.push_back("George"); + names.push_back("John"); + names.push_back("Thomas"); + EXPECT_CALL(rolodex, GetNames(_)) + .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); +``` + +## Changing a Mock Object's Behavior Based on the State ## + +If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: + +``` +using ::testing::InSequence; +using ::testing::Return; + +... + { + InSequence seq; + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(my_mock, Flush()); + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(false)); + } + my_mock.FlushIfDirty(); +``` + +This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. + +If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: + +``` +using ::testing::_; +using ::testing::SaveArg; +using ::testing::Return; + +ACTION_P(ReturnPointee, p) { return *p; } +... + int previous_value = 0; + EXPECT_CALL(my_mock, GetPrevValue()) + .WillRepeatedly(ReturnPointee(&previous_value)); + EXPECT_CALL(my_mock, UpdateValue(_)) + .WillRepeatedly(SaveArg<0>(&previous_value)); + my_mock.DoSomethingToUpdateValue(); +``` + +Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. + +## Setting the Default Value for a Return Type ## + +If a mock method's return type is a built-in C++ type or pointer, by +default it will return 0 when invoked. Also, in C++ 11 and above, a mock +method whose return type has a default constructor will return a default-constructed +value by default. You only need to specify an +action if this default value doesn't work for you. + +Sometimes, you may want to change this default value, or you may want +to specify a default value for types Google Mock doesn't know +about. You can do this using the `::testing::DefaultValue` class +template: + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD0(CalculateBar, Bar()); +}; +... + + Bar default_bar; + // Sets the default return value for type Bar. + DefaultValue::Set(default_bar); + + MockFoo foo; + + // We don't need to specify an action here, as the default + // return value works for us. + EXPECT_CALL(foo, CalculateBar()); + + foo.CalculateBar(); // This should return default_bar. + + // Unsets the default return value. + DefaultValue::Clear(); +``` + +Please note that changing the default value for a type can make you +tests hard to understand. We recommend you to use this feature +judiciously. For example, you may want to make sure the `Set()` and +`Clear()` calls are right next to the code that uses your mock. + +## Setting the Default Actions for a Mock Method ## + +You've learned how to change the default value of a given +type. However, this may be too coarse for your purpose: perhaps you +have two mock methods with the same return type and you want them to +have different behaviors. The `ON_CALL()` macro allows you to +customize your mock's behavior at the method level: + +``` +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Gt; +using ::testing::Return; +... + ON_CALL(foo, Sign(_)) + .WillByDefault(Return(-1)); + ON_CALL(foo, Sign(0)) + .WillByDefault(Return(0)); + ON_CALL(foo, Sign(Gt(0))) + .WillByDefault(Return(1)); + + EXPECT_CALL(foo, Sign(_)) + .Times(AnyNumber()); + + foo.Sign(5); // This should return 1. + foo.Sign(-9); // This should return -1. + foo.Sign(0); // This should return 0. +``` + +As you may have guessed, when there are more than one `ON_CALL()` +statements, the news order take precedence over the older ones. In +other words, the **last** one that matches the function arguments will +be used. This matching order allows you to set up the common behavior +in a mock object's constructor or the test fixture's set-up phase and +specialize the mock's behavior later. + +## Using Functions/Methods/Functors as Actions ## + +If the built-in actions don't suit you, you can easily use an existing +function, method, or functor as an action: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(Sum, int(int x, int y)); + MOCK_METHOD1(ComplexJob, bool(int x)); +}; + +int CalculateSum(int x, int y) { return x + y; } + +class Helper { + public: + bool ComplexJob(int x); +}; +... + + MockFoo foo; + Helper helper; + EXPECT_CALL(foo, Sum(_, _)) + .WillOnce(Invoke(CalculateSum)); + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(Invoke(&helper, &Helper::ComplexJob)); + + foo.Sum(5, 6); // Invokes CalculateSum(5, 6). + foo.ComplexJob(10); // Invokes helper.ComplexJob(10); +``` + +The only requirement is that the type of the function, etc must be +_compatible_ with the signature of the mock function, meaning that the +latter's arguments can be implicitly converted to the corresponding +arguments of the former, and the former's return type can be +implicitly converted to that of the latter. So, you can invoke +something whose type is _not_ exactly the same as the mock function, +as long as it's safe to do so - nice, huh? + +## Invoking a Function/Method/Functor Without Arguments ## + +`Invoke()` is very useful for doing actions that are more complex. It +passes the mock function's arguments to the function or functor being +invoked such that the callee has the full context of the call to work +with. If the invoked function is not interested in some or all of the +arguments, it can simply ignore them. + +Yet, a common pattern is that a test author wants to invoke a function +without the arguments of the mock function. `Invoke()` allows her to +do that using a wrapper function that throws away the arguments before +invoking an underlining nullary function. Needless to say, this can be +tedious and obscures the intent of the test. + +`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except +that it doesn't pass the mock function's arguments to the +callee. Here's an example: + +``` +using ::testing::_; +using ::testing::InvokeWithoutArgs; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(ComplexJob, bool(int n)); +}; + +bool Job1() { ... } +... + + MockFoo foo; + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(InvokeWithoutArgs(Job1)); + + foo.ComplexJob(10); // Invokes Job1(). +``` + +## Invoking an Argument of the Mock Function ## + +Sometimes a mock function will receive a function pointer or a functor +(in other words, a "callable") as an argument, e.g. + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); +}; +``` + +and you may want to invoke this callable argument: + +``` +using ::testing::_; +... + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(...); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +Arghh, you need to refer to a mock function argument but C++ has no +lambda (yet), so you have to define your own action. :-( Or do you +really? + +Well, Google Mock has an action to solve _exactly_ this problem: + +``` + InvokeArgument(arg_1, arg_2, ..., arg_m) +``` + +will invoke the `N`-th (0-based) argument the mock function receives, +with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is +a function pointer or a functor, Google Mock handles them both. + +With that, you could write: + +``` +using ::testing::_; +using ::testing::InvokeArgument; +... + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(InvokeArgument<1>(5)); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +What if the callable takes an argument by reference? No problem - just +wrap it inside `ByRef()`: + +``` +... + MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); +... +using ::testing::_; +using ::testing::ByRef; +using ::testing::InvokeArgument; +... + + MockFoo foo; + Helper helper; + ... + EXPECT_CALL(foo, Bar(_)) + .WillOnce(InvokeArgument<0>(5, ByRef(helper))); + // ByRef(helper) guarantees that a reference to helper, not a copy of it, + // will be passed to the callable. +``` + +What if the callable takes an argument by reference and we do **not** +wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a +copy_ of the argument, and pass a _reference to the copy_, instead of +a reference to the original value, to the callable. This is especially +handy when the argument is a temporary value: + +``` +... + MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); +... +using ::testing::_; +using ::testing::InvokeArgument; +... + + MockFoo foo; + ... + EXPECT_CALL(foo, DoThat(_)) + .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); + // Will execute (*f)(5.0, string("Hi")), where f is the function pointer + // DoThat() receives. Note that the values 5.0 and string("Hi") are + // temporary and dead once the EXPECT_CALL() statement finishes. Yet + // it's fine to perform this action later, since a copy of the values + // are kept inside the InvokeArgument action. +``` + +## Ignoring an Action's Result ## + +Sometimes you have an action that returns _something_, but you need an +action that returns `void` (perhaps you want to use it in a mock +function that returns `void`, or perhaps it needs to be used in +`DoAll()` and it's not the last in the list). `IgnoreResult()` lets +you do that. For example: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; + +int Process(const MyData& data); +string DoSomething(); + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Abc, void(const MyData& data)); + MOCK_METHOD0(Xyz, bool()); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, Abc(_)) + // .WillOnce(Invoke(Process)); + // The above line won't compile as Process() returns int but Abc() needs + // to return void. + .WillOnce(IgnoreResult(Invoke(Process))); + + EXPECT_CALL(foo, Xyz()) + .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), + // Ignores the string DoSomething() returns. + Return(true))); +``` + +Note that you **cannot** use `IgnoreResult()` on an action that already +returns `void`. Doing so will lead to ugly compiler errors. + +## Selecting an Action's Arguments ## + +Say you have a mock function `Foo()` that takes seven arguments, and +you have a custom action that you want to invoke when `Foo()` is +called. Trouble is, the custom action only wants three arguments: + +``` +using ::testing::_; +using ::testing::Invoke; +... + MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight)); +... + +bool IsVisibleInQuadrant1(bool visible, int x, int y) { + return visible && x >= 0 && y >= 0; +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( +``` + +To please the compiler God, you can to define an "adaptor" that has +the same signature as `Foo()` and calls the custom action with the +right arguments: + +``` +using ::testing::_; +using ::testing::Invoke; + +bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight) { + return IsVisibleInQuadrant1(visible, x, y); +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. +``` + +But isn't this awkward? + +Google Mock provides a generic _action adaptor_, so you can spend your +time minding more important business than writing your own +adaptors. Here's the syntax: + +``` + WithArgs(action) +``` + +creates an action that passes the arguments of the mock function at +the given indices (0-based) to the inner `action` and performs +it. Using `WithArgs`, our original example can be written as: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::WithArgs; +... + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); + // No need to define your own adaptor. +``` + +For better readability, Google Mock also gives you: + + * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and + * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. + +As you may have realized, `InvokeWithoutArgs(...)` is just syntactic +sugar for `WithoutArgs(Invoke(...))`. + +Here are more tips: + + * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. + * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. + * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. + * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. + +## Ignoring Arguments in Action Functions ## + +The selecting-an-action's-arguments recipe showed us one way to make a +mock function and an action with incompatible argument lists fit +together. The downside is that wrapping the action in +`WithArgs<...>()` can get tedious for people writing the tests. + +If you are defining a function, method, or functor to be used with +`Invoke*()`, and you are not interested in some of its arguments, an +alternative to `WithArgs` is to declare the uninteresting arguments as +`Unused`. This makes the definition less cluttered and less fragile in +case the types of the uninteresting arguments change. It could also +increase the chance the action function can be reused. For example, +given + +``` + MOCK_METHOD3(Foo, double(const string& label, double x, double y)); + MOCK_METHOD3(Bar, double(int index, double x, double y)); +``` + +instead of + +``` +using ::testing::_; +using ::testing::Invoke; + +double DistanceToOriginWithLabel(const string& label, double x, double y) { + return sqrt(x*x + y*y); +} + +double DistanceToOriginWithIndex(int index, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOriginWithLabel)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOriginWithIndex)); +``` + +you could write + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Unused; + +double DistanceToOrigin(Unused, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOrigin)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOrigin)); +``` + +## Sharing Actions ## + +Just like matchers, a Google Mock action object consists of a pointer +to a ref-counted implementation object. Therefore copying actions is +also allowed and very efficient. When the last action that references +the implementation object dies, the implementation object will be +deleted. + +If you have some complex action that you want to use again and again, +you may not have to build it from scratch everytime. If the action +doesn't have an internal state (i.e. if it always does the same thing +no matter how many times it has been called), you can assign it to an +action variable and use that variable repeatedly. For example: + +``` + Action set_flag = DoAll(SetArgPointee<0>(5), + Return(true)); + ... use set_flag in .WillOnce() and .WillRepeatedly() ... +``` + +However, if the action has its own state, you may be surprised if you +share the action object. Suppose you have an action factory +`IncrementCounter(init)` which creates an action that increments and +returns a counter whose initial value is `init`, using two actions +created from the same expression and using a shared action will +exihibit different behaviors. Example: + +``` + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(IncrementCounter(0)); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(IncrementCounter(0)); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 1 - Blah() uses a different + // counter than Bar()'s. +``` + +versus + +``` + Action increment = IncrementCounter(0); + + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(increment); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(increment); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 3 - the counter is shared. +``` + +# Misc Recipes on Using Google Mock # + +## Mocking Methods That Use Move-Only Types ## + +C++11 introduced move-only types. A move-only-typed value can be moved from one object to another, but cannot be copied. `std::unique_ptr` is probably the most commonly used move-only type. + +Mocking a method that takes and/or returns move-only types presents some challenges, but nothing insurmountable. This recipe shows you how you can do it. + +Let’s say we are working on a fictional project that lets one post and share snippets called “buzzesâ€. Your code uses these types: + +``` +enum class AccessLevel { kInternal, kPublic }; + +class Buzz { + public: + explicit Buzz(AccessLevel access) { … } + ... +}; + +class Buzzer { + public: + virtual ~Buzzer() {} + virtual std::unique_ptr MakeBuzz(const std::string& text) = 0; + virtual bool ShareBuzz(std::unique_ptr buzz, Time timestamp) = 0; + ... +}; +``` + +A `Buzz` object represents a snippet being posted. A class that implements the `Buzzer` interface is capable of creating and sharing `Buzz`. Methods in `Buzzer` may return a `unique_ptr` or take a `unique_ptr`. Now we need to mock `Buzzer` in our tests. + +To mock a method that returns a move-only type, you just use the familiar `MOCK_METHOD` syntax as usual: + +``` +class MockBuzzer : public Buzzer { + public: + MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); + … +}; +``` + +However, if you attempt to use the same `MOCK_METHOD` pattern to mock a method that takes a move-only parameter, you’ll get a compiler error currently: + +``` + // Does NOT compile! + MOCK_METHOD2(ShareBuzz, bool(std::unique_ptr buzz, Time timestamp)); +``` + +While it’s highly desirable to make this syntax just work, it’s not trivial and the work hasn’t been done yet. Fortunately, there is a trick you can apply today to get something that works nearly as well as this. + +The trick, is to delegate the `ShareBuzz()` method to a mock method (let’s call it `DoShareBuzz()`) that does not take move-only parameters: + +``` +class MockBuzzer : public Buzzer { + public: + MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); + MOCK_METHOD2(DoShareBuzz, bool(Buzz* buzz, Time timestamp)); + bool ShareBuzz(std::unique_ptr buzz, Time timestamp) { + return DoShareBuzz(buzz.get(), timestamp); + } +}; +``` + +Note that there's no need to define or declare `DoShareBuzz()` in a base class. You only need to define it as a `MOCK_METHOD` in the mock class. + +Now that we have the mock class defined, we can use it in tests. In the following code examples, we assume that we have defined a `MockBuzzer` object named `mock_buzzer_`: + +``` + MockBuzzer mock_buzzer_; +``` + +First let’s see how we can set expectations on the `MakeBuzz()` method, which returns a `unique_ptr`. + +As usual, if you set an expectation without an action (i.e. the `.WillOnce()` or `.WillRepeated()` clause), when that expectation fires, the default action for that method will be taken. Since `unique_ptr<>` has a default constructor that returns a null `unique_ptr`, that’s what you’ll get if you don’t specify an action: + +``` + // Use the default action. + EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")); + + // Triggers the previous EXPECT_CALL. + EXPECT_EQ(nullptr, mock_buzzer_.MakeBuzz("hello")); +``` + +If you are not happy with the default action, you can tweak it. Depending on what you need, you may either tweak the default action for a specific (mock object, mock method) combination using `ON_CALL()`, or you may tweak the default action for all mock methods that return a specific type. The usage of `ON_CALL()` is similar to `EXPECT_CALL()`, so we’ll skip it and just explain how to do the latter (tweaking the default action for a specific return type). You do this via the `DefaultValue<>::SetFactory()` and `DefaultValue<>::Clear()` API: + +``` + // Sets the default action for return type std::unique_ptr to + // creating a new Buzz every time. + DefaultValue>::SetFactory( + [] { return MakeUnique(AccessLevel::kInternal); }); + + // When this fires, the default action of MakeBuzz() will run, which + // will return a new Buzz object. + EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")).Times(AnyNumber()); + + auto buzz1 = mock_buzzer_.MakeBuzz("hello"); + auto buzz2 = mock_buzzer_.MakeBuzz("hello"); + EXPECT_NE(nullptr, buzz1); + EXPECT_NE(nullptr, buzz2); + EXPECT_NE(buzz1, buzz2); + + // Resets the default action for return type std::unique_ptr, + // to avoid interfere with other tests. + DefaultValue>::Clear(); +``` + +What if you want the method to do something other than the default action? If you just need to return a pre-defined move-only value, you can use the `Return(ByMove(...))` action: + +``` + // When this fires, the unique_ptr<> specified by ByMove(...) will + // be returned. + EXPECT_CALL(mock_buzzer_, MakeBuzz("world")) + .WillOnce(Return(ByMove(MakeUnique(AccessLevel::kInternal)))); + + EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("world")); +``` + +Note that `ByMove()` is essential here - if you drop it, the code won’t compile. + +Quiz time! What do you think will happen if a `Return(ByMove(...))` action is performed more than once (e.g. you write `….WillRepeatedly(Return(ByMove(...)));`)? Come think of it, after the first time the action runs, the source value will be consumed (since it’s a move-only value), so the next time around, there’s no value to move from -- you’ll get a run-time error that `Return(ByMove(...))` can only be run once. + +If you need your mock method to do more than just moving a pre-defined value, remember that you can always use `Invoke()` to call a lambda or a callable object, which can do pretty much anything you want: + +``` + EXPECT_CALL(mock_buzzer_, MakeBuzz("x")) + .WillRepeatedly(Invoke([](const std::string& text) { + return std::make_unique(AccessLevel::kInternal); + })); + + EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); + EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); +``` + +Every time this `EXPECT_CALL` fires, a new `unique_ptr` will be created and returned. You cannot do this with `Return(ByMove(...))`. + +Now there’s one topic we haven’t covered: how do you set expectations on `ShareBuzz()`, which takes a move-only-typed parameter? The answer is you don’t. Instead, you set expectations on the `DoShareBuzz()` mock method (remember that we defined a `MOCK_METHOD` for `DoShareBuzz()`, not `ShareBuzz()`): + +``` + EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)); + + // When one calls ShareBuzz() on the MockBuzzer like this, the call is + // forwarded to DoShareBuzz(), which is mocked. Therefore this statement + // will trigger the above EXPECT_CALL. + mock_buzzer_.ShareBuzz(MakeUnique<Buzz>(AccessLevel::kInternal), + ::base::Now()); +``` + +Some of you may have spotted one problem with this approach: the `DoShareBuzz()` mock method differs from the real `ShareBuzz()` method in that it cannot take ownership of the buzz parameter - `ShareBuzz()` will always delete buzz after `DoShareBuzz()` returns. What if you need to save the buzz object somewhere for later use when `ShareBuzz()` is called? Indeed, you'd be stuck. + +Another problem with the `DoShareBuzz()` we had is that it can surprise people reading or maintaining the test, as one would expect that `DoShareBuzz()` has (logically) the same contract as `ShareBuzz()`. + +Fortunately, these problems can be fixed with a bit more code. Let's try to get it right this time: + +``` +class MockBuzzer : public Buzzer { + public: + MockBuzzer() { + // Since DoShareBuzz(buzz, time) is supposed to take ownership of + // buzz, define a default behavior for DoShareBuzz(buzz, time) to + // delete buzz. + ON_CALL(*this, DoShareBuzz(_, _)) + .WillByDefault(Invoke([](Buzz* buzz, Time timestamp) { + delete buzz; + return true; + })); + } + + MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); + + // Takes ownership of buzz. + MOCK_METHOD2(DoShareBuzz, bool(Buzz* buzz, Time timestamp)); + bool ShareBuzz(std::unique_ptr buzz, Time timestamp) { + return DoShareBuzz(buzz.release(), timestamp); + } +}; +``` + +Now, the mock `DoShareBuzz()` method is free to save the buzz argument for later use if this is what you want: + +``` + std::unique_ptr intercepted_buzz; + EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)) + .WillOnce(Invoke([&intercepted_buzz](Buzz* buzz, Time timestamp) { + // Save buzz in intercepted_buzz for analysis later. + intercepted_buzz.reset(buzz); + return false; + })); + + mock_buzzer_.ShareBuzz(std::make_unique(AccessLevel::kInternal), + Now()); + EXPECT_NE(nullptr, intercepted_buzz); +``` + +Using the tricks covered in this recipe, you are now able to mock methods that take and/or return move-only types. Put your newly-acquired power to good use - when you design a new API, you can now feel comfortable using `unique_ptrs` as appropriate, without fearing that doing so will compromise your tests. + +## Making the Compilation Faster ## + +Believe it or not, the _vast majority_ of the time spent on compiling +a mock class is in generating its constructor and destructor, as they +perform non-trivial tasks (e.g. verification of the +expectations). What's more, mock methods with different signatures +have different types and thus their constructors/destructors need to +be generated by the compiler separately. As a result, if you mock many +different types of methods, compiling your mock class can get really +slow. + +If you are experiencing slow compilation, you can move the definition +of your mock class' constructor and destructor out of the class body +and into a `.cpp` file. This way, even if you `#include` your mock +class in N files, the compiler only needs to generate its constructor +and destructor once, resulting in a much faster compilation. + +Let's illustrate the idea using an example. Here's the definition of a +mock class before applying this recipe: + +``` +// File mock_foo.h. +... +class MockFoo : public Foo { + public: + // Since we don't declare the constructor or the destructor, + // the compiler will generate them in every translation unit + // where this mock class is used. + + MOCK_METHOD0(DoThis, int()); + MOCK_METHOD1(DoThat, bool(const char* str)); + ... more mock methods ... +}; +``` + +After the change, it would look like: + +``` +// File mock_foo.h. +... +class MockFoo : public Foo { + public: + // The constructor and destructor are declared, but not defined, here. + MockFoo(); + virtual ~MockFoo(); + + MOCK_METHOD0(DoThis, int()); + MOCK_METHOD1(DoThat, bool(const char* str)); + ... more mock methods ... +}; +``` +and +``` +// File mock_foo.cpp. +#include "path/to/mock_foo.h" + +// The definitions may appear trivial, but the functions actually do a +// lot of things through the constructors/destructors of the member +// variables used to implement the mock methods. +MockFoo::MockFoo() {} +MockFoo::~MockFoo() {} +``` + +## Forcing a Verification ## + +When it's being destoyed, your friendly mock object will automatically +verify that all expectations on it have been satisfied, and will +generate [Google Test](../../googletest/) failures +if not. This is convenient as it leaves you with one less thing to +worry about. That is, unless you are not sure if your mock object will +be destoyed. + +How could it be that your mock object won't eventually be destroyed? +Well, it might be created on the heap and owned by the code you are +testing. Suppose there's a bug in that code and it doesn't delete the +mock object properly - you could end up with a passing test when +there's actually a bug. + +Using a heap checker is a good idea and can alleviate the concern, but +its implementation may not be 100% reliable. So, sometimes you do want +to _force_ Google Mock to verify a mock object before it is +(hopefully) destructed. You can do this with +`Mock::VerifyAndClearExpectations(&mock_object)`: + +``` +TEST(MyServerTest, ProcessesRequest) { + using ::testing::Mock; + + MockFoo* const foo = new MockFoo; + EXPECT_CALL(*foo, ...)...; + // ... other expectations ... + + // server now owns foo. + MyServer server(foo); + server.ProcessRequest(...); + + // In case that server's destructor will forget to delete foo, + // this will verify the expectations anyway. + Mock::VerifyAndClearExpectations(foo); +} // server is destroyed when it goes out of scope here. +``` + +**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a +`bool` to indicate whether the verification was successful (`true` for +yes), so you can wrap that function call inside a `ASSERT_TRUE()` if +there is no point going further when the verification has failed. + +## Using Check Points ## + +Sometimes you may want to "reset" a mock object at various check +points in your test: at each check point, you verify that all existing +expectations on the mock object have been satisfied, and then you set +some new expectations on it as if it's newly created. This allows you +to work with a mock object in "phases" whose sizes are each +manageable. + +One such scenario is that in your test's `SetUp()` function, you may +want to put the object you are testing into a certain state, with the +help from a mock object. Once in the desired state, you want to clear +all expectations on the mock, such that in the `TEST_F` body you can +set fresh expectations on it. + +As you may have figured out, the `Mock::VerifyAndClearExpectations()` +function we saw in the previous recipe can help you here. Or, if you +are using `ON_CALL()` to set default actions on the mock object and +want to clear the default actions as well, use +`Mock::VerifyAndClear(&mock_object)` instead. This function does what +`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the +same `bool`, **plus** it clears the `ON_CALL()` statements on +`mock_object` too. + +Another trick you can use to achieve the same effect is to put the +expectations in sequences and insert calls to a dummy "check-point" +function at specific places. Then you can verify that the mock +function calls do happen at the right time. For example, if you are +exercising code: + +``` +Foo(1); +Foo(2); +Foo(3); +``` + +and want to verify that `Foo(1)` and `Foo(3)` both invoke +`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: + +``` +using ::testing::MockFunction; + +TEST(FooTest, InvokesBarCorrectly) { + MyMock mock; + // Class MockFunction has exactly one mock method. It is named + // Call() and has type F. + MockFunction check; + { + InSequence s; + + EXPECT_CALL(mock, Bar("a")); + EXPECT_CALL(check, Call("1")); + EXPECT_CALL(check, Call("2")); + EXPECT_CALL(mock, Bar("a")); + } + Foo(1); + check.Call("1"); + Foo(2); + check.Call("2"); + Foo(3); +} +``` + +The expectation spec says that the first `Bar("a")` must happen before +check point "1", the second `Bar("a")` must happen after check point "2", +and nothing should happen between the two check points. The explicit +check points make it easy to tell which `Bar("a")` is called by which +call to `Foo()`. + +## Mocking Destructors ## + +Sometimes you want to make sure a mock object is destructed at the +right time, e.g. after `bar->A()` is called but before `bar->B()` is +called. We already know that you can specify constraints on the order +of mock function calls, so all we need to do is to mock the destructor +of the mock function. + +This sounds simple, except for one problem: a destructor is a special +function with special syntax and special semantics, and the +`MOCK_METHOD0` macro doesn't work for it: + +``` + MOCK_METHOD0(~MockFoo, void()); // Won't compile! +``` + +The good news is that you can use a simple pattern to achieve the same +effect. First, add a mock function `Die()` to your mock class and call +it in the destructor, like this: + +``` +class MockFoo : public Foo { + ... + // Add the following two lines to the mock class. + MOCK_METHOD0(Die, void()); + virtual ~MockFoo() { Die(); } +}; +``` + +(If the name `Die()` clashes with an existing symbol, choose another +name.) Now, we have translated the problem of testing when a `MockFoo` +object dies to testing when its `Die()` method is called: + +``` + MockFoo* foo = new MockFoo; + MockBar* bar = new MockBar; + ... + { + InSequence s; + + // Expects *foo to die after bar->A() and before bar->B(). + EXPECT_CALL(*bar, A()); + EXPECT_CALL(*foo, Die()); + EXPECT_CALL(*bar, B()); + } +``` + +And that's that. + +## Using Google Mock and Threads ## + +**IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on +platforms where Google Mock is thread-safe. Currently these are only +platforms that support the pthreads library (this includes Linux and Mac). +To make it thread-safe on other platforms we only need to implement +some synchronization operations in `"gtest/internal/gtest-port.h"`. + +In a **unit** test, it's best if you could isolate and test a piece of +code in a single-threaded context. That avoids race conditions and +dead locks, and makes debugging your test much easier. + +Yet many programs are multi-threaded, and sometimes to test something +we need to pound on it from more than one thread. Google Mock works +for this purpose too. + +Remember the steps for using a mock: + + 1. Create a mock object `foo`. + 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. + 1. The code under test calls methods of `foo`. + 1. Optionally, verify and reset the mock. + 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. + +If you follow the following simple rules, your mocks and threads can +live happily together: + + * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. + * Obviously, you can do step #1 without locking. + * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? + * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. + +If you violate the rules (for example, if you set expectations on a +mock while another thread is calling its methods), you get undefined +behavior. That's not fun, so don't do it. + +Google Mock guarantees that the action for a mock function is done in +the same thread that called the mock function. For example, in + +``` + EXPECT_CALL(mock, Foo(1)) + .WillOnce(action1); + EXPECT_CALL(mock, Foo(2)) + .WillOnce(action2); +``` + +if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, +Google Mock will execute `action1` in thread 1 and `action2` in thread +2. + +Google Mock does _not_ impose a sequence on actions performed in +different threads (doing so may create deadlocks as the actions may +need to cooperate). This means that the execution of `action1` and +`action2` in the above example _may_ interleave. If this is a problem, +you should add proper synchronization logic to `action1` and `action2` +to make the test thread-safe. + + +Also, remember that `DefaultValue` is a global resource that +potentially affects _all_ living mock objects in your +program. Naturally, you won't want to mess with it from multiple +threads or when there still are mocks in action. + +## Controlling How Much Information Google Mock Prints ## + +When Google Mock sees something that has the potential of being an +error (e.g. a mock function with no expectation is called, a.k.a. an +uninteresting call, which is allowed but perhaps you forgot to +explicitly ban the call), it prints some warning messages, including +the arguments of the function and the return value. Hopefully this +will remind you to take a look and see if there is indeed a problem. + +Sometimes you are confident that your tests are correct and may not +appreciate such friendly messages. Some other times, you are debugging +your tests or learning about the behavior of the code you are testing, +and wish you could observe every mock call that happens (including +argument values and the return value). Clearly, one size doesn't fit +all. + +You can control how much Google Mock tells you using the +`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string +with three possible values: + + * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. + * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. + * `error`: Google Mock will print errors only (least verbose). + +Alternatively, you can adjust the value of that flag from within your +tests like so: + +``` + ::testing::FLAGS_gmock_verbose = "error"; +``` + +Now, judiciously use the right flag to enable Google Mock serve you better! + +## Gaining Super Vision into Mock Calls ## + +You have a test using Google Mock. It fails: Google Mock tells you +that some expectations aren't satisfied. However, you aren't sure why: +Is there a typo somewhere in the matchers? Did you mess up the order +of the `EXPECT_CALL`s? Or is the code under test doing something +wrong? How can you find out the cause? + +Won't it be nice if you have X-ray vision and can actually see the +trace of all `EXPECT_CALL`s and mock method calls as they are made? +For each call, would you like to see its actual argument values and +which `EXPECT_CALL` Google Mock thinks it matches? + +You can unlock this power by running your test with the +`--gmock_verbose=info` flag. For example, given the test program: + +``` +using testing::_; +using testing::HasSubstr; +using testing::Return; + +class MockFoo { + public: + MOCK_METHOD2(F, void(const string& x, const string& y)); +}; + +TEST(Foo, Bar) { + MockFoo mock; + EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); + EXPECT_CALL(mock, F("a", "b")); + EXPECT_CALL(mock, F("c", HasSubstr("d"))); + + mock.F("a", "good"); + mock.F("a", "b"); +} +``` + +if you run it with `--gmock_verbose=info`, you will see this output: + +``` +[ RUN ] Foo.Bar + +foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked +foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked +foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked +foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... + Function call: F(@0x7fff7c8dad40"a", @0x7fff7c8dad10"good") +foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... + Function call: F(@0x7fff7c8dada0"a", @0x7fff7c8dad70"b") +foo_test.cc:16: Failure +Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] Foo.Bar +``` + +Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo +and should actually be `"a"`. With the above message, you should see +that the actual `F("a", "good")` call is matched by the first +`EXPECT_CALL`, not the third as you thought. From that it should be +obvious that the third `EXPECT_CALL` is written wrong. Case solved. + +## Running Tests in Emacs ## + +If you build and run your tests in Emacs, the source file locations of +Google Mock and [Google Test](../../googletest/) +errors will be highlighted. Just press `` on one of them and +you'll be taken to the offending line. Or, you can just type `C-x `` +to jump to the next error. + +To make it even easier, you can add the following lines to your +`~/.emacs` file: + +``` +(global-set-key "\M-m" 'compile) ; m is for make +(global-set-key [M-down] 'next-error) +(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) +``` + +Then you can type `M-m` to start a build, or `M-up`/`M-down` to move +back and forth between errors. + +## Fusing Google Mock Source Files ## + +Google Mock's implementation consists of dozens of files (excluding +its own tests). Sometimes you may want them to be packaged up in +fewer files instead, such that you can easily copy them to a new +machine and start hacking there. For this we provide an experimental +Python script `fuse_gmock_files.py` in the `scripts/` directory +(starting with release 1.2.0). Assuming you have Python 2.4 or above +installed on your machine, just go to that directory and run +``` +python fuse_gmock_files.py OUTPUT_DIR +``` + +and you should see an `OUTPUT_DIR` directory being created with files +`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. +These three files contain everything you need to use Google Mock (and +Google Test). Just copy them to anywhere you want and you are ready +to write tests and use mocks. You can use the +[scrpts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests +against them. + +# Extending Google Mock # + +## Writing New Matchers Quickly ## + +The `MATCHER*` family of macros can be used to define custom matchers +easily. The syntax: + +``` +MATCHER(name, description_string_expression) { statements; } +``` + +will define a matcher with the given name that executes the +statements, which must return a `bool` to indicate if the match +succeeds. Inside the statements, you can refer to the value being +matched by `arg`, and refer to its type by `arg_type`. + +The description string is a `string`-typed expression that documents +what the matcher does, and is used to generate the failure message +when the match fails. It can (and should) reference the special +`bool` variable `negation`, and should evaluate to the description of +the matcher when `negation` is `false`, or that of the matcher's +negation when `negation` is `true`. + +For convenience, we allow the description string to be empty (`""`), +in which case Google Mock will use the sequence of words in the +matcher name as the description. + +For example: +``` +MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } +``` +allows you to write +``` + // Expects mock_foo.Bar(n) to be called where n is divisible by 7. + EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); +``` +or, +``` +using ::testing::Not; +... + EXPECT_THAT(some_expression, IsDivisibleBy7()); + EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); +``` +If the above assertions fail, they will print something like: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 +... + Value of: some_other_expression + Expected: not (is divisible by 7) + Actual: 21 +``` +where the descriptions `"is divisible by 7"` and `"not (is divisible +by 7)"` are automatically calculated from the matcher name +`IsDivisibleBy7`. + +As you may have noticed, the auto-generated descriptions (especially +those for the negation) may not be so great. You can always override +them with a string expression of your own: +``` +MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + + " divisible by 7") { + return (arg % 7) == 0; +} +``` + +Optionally, you can stream additional information to a hidden argument +named `result_listener` to explain the match result. For example, a +better definition of `IsDivisibleBy7` is: +``` +MATCHER(IsDivisibleBy7, "") { + if ((arg % 7) == 0) + return true; + + *result_listener << "the remainder is " << (arg % 7); + return false; +} +``` + +With this definition, the above assertion will give a better message: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 (the remainder is 6) +``` + +You should let `MatchAndExplain()` print _any additional information_ +that can help a user understand the match result. Note that it should +explain why the match succeeds in case of a success (unless it's +obvious) - this is useful when the matcher is used inside +`Not()`. There is no need to print the argument value itself, as +Google Mock already prints it for you. + +**Notes:** + + 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. + 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. + +## Writing New Parameterized Matchers Quickly ## + +Sometimes you'll want to define a matcher that has parameters. For that you +can use the macro: +``` +MATCHER_P(name, param_name, description_string) { statements; } +``` +where the description string can be either `""` or a string expression +that references `negation` and `param_name`. + +For example: +``` +MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +``` +will allow you to write: +``` + EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +``` +which may lead to this message (assuming `n` is 10): +``` + Value of: Blah("a") + Expected: has absolute value 10 + Actual: -9 +``` + +Note that both the matcher description and its parameter are +printed, making the message human-friendly. + +In the matcher definition body, you can write `foo_type` to +reference the type of a parameter named `foo`. For example, in the +body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write +`value_type` to refer to the type of `value`. + +Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to +`MATCHER_P10` to support multi-parameter matchers: +``` +MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } +``` + +Please note that the custom description string is for a particular +**instance** of the matcher, where the parameters have been bound to +actual values. Therefore usually you'll want the parameter values to +be part of the description. Google Mock lets you do that by +referencing the matcher parameters in the description string +expression. + +For example, +``` + using ::testing::PrintToString; + MATCHER_P2(InClosedRange, low, hi, + std::string(negation ? "isn't" : "is") + " in range [" + + PrintToString(low) + ", " + PrintToString(hi) + "]") { + return low <= arg && arg <= hi; + } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the message: +``` + Expected: is in range [4, 6] +``` + +If you specify `""` as the description, the failure message will +contain the sequence of words in the matcher name followed by the +parameter values printed as a tuple. For example, +``` + MATCHER_P2(InClosedRange, low, hi, "") { ... } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the text: +``` + Expected: in closed range (4, 6) +``` + +For the purpose of typing, you can view +``` +MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +``` +as shorthand for +``` +template +FooMatcherPk +Foo(p1_type p1, ..., pk_type pk) { ... } +``` + +When you write `Foo(v1, ..., vk)`, the compiler infers the types of +the parameters `v1`, ..., and `vk` for you. If you are not happy with +the result of the type inference, you can specify the types by +explicitly instantiating the template, as in `Foo(5, false)`. +As said earlier, you don't get to (or need to) specify +`arg_type` as that's determined by the context in which the matcher +is used. + +You can assign the result of expression `Foo(p1, ..., pk)` to a +variable of type `FooMatcherPk`. This can be +useful when composing matchers. Matchers that don't have a parameter +or have only one parameter have special types: you can assign `Foo()` +to a `FooMatcher`-typed variable, and assign `Foo(p)` to a +`FooMatcherP`-typed variable. + +While you can instantiate a matcher template with reference types, +passing the parameters by pointer usually makes your code more +readable. If, however, you still want to pass a parameter by +reference, be aware that in the failure message generated by the +matcher you will see the value of the referenced object but not its +address. + +You can overload matchers with different numbers of parameters: +``` +MATCHER_P(Blah, a, description_string_1) { ... } +MATCHER_P2(Blah, a, b, description_string_2) { ... } +``` + +While it's tempting to always use the `MATCHER*` macros when defining +a new matcher, you should also consider implementing +`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see +the recipes that follow), especially if you need to use the matcher a +lot. While these approaches require more work, they give you more +control on the types of the value being matched and the matcher +parameters, which in general leads to better compiler error messages +that pay off in the long run. They also allow overloading matchers +based on parameter types (as opposed to just based on the number of +parameters). + +## Writing New Monomorphic Matchers ## + +A matcher of argument type `T` implements +`::testing::MatcherInterface` and does two things: it tests whether a +value of type `T` matches the matcher, and can describe what kind of +values it matches. The latter ability is used for generating readable +error messages when expectations are violated. + +The interface looks like this: + +``` +class MatchResultListener { + public: + ... + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x); + + // Returns the underlying ostream. + ::std::ostream* stream(); +}; + +template +class MatcherInterface { + public: + virtual ~MatcherInterface(); + + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Describes this matcher to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. + virtual void DescribeNegationTo(::std::ostream* os) const; +}; +``` + +If you need a custom matcher but `Truly()` is not a good option (for +example, you may not be happy with the way `Truly(predicate)` +describes itself, or you may want your matcher to be polymorphic as +`Eq(value)` is), you can define a matcher to do whatever you want in +two steps: first implement the matcher interface, and then define a +factory function to create a matcher instance. The second step is not +strictly needed but it makes the syntax of using the matcher nicer. + +For example, you can define a matcher to test whether an `int` is +divisible by 7 and then use it like this: +``` +using ::testing::MakeMatcher; +using ::testing::Matcher; +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { + return (n % 7) == 0; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is divisible by 7"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "is not divisible by 7"; + } +}; + +inline Matcher DivisibleBy7() { + return MakeMatcher(new DivisibleBy7Matcher); +} +... + + EXPECT_CALL(foo, Bar(DivisibleBy7())); +``` + +You may improve the matcher message by streaming additional +information to the `listener` argument in `MatchAndExplain()`: + +``` +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, + MatchResultListener* listener) const { + const int remainder = n % 7; + if (remainder != 0) { + *listener << "the remainder is " << remainder; + } + return remainder == 0; + } + ... +}; +``` + +Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: +``` +Value of: x +Expected: is divisible by 7 + Actual: 23 (the remainder is 2) +``` + +## Writing New Polymorphic Matchers ## + +You've learned how to write your own matchers in the previous +recipe. Just one problem: a matcher created using `MakeMatcher()` only +works for one particular type of arguments. If you want a +_polymorphic_ matcher that works with arguments of several types (for +instance, `Eq(x)` can be used to match a `value` as long as `value` == +`x` compiles -- `value` and `x` don't have to share the same type), +you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit +involved. + +Fortunately, most of the time you can define a polymorphic matcher +easily with the help of `MakePolymorphicMatcher()`. Here's how you can +define `NotNull()` as an example: + +``` +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +using ::testing::NotNull; +using ::testing::PolymorphicMatcher; + +class NotNullMatcher { + public: + // To implement a polymorphic matcher, first define a COPYABLE class + // that has three members MatchAndExplain(), DescribeTo(), and + // DescribeNegationTo(), like the following. + + // In this example, we want to use NotNull() with any pointer, so + // MatchAndExplain() accepts a pointer of any type as its first argument. + // In general, you can define MatchAndExplain() as an ordinary method or + // a method template, or even overload it. + template + bool MatchAndExplain(T* p, + MatchResultListener* /* listener */) const { + return p != NULL; + } + + // Describes the property of a value matching this matcher. + void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } + + // Describes the property of a value NOT matching this matcher. + void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } +}; + +// To construct a polymorphic matcher, pass an instance of the class +// to MakePolymorphicMatcher(). Note the return type. +inline PolymorphicMatcher NotNull() { + return MakePolymorphicMatcher(NotNullMatcher()); +} +... + + EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. +``` + +**Note:** Your polymorphic matcher class does **not** need to inherit from +`MatcherInterface` or any other class, and its methods do **not** need +to be virtual. + +Like in a monomorphic matcher, you may explain the match result by +streaming additional information to the `listener` argument in +`MatchAndExplain()`. + +## Writing New Cardinalities ## + +A cardinality is used in `Times()` to tell Google Mock how many times +you expect a call to occur. It doesn't have to be exact. For example, +you can say `AtLeast(5)` or `Between(2, 4)`. + +If the built-in set of cardinalities doesn't suit you, you are free to +define your own by implementing the following interface (in namespace +`testing`): + +``` +class CardinalityInterface { + public: + virtual ~CardinalityInterface(); + + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; +``` + +For example, to specify that a call must occur even number of times, +you can write + +``` +using ::testing::Cardinality; +using ::testing::CardinalityInterface; +using ::testing::MakeCardinality; + +class EvenNumberCardinality : public CardinalityInterface { + public: + virtual bool IsSatisfiedByCallCount(int call_count) const { + return (call_count % 2) == 0; + } + + virtual bool IsSaturatedByCallCount(int call_count) const { + return false; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "called even number of times"; + } +}; + +Cardinality EvenNumber() { + return MakeCardinality(new EvenNumberCardinality); +} +... + + EXPECT_CALL(foo, Bar(3)) + .Times(EvenNumber()); +``` + +## Writing New Actions Quickly ## + +If the built-in actions don't work for you, and you find it +inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` +family to quickly define a new action that can be used in your code as +if it's a built-in action. + +By writing +``` +ACTION(name) { statements; } +``` +in a namespace scope (i.e. not inside a class or function), you will +define an action with the given name that executes the statements. +The value returned by `statements` will be used as the return value of +the action. Inside the statements, you can refer to the K-th +(0-based) argument of the mock function as `argK`. For example: +``` +ACTION(IncrementArg1) { return ++(*arg1); } +``` +allows you to write +``` +... WillOnce(IncrementArg1()); +``` + +Note that you don't need to specify the types of the mock function +arguments. Rest assured that your code is type-safe though: +you'll get a compiler error if `*arg1` doesn't support the `++` +operator, or if the type of `++(*arg1)` isn't compatible with the mock +function's return type. + +Another example: +``` +ACTION(Foo) { + (*arg2)(5); + Blah(); + *arg1 = 0; + return arg0; +} +``` +defines an action `Foo()` that invokes argument #2 (a function pointer) +with 5, calls function `Blah()`, sets the value pointed to by argument +#1 to 0, and returns argument #0. + +For more convenience and flexibility, you can also use the following +pre-defined symbols in the body of `ACTION`: + +| `argK_type` | The type of the K-th (0-based) argument of the mock function | +|:------------|:-------------------------------------------------------------| +| `args` | All arguments of the mock function as a tuple | +| `args_type` | The type of all arguments of the mock function as a tuple | +| `return_type` | The return type of the mock function | +| `function_type` | The type of the mock function | + +For example, when using an `ACTION` as a stub action for mock function: +``` +int DoSomething(bool flag, int* ptr); +``` +we have: +| **Pre-defined Symbol** | **Is Bound To** | +|:-----------------------|:----------------| +| `arg0` | the value of `flag` | +| `arg0_type` | the type `bool` | +| `arg1` | the value of `ptr` | +| `arg1_type` | the type `int*` | +| `args` | the tuple `(flag, ptr)` | +| `args_type` | the type `::testing::tuple` | +| `return_type` | the type `int` | +| `function_type` | the type `int(bool, int*)` | + +## Writing New Parameterized Actions Quickly ## + +Sometimes you'll want to parameterize an action you define. For that +we have another macro +``` +ACTION_P(name, param) { statements; } +``` + +For example, +``` +ACTION_P(Add, n) { return arg0 + n; } +``` +will allow you to write +``` +// Returns argument #0 + 5. +... WillOnce(Add(5)); +``` + +For convenience, we use the term _arguments_ for the values used to +invoke the mock function, and the term _parameters_ for the values +used to instantiate an action. + +Note that you don't need to provide the type of the parameter either. +Suppose the parameter is named `param`, you can also use the +Google-Mock-defined symbol `param_type` to refer to the type of the +parameter as inferred by the compiler. For example, in the body of +`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. + +Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support +multi-parameter actions. For example, +``` +ACTION_P2(ReturnDistanceTo, x, y) { + double dx = arg0 - x; + double dy = arg1 - y; + return sqrt(dx*dx + dy*dy); +} +``` +lets you write +``` +... WillOnce(ReturnDistanceTo(5.0, 26.5)); +``` + +You can view `ACTION` as a degenerated parameterized action where the +number of parameters is 0. + +You can also easily define actions overloaded on the number of parameters: +``` +ACTION_P(Plus, a) { ... } +ACTION_P2(Plus, a, b) { ... } +``` + +## Restricting the Type of an Argument or Parameter in an ACTION ## + +For maximum brevity and reusability, the `ACTION*` macros don't ask +you to provide the types of the mock function arguments and the action +parameters. Instead, we let the compiler infer the types for us. + +Sometimes, however, we may want to be more explicit about the types. +There are several tricks to do that. For example: +``` +ACTION(Foo) { + // Makes sure arg0 can be converted to int. + int n = arg0; + ... use n instead of arg0 here ... +} + +ACTION_P(Bar, param) { + // Makes sure the type of arg1 is const char*. + ::testing::StaticAssertTypeEq(); + + // Makes sure param can be converted to bool. + bool flag = param; +} +``` +where `StaticAssertTypeEq` is a compile-time assertion in Google Test +that verifies two types are the same. + +## Writing New Action Templates Quickly ## + +Sometimes you want to give an action explicit template parameters that +cannot be inferred from its value parameters. `ACTION_TEMPLATE()` +supports that and can be viewed as an extension to `ACTION()` and +`ACTION_P*()`. + +The syntax: +``` +ACTION_TEMPLATE(ActionName, + HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), + AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } +``` + +defines an action template that takes _m_ explicit template parameters +and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is +between 0 and 10. `name_i` is the name of the i-th template +parameter, and `kind_i` specifies whether it's a `typename`, an +integral constant, or a template. `p_i` is the name of the i-th value +parameter. + +Example: +``` +// DuplicateArg(output) converts the k-th argument of the mock +// function to type T and copies it to *output. +ACTION_TEMPLATE(DuplicateArg, + // Note the comma between int and k: + HAS_2_TEMPLATE_PARAMS(int, k, typename, T), + AND_1_VALUE_PARAMS(output)) { + *output = T(::testing::get(args)); +} +``` + +To create an instance of an action template, write: +``` + ActionName(v1, ..., v_n) +``` +where the `t`s are the template arguments and the +`v`s are the value arguments. The value argument +types are inferred by the compiler. For example: +``` +using ::testing::_; +... + int n; + EXPECT_CALL(mock, Foo(_, _)) + .WillOnce(DuplicateArg<1, unsigned char>(&n)); +``` + +If you want to explicitly specify the value argument types, you can +provide additional template arguments: +``` + ActionName(v1, ..., v_n) +``` +where `u_i` is the desired type of `v_i`. + +`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the +number of value parameters, but not on the number of template +parameters. Without the restriction, the meaning of the following is +unclear: + +``` + OverloadedAction(x); +``` + +Are we using a single-template-parameter action where `bool` refers to +the type of `x`, or a two-template-parameter action where the compiler +is asked to infer the type of `x`? + +## Using the ACTION Object's Type ## + +If you are writing a function that returns an `ACTION` object, you'll +need to know its type. The type depends on the macro used to define +the action and the parameter types. The rule is relatively simple: +| **Given Definition** | **Expression** | **Has Type** | +|:---------------------|:---------------|:-------------| +| `ACTION(Foo)` | `Foo()` | `FooAction` | +| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | +| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | +| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | +| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | +| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | +| ... | ... | ... | + +Note that we have to pick different suffixes (`Action`, `ActionP`, +`ActionP2`, and etc) for actions with different numbers of value +parameters, or the action definitions cannot be overloaded on the +number of them. + +## Writing New Monomorphic Actions ## + +While the `ACTION*` macros are very convenient, sometimes they are +inappropriate. For example, despite the tricks shown in the previous +recipes, they don't let you directly specify the types of the mock +function arguments and the action parameters, which in general leads +to unoptimized compiler error messages that can baffle unfamiliar +users. They also don't allow overloading actions based on parameter +types without jumping through some hoops. + +An alternative to the `ACTION*` macros is to implement +`::testing::ActionInterface`, where `F` is the type of the mock +function in which the action will be used. For example: + +``` +template class ActionInterface { + public: + virtual ~ActionInterface(); + + // Performs the action. Result is the return type of function type + // F, and ArgumentTuple is the tuple of arguments of F. + // + // For example, if F is int(bool, const string&), then Result would + // be int, and ArgumentTuple would be ::testing::tuple. + virtual Result Perform(const ArgumentTuple& args) = 0; +}; + +using ::testing::_; +using ::testing::Action; +using ::testing::ActionInterface; +using ::testing::MakeAction; + +typedef int IncrementMethod(int*); + +class IncrementArgumentAction : public ActionInterface { + public: + virtual int Perform(const ::testing::tuple& args) { + int* p = ::testing::get<0>(args); // Grabs the first argument. + return *p++; + } +}; + +Action IncrementArgument() { + return MakeAction(new IncrementArgumentAction); +} +... + + EXPECT_CALL(foo, Baz(_)) + .WillOnce(IncrementArgument()); + + int n = 5; + foo.Baz(&n); // Should return 5 and change n to 6. +``` + +## Writing New Polymorphic Actions ## + +The previous recipe showed you how to define your own action. This is +all good, except that you need to know the type of the function in +which the action will be used. Sometimes that can be a problem. For +example, if you want to use the action in functions with _different_ +types (e.g. like `Return()` and `SetArgPointee()`). + +If an action can be used in several types of mock functions, we say +it's _polymorphic_. The `MakePolymorphicAction()` function template +makes it easy to define such an action: + +``` +namespace testing { + +template +PolymorphicAction MakePolymorphicAction(const Impl& impl); + +} // namespace testing +``` + +As an example, let's define an action that returns the second argument +in the mock function's argument list. The first step is to define an +implementation class: + +``` +class ReturnSecondArgumentAction { + public: + template + Result Perform(const ArgumentTuple& args) const { + // To get the i-th (0-based) argument, use ::testing::get(args). + return ::testing::get<1>(args); + } +}; +``` + +This implementation class does _not_ need to inherit from any +particular class. What matters is that it must have a `Perform()` +method template. This method template takes the mock function's +arguments as a tuple in a **single** argument, and returns the result of +the action. It can be either `const` or not, but must be invokable +with exactly one template argument, which is the result type. In other +words, you must be able to call `Perform(args)` where `R` is the +mock function's return type and `args` is its arguments in a tuple. + +Next, we use `MakePolymorphicAction()` to turn an instance of the +implementation class into the polymorphic action we need. It will be +convenient to have a wrapper for this: + +``` +using ::testing::MakePolymorphicAction; +using ::testing::PolymorphicAction; + +PolymorphicAction ReturnSecondArgument() { + return MakePolymorphicAction(ReturnSecondArgumentAction()); +} +``` + +Now, you can use this polymorphic action the same way you use the +built-in ones: + +``` +using ::testing::_; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, int(bool flag, int n)); + MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(ReturnSecondArgument()); + EXPECT_CALL(foo, DoThat(_, _, _)) + .WillOnce(ReturnSecondArgument()); + ... + foo.DoThis(true, 5); // Will return 5. + foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". +``` + +## Teaching Google Mock How to Print Your Values ## + +When an uninteresting or unexpected call occurs, Google Mock prints the +argument values and the stack trace to help you debug. Assertion +macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in +question when the assertion fails. Google Mock and Google Test do this using +Google Test's user-extensible value printer. + +This printer knows how to print built-in C++ types, native arrays, STL +containers, and any type that supports the `<<` operator. For other +types, it prints the raw bytes in the value and hopes that you the +user can figure it out. +[Google Test's advanced guide](../../googletest/docs/AdvancedGuide.md#teaching-google-test-how-to-print-your-values) +explains how to extend the printer to do a better job at +printing your particular type than to dump the bytes. diff --git a/googlemock/docs/DesignDoc.md b/googlemock/docs/DesignDoc.md new file mode 100644 index 0000000..3f515c3 --- /dev/null +++ b/googlemock/docs/DesignDoc.md @@ -0,0 +1,280 @@ +This page discusses the design of new Google Mock features. + + + +# Macros for Defining Actions # + +## Problem ## + +Due to the lack of closures in C++, it currently requires some +non-trivial effort to define a custom action in Google Mock. For +example, suppose you want to "increment the value pointed to by the +second argument of the mock function and return it", you could write: + +``` +int IncrementArg1(Unused, int* p, Unused) { + return ++(*p); +} + +... WillOnce(Invoke(IncrementArg1)); +``` + +There are several things unsatisfactory about this approach: + + * Even though the action only cares about the second argument of the mock function, its definition needs to list other arguments as dummies. This is tedious. + * The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction. + * To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`. + +The latter two problems can be overcome using `MakePolymorphicAction()`, +but it requires much more boilerplate code: + +``` +class IncrementArg1Action { + public: + template + Result Perform(const ArgumentTuple& args) const { + return ++(*tr1::get<1>(args)); + } +}; + +PolymorphicAction IncrementArg1() { + return MakePolymorphicAction(IncrementArg1Action()); +} + +... WillOnce(IncrementArg1()); +``` + +Our goal is to allow defining custom actions with the least amount of +boiler-plate C++ requires. + +## Solution ## + +We propose to introduce a new macro: +``` +ACTION(name) { statements; } +``` + +Using this in a namespace scope will define an action with the given +name that executes the statements. Inside the statements, you can +refer to the K-th (0-based) argument of the mock function as `argK`. +For example: +``` +ACTION(IncrementArg1) { return ++(*arg1); } +``` +allows you to write +``` +... WillOnce(IncrementArg1()); +``` + +Note that you don't need to specify the types of the mock function +arguments, as brevity is a top design goal here. Rest assured that +your code is still type-safe though: you'll get a compiler error if +`*arg1` doesn't support the `++` operator, or if the type of +`++(*arg1)` isn't compatible with the mock function's return type. + +Another example: +``` +ACTION(Foo) { + (*arg2)(5); + Blah(); + *arg1 = 0; + return arg0; +} +``` +defines an action `Foo()` that invokes argument #2 (a function pointer) +with 5, calls function `Blah()`, sets the value pointed to by argument +#1 to 0, and returns argument #0. + +For more convenience and flexibility, you can also use the following +pre-defined symbols in the body of `ACTION`: + +| `argK_type` | The type of the K-th (0-based) argument of the mock function | +|:------------|:-------------------------------------------------------------| +| `args` | All arguments of the mock function as a tuple | +| `args_type` | The type of all arguments of the mock function as a tuple | +| `return_type` | The return type of the mock function | +| `function_type` | The type of the mock function | + +For example, when using an `ACTION` as a stub action for mock function: +``` +int DoSomething(bool flag, int* ptr); +``` +we have: +| **Pre-defined Symbol** | **Is Bound To** | +|:-----------------------|:----------------| +| `arg0` | the value of `flag` | +| `arg0_type` | the type `bool` | +| `arg1` | the value of `ptr` | +| `arg1_type` | the type `int*` | +| `args` | the tuple `(flag, ptr)` | +| `args_type` | the type `std::tr1::tuple` | +| `return_type` | the type `int` | +| `function_type` | the type `int(bool, int*)` | + +## Parameterized actions ## + +Sometimes you'll want to parameterize the action. For that we propose +another macro +``` +ACTION_P(name, param) { statements; } +``` + +For example, +``` +ACTION_P(Add, n) { return arg0 + n; } +``` +will allow you to write +``` +// Returns argument #0 + 5. +... WillOnce(Add(5)); +``` + +For convenience, we use the term _arguments_ for the values used to +invoke the mock function, and the term _parameters_ for the values +used to instantiate an action. + +Note that you don't need to provide the type of the parameter either. +Suppose the parameter is named `param`, you can also use the +Google-Mock-defined symbol `param_type` to refer to the type of the +parameter as inferred by the compiler. + +We will also provide `ACTION_P2`, `ACTION_P3`, and etc to support +multi-parameter actions. For example, +``` +ACTION_P2(ReturnDistanceTo, x, y) { + double dx = arg0 - x; + double dy = arg1 - y; + return sqrt(dx*dx + dy*dy); +} +``` +lets you write +``` +... WillOnce(ReturnDistanceTo(5.0, 26.5)); +``` + +You can view `ACTION` as a degenerated parameterized action where the +number of parameters is 0. + +## Advanced Usages ## + +### Overloading Actions ### + +You can easily define actions overloaded on the number of parameters: +``` +ACTION_P(Plus, a) { ... } +ACTION_P2(Plus, a, b) { ... } +``` + +### Restricting the Type of an Argument or Parameter ### + +For maximum brevity and reusability, the `ACTION*` macros don't let +you specify the types of the mock function arguments and the action +parameters. Instead, we let the compiler infer the types for us. + +Sometimes, however, we may want to be more explicit about the types. +There are several tricks to do that. For example: +``` +ACTION(Foo) { + // Makes sure arg0 can be converted to int. + int n = arg0; + ... use n instead of arg0 here ... +} + +ACTION_P(Bar, param) { + // Makes sure the type of arg1 is const char*. + ::testing::StaticAssertTypeEq(); + + // Makes sure param can be converted to bool. + bool flag = param; +} +``` +where `StaticAssertTypeEq` is a compile-time assertion we plan to add to +Google Test (the name is chosen to match `static_assert` in C++0x). + +### Using the ACTION Object's Type ### + +If you are writing a function that returns an `ACTION` object, you'll +need to know its type. The type depends on the macro used to define +the action and the parameter types. The rule is relatively simple: +| **Given Definition** | **Expression** | **Has Type** | +|:---------------------|:---------------|:-------------| +| `ACTION(Foo)` | `Foo()` | `FooAction` | +| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | +| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | +| ... | ... | ... | + +Note that we have to pick different suffixes (`Action`, `ActionP`, +`ActionP2`, and etc) for actions with different numbers of parameters, +or the action definitions cannot be overloaded on the number of +parameters. + +## When to Use ## + +While the new macros are very convenient, please also consider other +means of implementing actions (e.g. via `ActionInterface` or +`MakePolymorphicAction()`), especially if you need to use the defined +action a lot. While the other approaches require more work, they give +you more control on the types of the mock function arguments and the +action parameters, which in general leads to better compiler error +messages that pay off in the long run. They also allow overloading +actions based on parameter types, as opposed to just the number of +parameters. + +## Related Work ## + +As you may have realized, the `ACTION*` macros resemble closures (also +known as lambda expressions or anonymous functions). Indeed, both of +them seek to lower the syntactic overhead for defining a function. + +C++0x will support lambdas, but they are not part of C++ right now. +Some non-standard libraries (most notably BLL or Boost Lambda Library) +try to alleviate this problem. However, they are not a good choice +for defining actions as: + + * They are non-standard and not widely installed. Google Mock only depends on standard libraries and `tr1::tuple`, which is part of the new C++ standard and comes with gcc 4+. We want to keep it that way. + * They are not trivial to learn. + * They will become obsolete when C++0x's lambda feature is widely supported. We don't want to make our users use a dying library. + * Since they are based on operators, they are rather ad hoc: you cannot use statements, and you cannot pass the lambda arguments to a function, for example. + * They have subtle semantics that easily confuses new users. For example, in expression `_1++ + foo++`, `foo` will be incremented only once where the expression is evaluated, while `_1` will be incremented every time the unnamed function is invoked. This is far from intuitive. + +`ACTION*` avoid all these problems. + +## Future Improvements ## + +There may be a need for composing `ACTION*` definitions (i.e. invoking +another `ACTION` inside the definition of one `ACTION*`). We are not +sure we want it yet, as one can get a similar effect by putting +`ACTION` definitions in function templates and composing the function +templates. We'll revisit this based on user feedback. + +The reason we don't allow `ACTION*()` inside a function body is that +the current C++ standard doesn't allow function-local types to be used +to instantiate templates. The upcoming C++0x standard will lift this +restriction. Once this feature is widely supported by compilers, we +can revisit the implementation and add support for using `ACTION*()` +inside a function. + +C++0x will also support lambda expressions. When they become +available, we may want to support using lambdas as actions. + +# Macros for Defining Matchers # + +Once the macros for defining actions are implemented, we plan to do +the same for matchers: + +``` +MATCHER(name) { statements; } +``` + +where you can refer to the value being matched as `arg`. For example, +given: + +``` +MATCHER(IsPositive) { return arg > 0; } +``` + +you can use `IsPositive()` as a matcher that matches a value iff it is +greater than 0. + +We will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized +matchers. \ No newline at end of file diff --git a/googlemock/docs/DevGuide.md b/googlemock/docs/DevGuide.md new file mode 100644 index 0000000..f4bab75 --- /dev/null +++ b/googlemock/docs/DevGuide.md @@ -0,0 +1,132 @@ + + +If you are interested in understanding the internals of Google Mock, +building from source, or contributing ideas or modifications to the +project, then this document is for you. + +# Introduction # + +First, let's give you some background of the project. + +## Licensing ## + +All Google Mock source and pre-built packages are provided under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php). + +## The Google Mock Community ## + +The Google Mock community exists primarily through the [discussion group](http://groups.google.com/group/googlemock), the +[issue tracker](https://github.com/google/googletest/issues) and, to a lesser extent, the [source control repository](../). You are definitely encouraged to contribute to the +discussion and you can also help us to keep the effectiveness of the +group high by following and promoting the guidelines listed here. + +### Please Be Friendly ### + +Showing courtesy and respect to others is a vital part of the Google +culture, and we strongly encourage everyone participating in Google +Mock development to join us in accepting nothing less. Of course, +being courteous is not the same as failing to constructively disagree +with each other, but it does mean that we should be respectful of each +other when enumerating the 42 technical reasons that a particular +proposal may not be the best choice. There's never a reason to be +antagonistic or dismissive toward anyone who is sincerely trying to +contribute to a discussion. + +Sure, C++ testing is serious business and all that, but it's also +a lot of fun. Let's keep it that way. Let's strive to be one of the +friendliest communities in all of open source. + +### Where to Discuss Google Mock ### + +As always, discuss Google Mock in the official [Google C++ Mocking Framework discussion group](http://groups.google.com/group/googlemock). You don't have to actually submit +code in order to sign up. Your participation itself is a valuable +contribution. + +# Working with the Code # + +If you want to get your hands dirty with the code inside Google Mock, +this is the section for you. + +## Checking Out the Source from Subversion ## + +Checking out the Google Mock source is most useful if you plan to +tweak it yourself. You check out the source for Google Mock using a +[Subversion](http://subversion.tigris.org/) client as you would for any +other project hosted on Google Code. Please see the instruction on +the [source code access page](../) for how to do it. + +## Compiling from Source ## + +Once you check out the code, you can find instructions on how to +compile it in the [README](../README.md) file. + +## Testing ## + +A mocking framework is of no good if itself is not thoroughly tested. +Tests should be written for any new code, and changes should be +verified to not break existing tests before they are submitted for +review. To perform the tests, follow the instructions in [README](http://code.google.com/p/googlemock/source/browse/trunk/README) and +verify that there are no failures. + +# Contributing Code # + +We are excited that Google Mock is now open source, and hope to get +great patches from the community. Before you fire up your favorite IDE +and begin hammering away at that new feature, though, please take the +time to read this section and understand the process. While it seems +rigorous, we want to keep a high standard of quality in the code +base. + +## Contributor License Agreements ## + +You must sign a Contributor License Agreement (CLA) before we can +accept any code. The CLA protects you and us. + + * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). + * If you work for a company that wants to allow you to contribute your work to Google Mock, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. + +## Coding Style ## + +To keep the source consistent, readable, diffable and easy to merge, +we use a fairly rigid coding style, as defined by the [google-styleguide](https://github.com/google/styleguide) project. All patches will be expected +to conform to the style outlined [here](https://github.com/google/styleguide/blob/gh-pages/cppguide.xml). + +## Submitting Patches ## + +Please do submit code. Here's what you need to do: + + 1. Normally you should make your change against the SVN trunk instead of a branch or a tag, as the latter two are for release control and should be treated mostly as read-only. + 1. Decide which code you want to submit. A submission should be a set of changes that addresses one issue in the [Google Mock issue tracker](http://code.google.com/p/googlemock/issues/list). Please don't mix more than one logical change per submittal, because it makes the history hard to follow. If you want to make a change that doesn't have a corresponding issue in the issue tracker, please create one. + 1. Also, coordinate with team members that are listed on the issue in question. This ensures that work isn't being duplicated and communicating your plan early also generally leads to better patches. + 1. Ensure that your code adheres to the [Google Mock source code style](#Coding_Style.md). + 1. Ensure that there are unit tests for your code. + 1. Sign a Contributor License Agreement. + 1. Create a patch file using `svn diff`. + 1. We use [Rietveld](http://codereview.appspot.com/) to do web-based code reviews. You can read about the tool [here](https://github.com/rietveld-codereview/rietveld/wiki). When you are ready, upload your patch via Rietveld and notify `googlemock@googlegroups.com` to review it. There are several ways to upload the patch. We recommend using the [upload\_gmock.py](../scripts/upload_gmock.py) script, which you can find in the `scripts/` folder in the SVN trunk. + +## Google Mock Committers ## + +The current members of the Google Mock engineering team are the only +committers at present. In the great tradition of eating one's own +dogfood, we will be requiring each new Google Mock engineering team +member to earn the right to become a committer by following the +procedures in this document, writing consistently great code, and +demonstrating repeatedly that he or she truly gets the zen of Google +Mock. + +# Release Process # + +We follow the typical release process for Subversion-based projects: + + 1. A release branch named `release-X.Y` is created. + 1. Bugs are fixed and features are added in trunk; those individual patches are merged into the release branch until it's stable. + 1. An individual point release (the `Z` in `X.Y.Z`) is made by creating a tag from the branch. + 1. Repeat steps 2 and 3 throughout one release cycle (as determined by features or time). + 1. Go back to step 1 to create another release branch and so on. + + +--- + +This page is based on the [Making GWT Better](http://code.google.com/webtoolkit/makinggwtbetter.html) guide from the [Google Web Toolkit](http://code.google.com/webtoolkit/) project. Except as otherwise [noted](http://code.google.com/policies.html#restrictions), the content of this page is licensed under the [Creative Commons Attribution 2.5 License](http://creativecommons.org/licenses/by/2.5/). diff --git a/googlemock/docs/Documentation.md b/googlemock/docs/Documentation.md new file mode 100644 index 0000000..444151e --- /dev/null +++ b/googlemock/docs/Documentation.md @@ -0,0 +1,12 @@ +This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)** +- **if you use a released version of Google Mock, please read the documentation for that specific version instead.** + + * [ForDummies](ForDummies.md) -- start here if you are new to Google Mock. + * [CheatSheet](CheatSheet.md) -- a quick reference. + * [CookBook](CookBook.md) -- recipes for doing various tasks using Google Mock. + * [FrequentlyAskedQuestions](FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. + +To contribute code to Google Mock, read: + + * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. + * [Pump Manual](../googletest/docs/PumpManual.md) -- how we generate some of Google Mock's source files. diff --git a/googlemock/docs/ForDummies.md b/googlemock/docs/ForDummies.md new file mode 100644 index 0000000..0da4cbe --- /dev/null +++ b/googlemock/docs/ForDummies.md @@ -0,0 +1,439 @@ + + +(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](FrequentlyAskedQuestions.md#how-am-i-supposed-to-make-sense-of-these-horrible-template-errors).) + +# What Is Google C++ Mocking Framework? # +When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). + +**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: + + * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. + * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. + +If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. + +**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. + +Using Google Mock involves three basic steps: + + 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; + 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; + 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. + +# Why Google Mock? # +While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: + + * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. + * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. + * The knowledge you gained from using one mock doesn't transfer to the next. + +In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. + +Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: + + * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". + * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). + * Your tests are brittle as some resources they use are unreliable (e.g. the network). + * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. + * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. + * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. + +We encourage you to use Google Mock as: + + * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! + * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. + +# Getting Started # +Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. + +# A Case for Mock Turtles # +Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: + +``` +class Turtle { + ... + virtual ~Turtle() {} + virtual void PenUp() = 0; + virtual void PenDown() = 0; + virtual void Forward(int distance) = 0; + virtual void Turn(int degrees) = 0; + virtual void GoTo(int x, int y) = 0; + virtual int GetX() const = 0; + virtual int GetY() const = 0; +}; +``` + +(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) + +You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. + +Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. + +# Writing the Mock Class # +If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) + +## How to Define It ## +Using the `Turtle` interface as example, here are the simple steps you need to follow: + + 1. Derive a class `MockTurtle` from `Turtle`. + 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](CookBook.md#mocking-nonvirtual-methods), it's much more involved). Count how many arguments it has. + 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. + 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). + 1. Repeat until all virtual functions you want to mock are done. + +After the process, you should have something like: + +``` +#include "gmock/gmock.h" // Brings in Google Mock. +class MockTurtle : public Turtle { + public: + ... + MOCK_METHOD0(PenUp, void()); + MOCK_METHOD0(PenDown, void()); + MOCK_METHOD1(Forward, void(int distance)); + MOCK_METHOD1(Turn, void(int degrees)); + MOCK_METHOD2(GoTo, void(int x, int y)); + MOCK_CONST_METHOD0(GetX, int()); + MOCK_CONST_METHOD0(GetY, int()); +}; +``` + +You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. + +**Tip:** If even this is too much work for you, you'll find the +`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line +tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, +and it will print the definition of the mock class for you. Due to the +complexity of the C++ language, this script may not always work, but +it can be quite handy when it does. For more details, read the [user documentation](../scripts/generator/README). + +## Where to Put It ## +When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) + +So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. + +Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. + +# Using Mocks in Tests # +Once you have a mock class, using it is easy. The typical work flow is: + + 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). + 1. Create some mock objects. + 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). + 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. + 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. + +Here's an example: + +``` +#include "path/to/mock-turtle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +using ::testing::AtLeast; // #1 + +TEST(PainterTest, CanDrawSomething) { + MockTurtle turtle; // #2 + EXPECT_CALL(turtle, PenDown()) // #3 + .Times(AtLeast(1)); + + Painter painter(&turtle); // #4 + + EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); +} // #5 + +int main(int argc, char** argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} +``` + +As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: + +``` +path/to/my_test.cc:119: Failure +Actual function call count doesn't match this expectation: +Actually: never called; +Expected: called at least once. +``` + +**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. + +**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. + +**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. + +This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. + +Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. + +## Using Google Mock with Any Testing Framework ## +If you want to use something other than Google Test (e.g. [CppUnit](http://sourceforge.net/projects/cppunit/) or +[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: +``` +int main(int argc, char** argv) { + // The following line causes Google Mock to throw an exception on failure, + // which will be interpreted by your testing framework as a test failure. + ::testing::GTEST_FLAG(throw_on_failure) = true; + ::testing::InitGoogleMock(&argc, argv); + ... whatever your testing framework requires ... +} +``` + +This approach has a catch: it makes Google Mock throw an exception +from a mock object's destructor sometimes. With some compilers, this +sometimes causes the test program to crash. You'll still be able to +notice that the test has failed, but it's not a graceful failure. + +A better solution is to use Google Test's +[event listener API](../../googletest/docs/AdvancedGuide.md#extending-google-test-by-handling-test-events) +to report a test failure to your testing framework properly. You'll need to +implement the `OnTestPartResult()` method of the event listener interface, but it +should be straightforward. + +If this turns out to be too much work, we suggest that you stick with +Google Test, which works with Google Mock seamlessly (in fact, it is +technically part of Google Mock.). If there is a reason that you +cannot use Google Test, please let us know. + +# Setting Expectations # +The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." + +## General Syntax ## +In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: + +``` +EXPECT_CALL(mock_object, method(matchers)) + .Times(cardinality) + .WillOnce(action) + .WillRepeatedly(action); +``` + +The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) + +The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. + +This syntax is designed to make an expectation read like English. For example, you can probably guess that + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .Times(5) + .WillOnce(Return(100)) + .WillOnce(Return(150)) + .WillRepeatedly(Return(200)); +``` + +says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). + +**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. + +## Matchers: What Arguments Do We Expect? ## +When a mock function takes arguments, we must specify what arguments we are expecting; for example: + +``` +// Expects the turtle to move forward by 100 units. +EXPECT_CALL(turtle, Forward(100)); +``` + +Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": + +``` +using ::testing::_; +... +// Expects the turtle to move forward. +EXPECT_CALL(turtle, Forward(_)); +``` + +`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. + +A list of built-in matchers can be found in the [CheatSheet](CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: + +``` +using ::testing::Ge;... +EXPECT_CALL(turtle, Forward(Ge(100))); +``` + +This checks that the turtle will be told to go forward by at least 100 units. + +## Cardinalities: How Many Times Will It Be Called? ## +The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. + +An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. + +We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](CheatSheet.md). + +The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: + + * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. + * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. + * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. + +**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? + +## Actions: What Should It Do? ## +Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. + +First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). In addition, in C++ 11 and above, a mock function whose return type is default-constructible (i.e. has a default constructor) has a default action of returning a default-constructed value. If you don't say anything, this behavior will be used. + +Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillOnce(Return(300)); +``` + +This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillRepeatedly(Return(300)); +``` + +says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. + +Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). + +What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](CheatSheet.md#actions). + +**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: + +``` +int n = 100; +EXPECT_CALL(turtle, GetX()) +.Times(4) +.WillRepeatedly(Return(n++)); +``` + +Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](CookBook.md). + +Time for another quiz! What do you think the following means? + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) +.Times(4) +.WillOnce(Return(100)); +``` + +Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. + +## Using Multiple Expectations ## +So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. + +By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: + +``` +using ::testing::_;... +EXPECT_CALL(turtle, Forward(_)); // #1 +EXPECT_CALL(turtle, Forward(10)) // #2 + .Times(2); +``` + +If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. + +**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. + +## Ordered vs Unordered Calls ## +By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. + +Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: + +``` +using ::testing::InSequence;... +TEST(FooTest, DrawsLineSegment) { + ... + { + InSequence dummy; + + EXPECT_CALL(turtle, PenDown()); + EXPECT_CALL(turtle, Forward(100)); + EXPECT_CALL(turtle, PenUp()); + } + Foo(); +} +``` + +By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. + +In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. + +(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](CookBook#Expecting_Partially_Ordered_Calls.md).) + +## All Expectations Are Sticky (Unless Said Otherwise) ## +Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? + +After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): + +``` +using ::testing::_;... +EXPECT_CALL(turtle, GoTo(_, _)) // #1 + .Times(AnyNumber()); +EXPECT_CALL(turtle, GoTo(0, 0)) // #2 + .Times(2); +``` + +Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. + +This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). + +Simple? Let's see if you've really understood it: what does the following code say? + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)); +} +``` + +If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! + +One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); +} +``` + +And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: + +``` +using ::testing::InSequence; +using ::testing::Return; +... +{ + InSequence s; + + for (int i = 1; i <= n; i++) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); + } +} +``` + +By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). + +## Uninteresting Calls ## +A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. + +In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. + +# What Now? # +Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. + +Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. diff --git a/googlemock/docs/FrequentlyAskedQuestions.md b/googlemock/docs/FrequentlyAskedQuestions.md new file mode 100644 index 0000000..5eac83f --- /dev/null +++ b/googlemock/docs/FrequentlyAskedQuestions.md @@ -0,0 +1,628 @@ + + +Please send your questions to the +[googlemock](http://groups.google.com/group/googlemock) discussion +group. If you need help with compiler errors, make sure you have +tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. + +## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## + +In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](CookBook.md#mocking-nonvirtual-methods). + +## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## + +After version 1.4.0 of Google Mock was released, we had an idea on how +to make it easier to write matchers that can generate informative +messages efficiently. We experimented with this idea and liked what +we saw. Therefore we decided to implement it. + +Unfortunately, this means that if you have defined your own matchers +by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, +your definitions will no longer compile. Matchers defined using the +`MATCHER*` family of macros are not affected. + +Sorry for the hassle if your matchers are affected. We believe it's +in everyone's long-term interest to make this change sooner than +later. Fortunately, it's usually not hard to migrate an existing +matcher to the new API. Here's what you need to do: + +If you wrote your matcher like this: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` + +you'll need to change it to: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` +(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second +argument of type `MatchResultListener*`.) + +If you were also using `ExplainMatchResultTo()` to improve the matcher +message: +``` +// Old matcher definition that doesn't work with the lastest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + + virtual void ExplainMatchResultTo(MyType value, + ::std::ostream* os) const { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Foo property is " << value.GetFoo(); + } + ... +}; +``` + +you should move the logic of `ExplainMatchResultTo()` into +`MatchAndExplain()`, using the `MatchResultListener` argument where +the `::std::ostream` was used: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Foo property is " << value.GetFoo(); + return value.GetFoo() > 5; + } + ... +}; +``` + +If your matcher is defined using `MakePolymorphicMatcher()`: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you should rename the `Matches()` method to `MatchAndExplain()` and +add a `MatchResultListener*` argument (the same as what you need to do +for matchers defined by implementing `MatcherInterface`): +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +If your polymorphic matcher uses `ExplainMatchResultTo()` for better +failure messages: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +void ExplainMatchResultTo(const MyGreatMatcher& matcher, + MyType value, + ::std::ostream* os) { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Bar property is " << value.GetBar(); +} +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you'll need to move the logic inside `ExplainMatchResultTo()` to +`MatchAndExplain()`: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Bar property is " << value.GetBar(); + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +For more information, you can read these +[two](CookBook.md#writing-new-monomorphic-matchers) +[recipes](CookBook.md#writing-new-polymorphic-matchers) +from the cookbook. As always, you +are welcome to post questions on `googlemock@googlegroups.com` if you +need any help. + +## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## + +Google Mock works out of the box with Google Test. However, it's easy +to configure it to work with any testing framework of your choice. +[Here](ForDummies.md#using-google-mock-with-any-testing-framework) is how. + +## How am I supposed to make sense of these horrible template errors? ## + +If you are confused by the compiler errors gcc threw at you, +try consulting the _Google Mock Doctor_ tool first. What it does is to +scan stdin for gcc error messages, and spit out diagnoses on the +problems (we call them diseases) your code has. + +To "install", run command: +``` +alias gmd='/scripts/gmock_doctor.py' +``` + +To use it, do: +``` + 2>&1 | gmd +``` + +For example: +``` +make my_test 2>&1 | gmd +``` + +Or you can run `gmd` and copy-n-paste gcc's error messages to it. + +## Can I mock a variadic function? ## + +You cannot mock a variadic function (i.e. a function taking ellipsis +(`...`) arguments) directly in Google Mock. + +The problem is that in general, there is _no way_ for a mock object to +know how many arguments are passed to the variadic method, and what +the arguments' types are. Only the _author of the base class_ knows +the protocol, and we cannot look into his head. + +Therefore, to mock such a function, the _user_ must teach the mock +object how to figure out the number of arguments and their types. One +way to do it is to provide overloaded versions of the function. + +Ellipsis arguments are inherited from C and not really a C++ feature. +They are unsafe to use and don't work with arguments that have +constructors or destructors. Therefore we recommend to avoid them in +C++ as much as possible. + +## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## + +If you compile this using Microsoft Visual C++ 2005 SP1: +``` +class Foo { + ... + virtual void Bar(const int i) = 0; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Bar, void(const int i)); +}; +``` +You may get the following warning: +``` +warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier +``` + +This is a MSVC bug. The same code compiles fine with gcc ,for +example. If you use Visual C++ 2008 SP1, you would get the warning: +``` +warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers +``` + +In C++, if you _declare_ a function with a `const` parameter, the +`const` modifier is _ignored_. Therefore, the `Foo` base class above +is equivalent to: +``` +class Foo { + ... + virtual void Bar(int i) = 0; // int or const int? Makes no difference. +}; +``` + +In fact, you can _declare_ Bar() with an `int` parameter, and _define_ +it with a `const int` parameter. The compiler will still match them +up. + +Since making a parameter `const` is meaningless in the method +_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. +That should workaround the VC bug. + +Note that we are talking about the _top-level_ `const` modifier here. +If the function parameter is passed by pointer or reference, declaring +the _pointee_ or _referee_ as `const` is still meaningful. For +example, the following two declarations are _not_ equivalent: +``` +void Bar(int* p); // Neither p nor *p is const. +void Bar(const int* p); // p is not const, but *p is. +``` + +## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## + +We've noticed that when the `/clr` compiler flag is used, Visual C++ +uses 5~6 times as much memory when compiling a mock class. We suggest +to avoid `/clr` when compiling native C++ mocks. + +## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## + +You might want to run your test with +`--gmock_verbose=info`. This flag lets Google Mock print a trace +of every mock function call it receives. By studying the trace, +you'll gain insights on why the expectations you set are not met. + +## How can I assert that a function is NEVER called? ## + +``` +EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## + +When Google Mock detects a failure, it prints relevant information +(the mock function arguments, the state of relevant expectations, and +etc) to help the user debug. If another failure is detected, Google +Mock will do the same, including printing the state of relevant +expectations. + +Sometimes an expectation's state didn't change between two failures, +and you'll see the same description of the state twice. They are +however _not_ redundant, as they refer to _different points in time_. +The fact they are the same _is_ interesting information. + +## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## + +Does the class (hopefully a pure interface) you are mocking have a +virtual destructor? + +Whenever you derive from a base class, make sure its destructor is +virtual. Otherwise Bad Things will happen. Consider the following +code: + +``` +class Base { + public: + // Not virtual, but should be. + ~Base() { ... } + ... +}; + +class Derived : public Base { + public: + ... + private: + std::string value_; +}; + +... + Base* p = new Derived; + ... + delete p; // Surprise! ~Base() will be called, but ~Derived() will not + // - value_ is leaked. +``` + +By changing `~Base()` to virtual, `~Derived()` will be correctly +called when `delete p` is executed, and the heap checker +will be happy. + +## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## + +When people complain about this, often they are referring to code like: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. However, I have to write the expectations in the +// reverse order. This sucks big time!!! +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); +``` + +The problem is that they didn't pick the **best** way to express the test's +intent. + +By default, expectations don't have to be matched in _any_ particular +order. If you want them to match in a certain order, you need to be +explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's +easy to accidentally over-specify your tests, and we want to make it +harder to do so. + +There are two better ways to write the test spec. You could either +put the expectations in sequence: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. Using a sequence, we can write the expectations +// in their natural order. +{ + InSequence s; + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +} +``` + +or you can put the sequence of actions in the same expectation: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +``` + +Back to the original questions: why does Google Mock search the +expectations (and `ON_CALL`s) from back to front? Because this +allows a user to set up a mock's behavior for the common case early +(e.g. in the mock's constructor or the test fixture's set-up phase) +and customize it with more specific rules later. If Google Mock +searches from front to back, this very useful pattern won't be +possible. + +## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## + +When choosing between being neat and being safe, we lean toward the +latter. So the answer is that we think it's better to show the +warning. + +Often people write `ON_CALL`s in the mock object's +constructor or `SetUp()`, as the default behavior rarely changes from +test to test. Then in the test body they set the expectations, which +are often different for each test. Having an `ON_CALL` in the set-up +part of a test doesn't mean that the calls are expected. If there's +no `EXPECT_CALL` and the method is called, it's possibly an error. If +we quietly let the call go through without notifying the user, bugs +may creep in unnoticed. + +If, however, you are sure that the calls are OK, you can write + +``` +EXPECT_CALL(foo, Bar(_)) + .WillRepeatedly(...); +``` + +instead of + +``` +ON_CALL(foo, Bar(_)) + .WillByDefault(...); +``` + +This tells Google Mock that you do expect the calls and no warning should be +printed. + +Also, you can control the verbosity using the `--gmock_verbose` flag. +If you find the output too noisy when debugging, just choose a less +verbose level. + +## How can I delete the mock function's argument in an action? ## + +If you find yourself needing to perform some action that's not +supported by Google Mock directly, remember that you can define your own +actions using +[MakeAction()](CookBook.md#writing-new-actions) or +[MakePolymorphicAction()](CookBook.md#writing_new_polymorphic_actions), +or you can write a stub function and invoke it using +[Invoke()](CookBook.md#using-functions_methods_functors). + +## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## + +What?! I think it's beautiful. :-) + +While which syntax looks more natural is a subjective matter to some +extent, Google Mock's syntax was chosen for several practical advantages it +has. + +Try to mock a function that takes a map as an argument: +``` +virtual int GetSize(const map& m); +``` + +Using the proposed syntax, it would be: +``` +MOCK_METHOD1(GetSize, int, const map& m); +``` + +Guess what? You'll get a compiler error as the compiler thinks that +`const map& m` are **two**, not one, arguments. To work +around this you can use `typedef` to give the map type a name, but +that gets in the way of your work. Google Mock's syntax avoids this +problem as the function's argument types are protected inside a pair +of parentheses: +``` +// This compiles fine. +MOCK_METHOD1(GetSize, int(const map& m)); +``` + +You still need a `typedef` if the return type contains an unprotected +comma, but that's much rarer. + +Other advantages include: + 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. + 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. + 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! + +## My code calls a static/global function. Can I mock it? ## + +You can, but you need to make some changes. + +In general, if you find yourself needing to mock a static function, +it's a sign that your modules are too tightly coupled (and less +flexible, less reusable, less testable, etc). You are probably better +off defining a small interface and call the function through that +interface, which then can be easily mocked. It's a bit of work +initially, but usually pays for itself quickly. + +This Google Testing Blog +[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) +says it excellently. Check it out. + +## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## + +I know it's not a question, but you get an answer for free any way. :-) + +With Google Mock, you can create mocks in C++ easily. And people might be +tempted to use them everywhere. Sometimes they work great, and +sometimes you may find them, well, a pain to use. So, what's wrong in +the latter case? + +When you write a test without using mocks, you exercise the code and +assert that it returns the correct value or that the system is in an +expected state. This is sometimes called "state-based testing". + +Mocks are great for what some call "interaction-based" testing: +instead of checking the system state at the very end, mock objects +verify that they are invoked the right way and report an error as soon +as it arises, giving you a handle on the precise context in which the +error was triggered. This is often more effective and economical to +do than state-based testing. + +If you are doing state-based testing and using a test double just to +simulate the real object, you are probably better off using a fake. +Using a mock in this case causes pain, as it's not a strong point for +mocks to perform complex actions. If you experience this and think +that mocks suck, you are just not using the right tool for your +problem. Or, you might be trying to solve the wrong problem. :-) + +## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## + +By all means, NO! It's just an FYI. + +What it means is that you have a mock function, you haven't set any +expectations on it (by Google Mock's rule this means that you are not +interested in calls to this function and therefore it can be called +any number of times), and it is called. That's OK - you didn't say +it's not OK to call the function! + +What if you actually meant to disallow this function to be called, but +forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While +one can argue that it's the user's fault, Google Mock tries to be nice and +prints you a note. + +So, when you see the message and believe that there shouldn't be any +uninteresting calls, you should investigate what's going on. To make +your life easier, Google Mock prints the function name and arguments +when an uninteresting call is encountered. + +## I want to define a custom action. Should I use Invoke() or implement the action interface? ## + +Either way is fine - you want to choose the one that's more convenient +for your circumstance. + +Usually, if your action is for a particular function type, defining it +using `Invoke()` should be easier; if your action can be used in +functions of different types (e.g. if you are defining +`Return(value)`), `MakePolymorphicAction()` is +easiest. Sometimes you want precise control on what types of +functions the action can be used in, and implementing +`ActionInterface` is the way to go here. See the implementation of +`Return()` in `include/gmock/gmock-actions.h` for an example. + +## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## + +You got this error as Google Mock has no idea what value it should return +when the mock method is called. `SetArgPointee()` says what the +side effect is, but doesn't say what the return value should be. You +need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. + +See this [recipe](CookBook.md#mocking_side_effects) for more details and an example. + + +## My question is not in your FAQ! ## + +If you cannot find the answer to your question in this FAQ, there are +some other resources you can use: + + 1. read other [documentation](Documentation.md), + 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), + 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). + +Please note that creating an issue in the +[issue tracker](https://github.com/google/googletest/issues) is _not_ +a good way to get your answer, as it is monitored infrequently by a +very small number of people. + +When asking a question, it's helpful to provide as much of the +following information as possible (people cannot help you if there's +not enough information in your question): + + * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), + * your operating system, + * the name and version of your compiler, + * the complete command line flags you give to your compiler, + * the complete compiler error messages (if the question is about compilation), + * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. diff --git a/googlemock/docs/KnownIssues.md b/googlemock/docs/KnownIssues.md new file mode 100644 index 0000000..adadf51 --- /dev/null +++ b/googlemock/docs/KnownIssues.md @@ -0,0 +1,19 @@ +As any non-trivial software system, Google Mock has some known limitations and problems. We are working on improving it, and welcome your help! The follow is a list of issues we know about. + + + +## README contains outdated information on Google Mock's compatibility with other testing frameworks ## + +The `README` file in release 1.1.0 still says that Google Mock only works with Google Test. Actually, you can configure Google Mock to work with any testing framework you choose. + +## Tests failing on machines using Power PC CPUs (e.g. some Macs) ## + +`gmock_output_test` and `gmock-printers_test` are known to fail with Power PC CPUs. This is due to portability issues with these tests, and is not an indication of problems in Google Mock itself. You can safely ignore them. + +## Failed to resolve libgtest.so.0 in tests when built against installed Google Test ## + +This only applies if you manually built and installed Google Test, and then built a Google Mock against it (either explicitly, or because gtest-config was in your path post-install). In this situation, Libtool has a known issue with certain systems' ldconfig setup: + +http://article.gmane.org/gmane.comp.sysutils.automake.general/9025 + +This requires a manual run of "sudo ldconfig" after the "sudo make install" for Google Test before any binaries which link against it can be executed. This isn't a bug in our install, but we should at least have documented it or hacked a work-around into our install. We should have one of these solutions in our next release. \ No newline at end of file diff --git a/googlemock/docs/v1_5/CheatSheet.md b/googlemock/docs/v1_5/CheatSheet.md new file mode 100644 index 0000000..3c7bed4 --- /dev/null +++ b/googlemock/docs/v1_5/CheatSheet.md @@ -0,0 +1,525 @@ + + +# Defining a Mock Class # + +## Mocking a Normal Class ## + +Given +``` +class Foo { + ... + virtual ~Foo(); + virtual int GetSize() const = 0; + virtual string Describe(const char* name) = 0; + virtual string Describe(int type) = 0; + virtual bool Process(Bar elem, int count) = 0; +}; +``` +(note that `~Foo()` **must** be virtual) we can define its mock as +``` +#include + +class MockFoo : public Foo { + MOCK_CONST_METHOD0(GetSize, int()); + MOCK_METHOD1(Describe, string(const char* name)); + MOCK_METHOD1(Describe, string(int type)); + MOCK_METHOD2(Process, bool(Bar elem, int count)); +}; +``` + +To create a "nice" mock object which ignores all uninteresting calls, +or a "strict" mock object, which treats them as failures: +``` +NiceMock nice_foo; // The type is a subclass of MockFoo. +StrictMock strict_foo; // The type is a subclass of MockFoo. +``` + +## Mocking a Class Template ## + +To mock +``` +template +class StackInterface { + public: + ... + virtual ~StackInterface(); + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; +``` +(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: +``` +template +class MockStack : public StackInterface { + public: + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Specifying Calling Conventions for Mock Functions ## + +If your mock function doesn't use the default calling convention, you +can specify it by appending `_WITH_CALLTYPE` to any of the macros +described in the previous two sections and supplying the calling +convention as the first argument to the macro. For example, +``` + MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); + MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); +``` +where `STDMETHODCALLTYPE` is defined by `` on Windows. + +# Using Mocks in Tests # + +The typical flow is: + 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. + 1. Create the mock objects. + 1. Optionally, set the default actions of the mock objects. + 1. Set your expectations on the mock objects (How will they be called? What wil they do?). + 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. + 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. + +Here is an example: +``` +using ::testing::Return; // #1 + +TEST(BarTest, DoesThis) { + MockFoo foo; // #2 + + ON_CALL(foo, GetSize()) // #3 + .WillByDefault(Return(1)); + // ... other default actions ... + + EXPECT_CALL(foo, Describe(5)) // #4 + .Times(3) + .WillRepeatedly(Return("Category 5")); + // ... other expectations ... + + EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 +} // #6 +``` + +# Setting Default Actions # + +Google Mock has a **built-in default action** for any function that +returns `void`, `bool`, a numeric value, or a pointer. + +To customize the default action for functions with return type `T` globally: +``` +using ::testing::DefaultValue; + +DefaultValue::Set(value); // Sets the default value to be returned. +// ... use the mocks ... +DefaultValue::Clear(); // Resets the default value. +``` + +To customize the default action for a particular method, use `ON_CALL()`: +``` +ON_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .WillByDefault(action); +``` + +# Setting Expectations # + +`EXPECT_CALL()` sets **expectations** on a mock method (How will it be +called? What will it do?): +``` +EXPECT_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .Times(cardinality) ? + .InSequence(sequences) * + .After(expectations) * + .WillOnce(action) * + .WillRepeatedly(action) ? + .RetiresOnSaturation(); ? +``` + +If `Times()` is omitted, the cardinality is assumed to be: + + * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; + * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or + * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. + +A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. + +# Matchers # + +A **matcher** matches a _single_ argument. You can use it inside +`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value +directly: + +| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | +|:------------------------------|:----------------------------------------| +| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | + +Built-in matchers (where `argument` is the function argument) are +divided into several categories: + +## Wildcard ## +|`_`|`argument` can be any value of the correct type.| +|:--|:-----------------------------------------------| +|`A()` or `An()`|`argument` can be any value of type `type`. | + +## Generic Comparison ## + +|`Eq(value)` or `value`|`argument == value`| +|:---------------------|:------------------| +|`Ge(value)` |`argument >= value`| +|`Gt(value)` |`argument > value` | +|`Le(value)` |`argument <= value`| +|`Lt(value)` |`argument < value` | +|`Ne(value)` |`argument != value`| +|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| +|`NotNull()` |`argument` is a non-null pointer (raw or smart).| +|`Ref(variable)` |`argument` is a reference to `variable`.| +|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| + +Except `Ref()`, these matchers make a _copy_ of `value` in case it's +modified or destructed later. If the compiler complains that `value` +doesn't have a public copy constructor, try wrap it in `ByRef()`, +e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure +`non_copyable_value` is not changed afterwards, or the meaning of your +matcher will be changed. + +## Floating-Point Matchers ## + +|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| +|:-------------------|:----------------------------------------------------------------------------------------------| +|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | +|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | +|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | + +The above matchers use ULP-based comparison (the same as used in +[Google Test](http://code.google.com/p/googletest/)). They +automatically pick a reasonable error bound based on the absolute +value of the expected value. `DoubleEq()` and `FloatEq()` conform to +the IEEE standard, which requires comparing two NaNs for equality to +return false. The `NanSensitive*` version instead treats two NaNs as +equal, which is often what a user wants. + +## String Matchers ## + +The `argument` can be either a C string or a C++ string object: + +|`ContainsRegex(string)`|`argument` matches the given regular expression.| +|:----------------------|:-----------------------------------------------| +|`EndsWith(suffix)` |`argument` ends with string `suffix`. | +|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | +|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| +|`StartsWith(prefix)` |`argument` starts with string `prefix`. | +|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | +|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| +|`StrEq(string)` |`argument` is equal to `string`. | +|`StrNe(string)` |`argument` is not equal to `string`. | + +`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide +strings as well. + +## Container Matchers ## + +Most STL-style containers support `==`, so you can use +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. If you want to write the elements in-line, +match them more flexibly, or get more informative messages, you can use: + +| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | +|:--------------|:-------------------------------------------------------------------------------------------| +|`ElementsAre(e0, e1, ..., en)`|`argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed.| +|`ElementsAreArray(array)` or `ElementsAreArray(array, count)`|The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array.| +| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | + +These matchers can also match: + + 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and + 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). + +where the array may be multi-dimensional (i.e. its elements can be arrays). + +## Member Matchers ## + +|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| +|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| +|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| +|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | +|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| + +## Matching the Result of a Function or Functor ## + +|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| +|:---------------|:---------------------------------------------------------------------| + +## Pointer Matchers ## + +|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| +|:-----------|:-----------------------------------------------------------------------------------------------| + +## Multiargument Matchers ## + +These are matchers on tuple types. They can be used in +`.With()`. The following can be used on functions with two
+arguments
`x` and `y`: + +|`Eq()`|`x == y`| +|:-----|:-------| +|`Ge()`|`x >= y`| +|`Gt()`|`x > y` | +|`Le()`|`x <= y`| +|`Lt()`|`x < y` | +|`Ne()`|`x != y`| + +You can use the following selectors to pick a subset of the arguments +(or reorder them) to participate in the matching: + +|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| +|:-----------|:-------------------------------------------------------------------| +|`Args(m)`|The `k` selected (using 0-based indices) arguments match `m`, e.g. `Args<1, 2>(Contains(5))`.| + +## Composite Matchers ## + +You can make a matcher from one or more other matchers: + +|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| +|:-----------------------|:---------------------------------------------------| +|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| +|`Not(m)` |`argument` doesn't match matcher `m`. | + +## Adapters for Matchers ## + +|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| +|:------------------|:--------------------------------------| +|`SafeMatcherCast(m)`| [safely casts](V1_5_CookBook#Casting_Matchers.md) matcher `m` to type `Matcher`. | +|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| + +## Matchers as Predicates ## + +|`Matches(m)`|a unary functor that returns `true` if the argument matches `m`.| +|:-----------|:---------------------------------------------------------------| +|`ExplainMatchResult(m, value, result_listener)`|returns `true` if `value` matches `m`, explaining the result to `result_listener`.| +|`Value(x, m)`|returns `true` if the value of `x` matches `m`. | + +## Defining Matchers ## + +| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | +|:-------------------------------------------------|:------------------------------------------------------| +| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | +| `MATCHER_P2(IsBetween, a, b, "is between %(a)s and %(b)s") { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | + +**Notes:** + + 1. The `MATCHER*` macros cannot be used inside a function or class. + 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). + 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. + +## Matchers as Test Assertions ## + +|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/GoogleTestPrimer#Assertions) if the value of `expression` doesn't match matcher `m`.| +|:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------| +|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | + +# Actions # + +**Actions** specify what a mock function should do when invoked. + +## Returning a Value ## + +|`Return()`|Return from a `void` mock function.| +|:---------|:----------------------------------| +|`Return(value)`|Return `value`. | +|`ReturnArg()`|Return the `N`-th (0-based) argument.| +|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| +|`ReturnNull()`|Return a null pointer. | +|`ReturnRef(variable)`|Return a reference to `variable`. | + +## Side Effects ## + +|`Assign(&variable, value)`|Assign `value` to variable.| +|:-------------------------|:--------------------------| +| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | +| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | +| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | +|`SetArgumentPointee(value)`|Assign `value` to the variable pointed by the `N`-th (0-based) argument.| +|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| +|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| +|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| + +## Using a Function or a Functor as an Action ## + +|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| +|:----------|:-----------------------------------------------------------------------------------------------------------------| +|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | +|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | +|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | +|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| + +The return value of the invoked function is used as the return value +of the action. + +When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: +``` + double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } + ... + EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); +``` + +In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, +``` + InvokeArgument<2>(5, string("Hi"), ByRef(foo)) +``` +calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. + +## Default Action ## + +|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| +|:------------|:--------------------------------------------------------------------| + +**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. + +## Composite Actions ## + +|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | +|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| +|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | +|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | +|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | +|`WithoutArgs(a)` |Perform action `a` without any arguments. | + +## Defining Actions ## + +| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | +|:--------------------------------------|:---------------------------------------------------------------------------------------| +| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | +| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | + +The `ACTION*` macros cannot be used inside a function or class. + +# Cardinalities # + +These are used in `Times()` to specify how many times a mock function will be called: + +|`AnyNumber()`|The function can be called any number of times.| +|:------------|:----------------------------------------------| +|`AtLeast(n)` |The call is expected at least `n` times. | +|`AtMost(n)` |The call is expected at most `n` times. | +|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| +|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| + +# Expectation Order # + +By default, the expectations can be matched in _any_ order. If some +or all expectations must be matched in a given order, there are two +ways to specify it. They can be used either independently or +together. + +## The After Clause ## + +``` +using ::testing::Expectation; +... +Expectation init_x = EXPECT_CALL(foo, InitX()); +Expectation init_y = EXPECT_CALL(foo, InitY()); +EXPECT_CALL(foo, Bar()) + .After(init_x, init_y); +``` +says that `Bar()` can be called only after both `InitX()` and +`InitY()` have been called. + +If you don't know how many pre-requisites an expectation has when you +write it, you can use an `ExpectationSet` to collect them: + +``` +using ::testing::ExpectationSet; +... +ExpectationSet all_inits; +for (int i = 0; i < element_count; i++) { + all_inits += EXPECT_CALL(foo, InitElement(i)); +} +EXPECT_CALL(foo, Bar()) + .After(all_inits); +``` +says that `Bar()` can be called only after all elements have been +initialized (but we don't care about which elements get initialized +before the others). + +Modifying an `ExpectationSet` after using it in an `.After()` doesn't +affect the meaning of the `.After()`. + +## Sequences ## + +When you have a long chain of sequential expectations, it's easier to +specify the order using **sequences**, which don't require you to given +each expectation in the chain a different name. All expected
+calls
in the same sequence must occur in the order they are +specified. + +``` +using ::testing::Sequence; +Sequence s1, s2; +... +EXPECT_CALL(foo, Reset()) + .InSequence(s1, s2) + .WillOnce(Return(true)); +EXPECT_CALL(foo, GetSize()) + .InSequence(s1) + .WillOnce(Return(1)); +EXPECT_CALL(foo, Describe(A())) + .InSequence(s2) + .WillOnce(Return("dummy")); +``` +says that `Reset()` must be called before _both_ `GetSize()` _and_ +`Describe()`, and the latter two can occur in any order. + +To put many expectations in a sequence conveniently: +``` +using ::testing::InSequence; +{ + InSequence dummy; + + EXPECT_CALL(...)...; + EXPECT_CALL(...)...; + ... + EXPECT_CALL(...)...; +} +``` +says that all expected calls in the scope of `dummy` must occur in +strict order. The name `dummy` is irrelevant.) + +# Verifying and Resetting a Mock # + +Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: +``` +using ::testing::Mock; +... +// Verifies and removes the expectations on mock_obj; +// returns true iff successful. +Mock::VerifyAndClearExpectations(&mock_obj); +... +// Verifies and removes the expectations on mock_obj; +// also removes the default actions set by ON_CALL(); +// returns true iff successful. +Mock::VerifyAndClear(&mock_obj); +``` + +You can also tell Google Mock that a mock object can be leaked and doesn't +need to be verified: +``` +Mock::AllowLeak(&mock_obj); +``` + +# Mock Classes # + +Google Mock defines a convenient mock class template +``` +class MockFunction { + public: + MOCK_METHODn(Call, R(A1, ..., An)); +}; +``` +See this [recipe](V1_5_CookBook#Using_Check_Points.md) for one application of it. + +# Flags # + +| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | +|:-------------------------------|:----------------------------------------------| +| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | \ No newline at end of file diff --git a/googlemock/docs/v1_5/CookBook.md b/googlemock/docs/v1_5/CookBook.md new file mode 100644 index 0000000..26e153c --- /dev/null +++ b/googlemock/docs/v1_5/CookBook.md @@ -0,0 +1,3250 @@ + + +You can find recipes for using Google Mock here. If you haven't yet, +please read the [ForDummies](V1_5_ForDummies.md) document first to make sure you understand +the basics. + +**Note:** Google Mock lives in the `testing` name space. For +readability, it is recommended to write `using ::testing::Foo;` once in +your file before using the name `Foo` defined by Google Mock. We omit +such `using` statements in this page for brevity, but you should do it +in your own code. + +# Creating Mock Classes # + +## Mocking Private or Protected Methods ## + +You must always put a mock method definition (`MOCK_METHOD*`) in a +`public:` section of the mock class, regardless of the method being +mocked being `public`, `protected`, or `private` in the base class. +This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function +from outside of the mock class. (Yes, C++ allows a subclass to change +the access level of a virtual function in the base class.) Example: + +``` +class Foo { + public: + ... + virtual bool Transform(Gadget* g) = 0; + + protected: + virtual void Resume(); + + private: + virtual int GetTimeOut(); +}; + +class MockFoo : public Foo { + public: + ... + MOCK_METHOD1(Transform, bool(Gadget* g)); + + // The following must be in the public section, even though the + // methods are protected or private in the base class. + MOCK_METHOD0(Resume, void()); + MOCK_METHOD0(GetTimeOut, int()); +}; +``` + +## Mocking Overloaded Methods ## + +You can mock overloaded functions as usual. No special attention is required: + +``` +class Foo { + ... + + // Must be virtual as we'll inherit from Foo. + virtual ~Foo(); + + // Overloaded on the types and/or numbers of arguments. + virtual int Add(Element x); + virtual int Add(int times, Element x); + + // Overloaded on the const-ness of this object. + virtual Bar& GetBar(); + virtual const Bar& GetBar() const; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Add, int(Element x)); + MOCK_METHOD2(Add, int(int times, Element x); + + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +``` + +**Note:** if you don't mock all versions of the overloaded method, the +compiler will give you a warning about some methods in the base class +being hidden. To fix that, use `using` to bring them in scope: + +``` +class MockFoo : public Foo { + ... + using Foo::Add; + MOCK_METHOD1(Add, int(Element x)); + // We don't want to mock int Add(int times, Element x); + ... +}; +``` + +## Mocking Class Templates ## + +To mock a class template, append `_T` to the `MOCK_*` macros: + +``` +template +class StackInterface { + ... + // Must be virtual as we'll inherit from StackInterface. + virtual ~StackInterface(); + + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; + +template +class MockStack : public StackInterface { + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Mocking Nonvirtual Methods ## + +Google Mock can mock non-virtual functions to be used in what we call _hi-perf +dependency injection_. + +In this case, instead of sharing a common base class with the real +class, your mock class will be _unrelated_ to the real class, but +contain methods with the same signatures. The syntax for mocking +non-virtual methods is the _same_ as mocking virtual methods: + +``` +// A simple packet stream class. None of its members is virtual. +class ConcretePacketStream { + public: + void AppendPacket(Packet* new_packet); + const Packet* GetPacket(size_t packet_number) const; + size_t NumberOfPackets() const; + ... +}; + +// A mock packet stream class. It inherits from no other, but defines +// GetPacket() and NumberOfPackets(). +class MockPacketStream { + public: + MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); + MOCK_CONST_METHOD0(NumberOfPackets, size_t()); + ... +}; +``` + +Note that the mock class doesn't define `AppendPacket()`, unlike the +real class. That's fine as long as the test doesn't need to call it. + +Next, you need a way to say that you want to use +`ConcretePacketStream` in production code, and use `MockPacketStream` +in tests. Since the functions are not virtual and the two classes are +unrelated, you must specify your choice at _compile time_ (as opposed +to run time). + +One way to do it is to templatize your code that needs to use a packet +stream. More specifically, you will give your code a template type +argument for the type of the packet stream. In production, you will +instantiate your template with `ConcretePacketStream` as the type +argument. In tests, you will instantiate the same template with +`MockPacketStream`. For example, you may write: + +``` +template +void CreateConnection(PacketStream* stream) { ... } + +template +class PacketReader { + public: + void ReadPackets(PacketStream* stream, size_t packet_num); +}; +``` + +Then you can use `CreateConnection()` and +`PacketReader` in production code, and use +`CreateConnection()` and +`PacketReader` in tests. + +``` + MockPacketStream mock_stream; + EXPECT_CALL(mock_stream, ...)...; + .. set more expectations on mock_stream ... + PacketReader reader(&mock_stream); + ... exercise reader ... +``` + +## Mocking Free Functions ## + +It's possible to use Google Mock to mock a free function (i.e. a +C-style function or a static method). You just need to rewrite your +code to use an interface (abstract class). + +Instead of calling a free function (say, `OpenFile`) directly, +introduce an interface for it and have a concrete subclass that calls +the free function: + +``` +class FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) = 0; +}; + +class File : public FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) { + return OpenFile(path, mode); + } +}; +``` + +Your code should talk to `FileInterface` to open a file. Now it's +easy to mock out the function. + +This may seem much hassle, but in practice you often have multiple +related functions that you can put in the same interface, so the +per-function syntactic overhead will be much lower. + +If you are concerned about the performance overhead incurred by +virtual functions, and profiling confirms your concern, you can +combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). + +## Nice Mocks and Strict Mocks ## + +If a mock method has no `EXPECT_CALL` spec but is called, Google Mock +will print a warning about the "uninteresting call". The rationale is: + + * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. + * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. + +However, sometimes you may want to suppress all "uninteresting call" +warnings, while sometimes you may want the opposite, i.e. to treat all +of them as errors. Google Mock lets you make the decision on a +per-mock-object basis. + +Suppose your test uses a mock class `MockFoo`: + +``` +TEST(...) { + MockFoo mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +If a method of `mock_foo` other than `DoThis()` is called, it will be +reported by Google Mock as a warning. However, if you rewrite your +test to use `NiceMock` instead, the warning will be gone, +resulting in a cleaner test output: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +`NiceMock` is a subclass of `MockFoo`, so it can be used +wherever `MockFoo` is accepted. + +It also works if `MockFoo`'s constructor takes some arguments, as +`NiceMock` "inherits" `MockFoo`'s constructors: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +The usage of `StrictMock` is similar, except that it makes all +uninteresting calls failures: + +``` +using ::testing::StrictMock; + +TEST(...) { + StrictMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... + + // The test will fail if a method of mock_foo other than DoThis() + // is called. +} +``` + +There are some caveats though (I don't like them just as much as the +next guy, but sadly they are side effects of C++'s limitations): + + 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. + 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). + 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) + +Finally, you should be **very cautious** when using this feature, as the +decision you make applies to **all** future changes to the mock +class. If an important change is made in the interface you are mocking +(and thus in the mock class), it could break your tests (if you use +`StrictMock`) or let bugs pass through without a warning (if you use +`NiceMock`). Therefore, try to specify the mock's behavior using +explicit `EXPECT_CALL` first, and only turn to `NiceMock` or +`StrictMock` as the last resort. + +## Simplifying the Interface without Breaking Existing Code ## + +Sometimes a method has a long list of arguments that is mostly +uninteresting. For example, + +``` +class LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const struct tm* tm_time, + const char* message, size_t message_len) = 0; +}; +``` + +This method's argument list is lengthy and hard to work with (let's +say that the `message` argument is not even 0-terminated). If we mock +it as is, using the mock will be awkward. If, however, we try to +simplify this interface, we'll need to fix all clients depending on +it, which is often infeasible. + +The trick is to re-dispatch the method in the mock class: + +``` +class ScopedMockLog : public LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, const tm* tm_time, + const char* message, size_t message_len) { + // We are only interested in the log severity, full file name, and + // log message. + Log(severity, full_filename, std::string(message, message_len)); + } + + // Implements the mock method: + // + // void Log(LogSeverity severity, + // const string& file_path, + // const string& message); + MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, + const string& message)); +}; +``` + +By defining a new mock method with a trimmed argument list, we make +the mock class much more user-friendly. + +## Alternative to Mocking Concrete Classes ## + +Often you may find yourself using classes that don't implement +interfaces. In order to test your code that uses such a class (let's +call it `Concrete`), you may be tempted to make the methods of +`Concrete` virtual and then mock it. + +Try not to do that. + +Making a non-virtual function virtual is a big decision. It creates an +extension point where subclasses can tweak your class' behavior. This +weakens your control on the class because now it's harder to maintain +the class' invariants. You should make a function virtual only when +there is a valid reason for a subclass to override it. + +Mocking concrete classes directly is problematic as it creates a tight +coupling between the class and the tests - any small change in the +class may invalidate your tests and make test maintenance a pain. + +To avoid such problems, many programmers have been practicing "coding +to interfaces": instead of talking to the `Concrete` class, your code +would define an interface and talk to it. Then you implement that +interface as an adaptor on top of `Concrete`. In tests, you can easily +mock that interface to observe how your code is doing. + +This technique incurs some overhead: + + * You pay the cost of virtual function calls (usually not a problem). + * There is more abstraction for the programmers to learn. + +However, it can also bring significant benefits in addition to better +testability: + + * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. + * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. + +Some people worry that if everyone is practicing this technique, they +will end up writing lots of redundant code. This concern is totally +understandable. However, there are two reasons why it may not be the +case: + + * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. + * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. + +You need to weigh the pros and cons carefully for your particular +problem, but I'd like to assure you that the Java community has been +practicing this for a long time and it's a proven effective technique +applicable in a wide variety of situations. :-) + +## Delegating Calls to a Fake ## + +Some times you have a non-trivial fake implementation of an +interface. For example: + +``` +class Foo { + public: + virtual ~Foo() {} + virtual char DoThis(int n) = 0; + virtual void DoThat(const char* s, int* p) = 0; +}; + +class FakeFoo : public Foo { + public: + virtual char DoThis(int n) { + return (n > 0) ? '+' : + (n < 0) ? '-' : '0'; + } + + virtual void DoThat(const char* s, int* p) { + *p = strlen(s); + } +}; +``` + +Now you want to mock this interface such that you can set expectations +on it. However, you also want to use `FakeFoo` for the default +behavior, as duplicating it in the mock object is, well, a lot of +work. + +When you define the mock class using Google Mock, you can have it +delegate its default action to a fake class you already have, using +this pattern: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + // Normal mock method definitions using Google Mock. + MOCK_METHOD1(DoThis, char(int n)); + MOCK_METHOD2(DoThat, void(const char* s, int* p)); + + // Delegates the default actions of the methods to a FakeFoo object. + // This must be called *before* the custom ON_CALL() statements. + void DelegateToFake() { + ON_CALL(*this, DoThis(_)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); + ON_CALL(*this, DoThat(_, _)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); + } + private: + FakeFoo fake_; // Keeps an instance of the fake in the mock. +}; +``` + +With that, you can use `MockFoo` in your tests as usual. Just remember +that if you don't explicitly set an action in an `ON_CALL()` or +`EXPECT_CALL()`, the fake will be called upon to do it: + +``` +using ::testing::_; + +TEST(AbcTest, Xyz) { + MockFoo foo; + foo.DelegateToFake(); // Enables the fake for delegation. + + // Put your ON_CALL(foo, ...)s here, if any. + + // No action specified, meaning to use the default action. + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(foo, DoThat(_, _)); + + int n = 0; + EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. + foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. + EXPECT_EQ(2, n); +} +``` + +**Some tips:** + + * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. + * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. + * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. + * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. + +Regarding the tip on mixing a mock and a fake, here's an example on +why it may be a bad sign: Suppose you have a class `System` for +low-level system operations. In particular, it does file and I/O +operations. And suppose you want to test how your code uses `System` +to do I/O, and you just want the file operations to work normally. If +you mock out the entire `System` class, you'll have to provide a fake +implementation for the file operation part, which suggests that +`System` is taking on too many roles. + +Instead, you can define a `FileOps` interface and an `IOOps` interface +and split `System`'s functionalities into the two. Then you can mock +`IOOps` without mocking `FileOps`. + +## Delegating Calls to a Real Object ## + +When using testing doubles (mocks, fakes, stubs, and etc), sometimes +their behaviors will differ from those of the real objects. This +difference could be either intentional (as in simulating an error such +that you can test the error handling code) or unintentional. If your +mocks have different behaviors than the real objects by mistake, you +could end up with code that passes the tests but fails in production. + +You can use the _delegating-to-real_ technique to ensure that your +mock has the same behavior as the real object while retaining the +ability to validate calls. This technique is very similar to the +delegating-to-fake technique, the difference being that we use a real +object instead of a fake. Here's an example: + +``` +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MockFoo() { + // By default, all calls are delegated to the real object. + ON_CALL(*this, DoThis()) + .WillByDefault(Invoke(&real_, &Foo::DoThis)); + ON_CALL(*this, DoThat(_)) + .WillByDefault(Invoke(&real_, &Foo::DoThat)); + ... + } + MOCK_METHOD0(DoThis, ...); + MOCK_METHOD1(DoThat, ...); + ... + private: + Foo real_; +}; +... + + MockFoo mock; + + EXPECT_CALL(mock, DoThis()) + .Times(3); + EXPECT_CALL(mock, DoThat("Hi")) + .Times(AtLeast(1)); + ... use mock in test ... +``` + +With this, Google Mock will verify that your code made the right calls +(with the right arguments, in the right order, called the right number +of times, etc), and a real object will answer the calls (so the +behavior will be the same as in production). This gives you the best +of both worlds. + +## Delegating Calls to a Parent Class ## + +Ideally, you should code to interfaces, whose methods are all pure +virtual. In reality, sometimes you do need to mock a virtual method +that is not pure (i.e, it already has an implementation). For example: + +``` +class Foo { + public: + virtual ~Foo(); + + virtual void Pure(int n) = 0; + virtual int Concrete(const char* str) { ... } +}; + +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); +}; +``` + +Sometimes you may want to call `Foo::Concrete()` instead of +`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub +action, or perhaps your test doesn't need to mock `Concrete()` at all +(but it would be oh-so painful to have to define a new mock class +whenever you don't need to mock one of its methods). + +The trick is to leave a back door in your mock class for accessing the +real methods in the base class: + +``` +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); + + // Use this to call Concrete() defined in Foo. + int FooConcrete(const char* str) { return Foo::Concrete(str); } +}; +``` + +Now, you can call `Foo::Concrete()` inside an action by: + +``` +using ::testing::_; +using ::testing::Invoke; +... + EXPECT_CALL(foo, Concrete(_)) + .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +or tell the mock object that you don't want to mock `Concrete()`: + +``` +using ::testing::Invoke; +... + ON_CALL(foo, Concrete(_)) + .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do +that, `MockFoo::Concrete()` will be called (and cause an infinite +recursion) since `Foo::Concrete()` is virtual. That's just how C++ +works.) + +# Using Matchers # + +## Matching Argument Values Exactly ## + +You can specify exactly which arguments a mock method is expecting: + +``` +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(5)) + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", bar)); +``` + +## Using Simple Matchers ## + +You can use matchers to match arguments that have a certain property: + +``` +using ::testing::Ge; +using ::testing::NotNull; +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", NotNull())); + // The second argument must not be NULL. +``` + +A frequently used matcher is `_`, which matches anything: + +``` +using ::testing::_; +using ::testing::NotNull; +... + EXPECT_CALL(foo, DoThat(_, NotNull())); +``` + +## Combining Matchers ## + +You can build complex matchers from existing ones using `AllOf()`, +`AnyOf()`, and `Not()`: + +``` +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::HasSubstr; +using ::testing::Ne; +using ::testing::Not; +... + // The argument must be > 5 and != 10. + EXPECT_CALL(foo, DoThis(AllOf(Gt(5), + Ne(10)))); + + // The first argument must not contain sub-string "blah". + EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), + NULL)); +``` + +## Casting Matchers ## + +Google Mock matchers are statically typed, meaning that the compiler +can catch your mistake if you use a matcher of the wrong type (for +example, if you use `Eq(5)` to match a `string` argument). Good for +you! + +Sometimes, however, you know what you're doing and want the compiler +to give you some slack. One example is that you have a matcher for +`long` and the argument you want to match is `int`. While the two +types aren't exactly the same, there is nothing really wrong with +using a `Matcher` to match an `int` - after all, we can first +convert the `int` argument to a `long` before giving it to the +matcher. + +To support this need, Google Mock gives you the +`SafeMatcherCast(m)` function. It casts a matcher `m` to type +`Matcher`. To ensure safety, Google Mock checks that (let `U` be the +type `m` accepts): + + 1. Type `T` can be implicitly cast to type `U`; + 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and + 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). + +The code won't compile if any of these conditions isn't met. + +Here's one example: + +``` +using ::testing::SafeMatcherCast; + +// A base class and a child class. +class Base { ... }; +class Derived : public Base { ... }; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(DoThis, void(Derived* derived)); +}; +... + + MockFoo foo; + // m is a Matcher we got from somewhere. + EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); +``` + +If you find `SafeMatcherCast(m)` too limiting, you can use a similar +function `MatcherCast(m)`. The difference is that `MatcherCast` works +as long as you can `static_cast` type `T` to type `U`. + +`MatcherCast` essentially lets you bypass C++'s type system +(`static_cast` isn't always safe as it could throw away information, +for example), so be careful not to misuse/abuse it. + +## Selecting Between Overloaded Functions ## + +If you expect an overloaded function to be called, the compiler may +need some help on which overloaded version it is. + +To disambiguate functions overloaded on the const-ness of this object, +use the `Const()` argument wrapper. + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + ... + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +... + + MockFoo foo; + Bar bar1, bar2; + EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). + .WillOnce(ReturnRef(bar1)); + EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). + .WillOnce(ReturnRef(bar2)); +``` + +(`Const()` is defined by Google Mock and returns a `const` reference +to its argument.) + +To disambiguate overloaded functions with the same number of arguments +but different argument types, you may need to specify the exact type +of a matcher, either by wrapping your matcher in `Matcher()`, or +using a matcher whose type is fixed (`TypedEq`, `An()`, +etc): + +``` +using ::testing::An; +using ::testing::Lt; +using ::testing::Matcher; +using ::testing::TypedEq; + +class MockPrinter : public Printer { + public: + MOCK_METHOD1(Print, void(int n)); + MOCK_METHOD1(Print, void(char c)); +}; + +TEST(PrinterTest, Print) { + MockPrinter printer; + + EXPECT_CALL(printer, Print(An())); // void Print(int); + EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); + EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); + + printer.Print(3); + printer.Print(6); + printer.Print('a'); +} +``` + +## Performing Different Actions Based on the Arguments ## + +When a mock method is called, the _last_ matching expectation that's +still active will be selected (think "newer overrides older"). So, you +can make a method do different things depending on its argument values +like this: + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Return; +... + // The default case. + EXPECT_CALL(foo, DoThis(_)) + .WillRepeatedly(Return('b')); + + // The more specific case. + EXPECT_CALL(foo, DoThis(Lt(5))) + .WillRepeatedly(Return('a')); +``` + +Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will +be returned; otherwise `'b'` will be returned. + +## Matching Multiple Arguments as a Whole ## + +Sometimes it's not enough to match the arguments individually. For +example, we may want to say that the first argument must be less than +the second argument. The `With()` clause allows us to match +all arguments of a mock function as a whole. For example, + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Ne; +... + EXPECT_CALL(foo, InRange(Ne(0), _)) + .With(Lt()); +``` + +says that the first argument of `InRange()` must not be 0, and must be +less than the second argument. + +The expression inside `With()` must be a matcher of type +`Matcher >`, where `A1`, ..., `An` are the +types of the function arguments. + +You can also write `AllArgs(m)` instead of `m` inside `.With()`. The +two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable +than `.With(Lt())`. + +You can use `Args(m)` to match the `n` selected arguments +against `m`. For example, + +``` +using ::testing::_; +using ::testing::AllOf; +using ::testing::Args; +using ::testing::Lt; +... + EXPECT_CALL(foo, Blah(_, _, _)) + .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); +``` + +says that `Blah()` will be called with arguments `x`, `y`, and `z` where +`x < y < z`. + +As a convenience and example, Google Mock provides some matchers for +2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_5_CheatSheet.md) for +the complete list. + +## Using Matchers as Predicates ## + +Have you noticed that a matcher is just a fancy predicate that also +knows how to describe itself? Many existing algorithms take predicates +as arguments (e.g. those defined in STL's `` header), and +it would be a shame if Google Mock matchers are not allowed to +participate. + +Luckily, you can use a matcher where a unary predicate functor is +expected by wrapping it inside the `Matches()` function. For example, + +``` +#include +#include + +std::vector v; +... +// How many elements in v are >= 10? +const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); +``` + +Since you can build complex matchers from simpler ones easily using +Google Mock, this gives you a way to conveniently construct composite +predicates (doing the same using STL's `` header is just +painful). For example, here's a predicate that's satisfied by any +number that is >= 0, <= 100, and != 50: + +``` +Matches(AllOf(Ge(0), Le(100), Ne(50))) +``` + +## Using Matchers in Google Test Assertions ## + +Since matchers are basically predicates that also know how to describe +themselves, there is a way to take advantage of them in +[Google Test](http://code.google.com/p/googletest/) assertions. It's +called `ASSERT_THAT` and `EXPECT_THAT`: + +``` + ASSERT_THAT(value, matcher); // Asserts that value matches matcher. + EXPECT_THAT(value, matcher); // The non-fatal version. +``` + +For example, in a Google Test test you can write: + +``` +#include + +using ::testing::AllOf; +using ::testing::Ge; +using ::testing::Le; +using ::testing::MatchesRegex; +using ::testing::StartsWith; +... + + EXPECT_THAT(Foo(), StartsWith("Hello")); + EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); + ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); +``` + +which (as you can probably guess) executes `Foo()`, `Bar()`, and +`Baz()`, and verifies that: + + * `Foo()` returns a string that starts with `"Hello"`. + * `Bar()` returns a string that matches regular expression `"Line \\d+"`. + * `Baz()` returns a number in the range [5, 10]. + +The nice thing about these macros is that _they read like +English_. They generate informative messages too. For example, if the +first `EXPECT_THAT()` above fails, the message will be something like: + +``` +Value of: Foo() + Actual: "Hi, world!" +Expected: starts with "Hello" +``` + +**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the +[Hamcrest](http://code.google.com/p/hamcrest/) project, which adds +`assertThat()` to JUnit. + +## Using Predicates as Matchers ## + +Google Mock provides a built-in set of matchers. In case you find them +lacking, you can use an arbitray unary predicate function or functor +as a matcher - as long as the predicate accepts a value of the type +you want. You do this by wrapping the predicate inside the `Truly()` +function, for example: + +``` +using ::testing::Truly; + +int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } +... + + // Bar() must be called with an even number. + EXPECT_CALL(foo, Bar(Truly(IsEven))); +``` + +Note that the predicate function / functor doesn't have to return +`bool`. It works as long as the return value can be used as the +condition in statement `if (condition) ...`. + +## Matching Arguments that Are Not Copyable ## + +When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves +away a copy of `bar`. When `Foo()` is called later, Google Mock +compares the argument to `Foo()` with the saved copy of `bar`. This +way, you don't need to worry about `bar` being modified or destroyed +after the `EXPECT_CALL()` is executed. The same is true when you use +matchers like `Eq(bar)`, `Le(bar)`, and so on. + +But what if `bar` cannot be copied (i.e. has no copy constructor)? You +could define your own matcher function and use it with `Truly()`, as +the previous couple of recipes have shown. Or, you may be able to get +away from it if you can guarantee that `bar` won't be changed after +the `EXPECT_CALL()` is executed. Just tell Google Mock that it should +save a reference to `bar`, instead of a copy of it. Here's how: + +``` +using ::testing::Eq; +using ::testing::ByRef; +using ::testing::Lt; +... + // Expects that Foo()'s argument == bar. + EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); + + // Expects that Foo()'s argument < bar. + EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); +``` + +Remember: if you do this, don't change `bar` after the +`EXPECT_CALL()`, or the result is undefined. + +## Validating a Member of an Object ## + +Often a mock function takes a reference to object as an argument. When +matching the argument, you may not want to compare the entire object +against a fixed object, as that may be over-specification. Instead, +you may need to validate a certain member variable or the result of a +certain getter method of the object. You can do this with `Field()` +and `Property()`. More specifically, + +``` +Field(&Foo::bar, m) +``` + +is a matcher that matches a `Foo` object whose `bar` member variable +satisfies matcher `m`. + +``` +Property(&Foo::baz, m) +``` + +is a matcher that matches a `Foo` object whose `baz()` method returns +a value that satisfies matcher `m`. + +For example: + +> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | +|:-----------------------------|:-----------------------------------| +> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | + +Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no +argument and be declared as `const`. + +BTW, `Field()` and `Property()` can also match plain pointers to +objects. For instance, + +``` +Field(&Foo::number, Ge(3)) +``` + +matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, +the match will always fail regardless of the inner matcher. + +What if you want to validate more than one members at the same time? +Remember that there is `AllOf()`. + +## Validating the Value Pointed to by a Pointer Argument ## + +C++ functions often take pointers as arguments. You can use matchers +like `NULL`, `NotNull()`, and other comparison matchers to match a +pointer, but what if you want to make sure the value _pointed to_ by +the pointer, instead of the pointer itself, has a certain property? +Well, you can use the `Pointee(m)` matcher. + +`Pointee(m)` matches a pointer iff `m` matches the value the pointer +points to. For example: + +``` +using ::testing::Ge; +using ::testing::Pointee; +... + EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); +``` + +expects `foo.Bar()` to be called with a pointer that points to a value +greater than or equal to 3. + +One nice thing about `Pointee()` is that it treats a `NULL` pointer as +a match failure, so you can write `Pointee(m)` instead of + +``` + AllOf(NotNull(), Pointee(m)) +``` + +without worrying that a `NULL` pointer will crash your test. + +Also, did we tell you that `Pointee()` works with both raw pointers +**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and +etc)? + +What if you have a pointer to pointer? You guessed it - you can use +nested `Pointee()` to probe deeper inside the value. For example, +`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer +that points to a number less than 3 (what a mouthful...). + +## Testing a Certain Property of an Object ## + +Sometimes you want to specify that an object argument has a certain +property, but there is no existing matcher that does this. If you want +good error messages, you should define a matcher. If you want to do it +quick and dirty, you could get away with writing an ordinary function. + +Let's say you have a mock function that takes an object of type `Foo`, +which has an `int bar()` method and an `int baz()` method, and you +want to constrain that the argument's `bar()` value plus its `baz()` +value is a given number. Here's how you can define a matcher to do it: + +``` +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class BarPlusBazEqMatcher : public MatcherInterface { + public: + explicit BarPlusBazEqMatcher(int expected_sum) + : expected_sum_(expected_sum) {} + + virtual bool MatchAndExplain(const Foo& foo, + MatchResultListener* listener) const { + return (foo.bar() + foo.baz()) == expected_sum_; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "bar() + baz() equals " << expected_sum_; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "bar() + baz() does not equal " << expected_sum_; + } + private: + const int expected_sum_; +}; + +inline Matcher BarPlusBazEq(int expected_sum) { + return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); +} + +... + + EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; +``` + +## Matching Containers ## + +Sometimes an STL container (e.g. list, vector, map, ...) is passed to +a mock function and you may want to validate it. Since most STL +containers support the `==` operator, you can write +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. + +Sometimes, though, you may want to be more flexible (for example, the +first element must be an exact match, but the second element can be +any positive number, and so on). Also, containers used in tests often +have a small number of elements, and having to define the expected +container out-of-line is a bit of a hassle. + +You can use the `ElementsAre()` matcher in such cases: + +``` +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Gt; +... + + MOCK_METHOD1(Foo, void(const vector& numbers)); +... + + EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); +``` + +The above matcher says that the container must have 4 elements, which +must be 1, greater than 0, anything, and 5 respectively. + +`ElementsAre()` is overloaded to take 0 to 10 arguments. If more are +needed, you can place them in a C-style array and use +`ElementsAreArray()` instead: + +``` +using ::testing::ElementsAreArray; +... + + // ElementsAreArray accepts an array of element values. + const int expected_vector1[] = { 1, 5, 2, 4, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); + + // Or, an array of element matchers. + Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); +``` + +In case the array needs to be dynamically created (and therefore the +array size cannot be inferred by the compiler), you can give +`ElementsAreArray()` an additional argument to specify the array size: + +``` +using ::testing::ElementsAreArray; +... + int* const expected_vector3 = new int[count]; + ... fill expected_vector3 with values ... + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); +``` + +**Tips:** + + * `ElementAre*()` works with _any_ container that implements the STL iterator concept (i.e. it has a `const_iterator` type and supports `begin()/end()`) and supports `size()`, not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. + * You can use nested `ElementAre*()` to match nested (multi-dimensional) containers. + * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. + * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). + +## Sharing Matchers ## + +Under the hood, a Google Mock matcher object consists of a pointer to +a ref-counted implementation object. Copying matchers is allowed and +very efficient, as only the pointer is copied. When the last matcher +that references the implementation object dies, the implementation +object will be deleted. + +Therefore, if you have some complex matcher that you want to use again +and again, there is no need to build it everytime. Just assign it to a +matcher variable and use that variable repeatedly! For example, + +``` + Matcher in_range = AllOf(Gt(5), Le(10)); + ... use in_range as a matcher in multiple EXPECT_CALLs ... +``` + +# Setting Expectations # + +## Ignoring Uninteresting Calls ## + +If you are not interested in how a mock method is called, just don't +say anything about it. In this case, if the method is ever called, +Google Mock will perform its default action to allow the test program +to continue. If you are not happy with the default action taken by +Google Mock, you can override it using `DefaultValue::Set()` +(described later in this document) or `ON_CALL()`. + +Please note that once you expressed interest in a particular mock +method (via `EXPECT_CALL()`), all invocations to it must match some +expectation. If this function is called but the arguments don't match +any `EXPECT_CALL()` statement, it will be an error. + +## Disallowing Unexpected Calls ## + +If a mock method shouldn't be called at all, explicitly say so: + +``` +using ::testing::_; +... + EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +If some calls to the method are allowed, but the rest are not, just +list all the expected calls: + +``` +using ::testing::AnyNumber; +using ::testing::Gt; +... + EXPECT_CALL(foo, Bar(5)); + EXPECT_CALL(foo, Bar(Gt(10))) + .Times(AnyNumber()); +``` + +A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` +statements will be an error. + +## Expecting Ordered Calls ## + +Although an `EXPECT_CALL()` statement defined earlier takes precedence +when Google Mock tries to match a function call with an expectation, +by default calls don't have to happen in the order `EXPECT_CALL()` +statements are written. For example, if the arguments match the +matchers in the third `EXPECT_CALL()`, but not those in the first two, +then the third expectation will be used. + +If you would rather have all calls occur in the order of the +expectations, put the `EXPECT_CALL()` statements in a block where you +define a variable of type `InSequence`: + +``` + using ::testing::_; + using ::testing::InSequence; + + { + InSequence s; + + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(bar, DoThat(_)) + .Times(2); + EXPECT_CALL(foo, DoThis(6)); + } +``` + +In this example, we expect a call to `foo.DoThis(5)`, followed by two +calls to `bar.DoThat()` where the argument can be anything, which are +in turn followed by a call to `foo.DoThis(6)`. If a call occurred +out-of-order, Google Mock will report an error. + +## Expecting Partially Ordered Calls ## + +Sometimes requiring everything to occur in a predetermined order can +lead to brittle tests. For example, we may care about `A` occurring +before both `B` and `C`, but aren't interested in the relative order +of `B` and `C`. In this case, the test should reflect our real intent, +instead of being overly constraining. + +Google Mock allows you to impose an arbitrary DAG (directed acyclic +graph) on the calls. One way to express the DAG is to use the +[After](V1_5_CheatSheet#The_After_Clause.md) clause of `EXPECT_CALL`. + +Another way is via the `InSequence()` clause (not the same as the +`InSequence` class), which we borrowed from jMock 2. It's less +flexible than `After()`, but more convenient when you have long chains +of sequential calls, as it doesn't require you to come up with +different names for the expectations in the chains. Here's how it +works: + +If we view `EXPECT_CALL()` statements as nodes in a graph, and add an +edge from node A to node B wherever A must occur before B, we can get +a DAG. We use the term "sequence" to mean a directed path in this +DAG. Now, if we decompose the DAG into sequences, we just need to know +which sequences each `EXPECT_CALL()` belongs to in order to be able to +reconstruct the orginal DAG. + +So, to specify the partial order on the expectations we need to do two +things: first to define some `Sequence` objects, and then for each +`EXPECT_CALL()` say which `Sequence` objects it is part +of. Expectations in the same sequence must occur in the order they are +written. For example, + +``` + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(foo, A()) + .InSequence(s1, s2); + EXPECT_CALL(bar, B()) + .InSequence(s1); + EXPECT_CALL(bar, C()) + .InSequence(s2); + EXPECT_CALL(foo, D()) + .InSequence(s2); +``` + +specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> +C -> D`): + +``` + +---> B + | + A ---| + | + +---> C ---> D +``` + +This means that A must occur before B and C, and C must occur before +D. There's no restriction about the order other than these. + +## Controlling When an Expectation Retires ## + +When a mock method is called, Google Mock only consider expectations +that are still active. An expectation is active when created, and +becomes inactive (aka _retires_) when a call that has to occur later +has occurred. For example, in + +``` + using ::testing::_; + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 + .Times(AnyNumber()) + .InSequence(s1, s2); + EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 + .InSequence(s1); + EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 + .InSequence(s2); +``` + +as soon as either #2 or #3 is matched, #1 will retire. If a warning +`"File too large."` is logged after this, it will be an error. + +Note that an expectation doesn't retire automatically when it's +saturated. For example, + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 +``` + +says that there will be exactly one warning with the message `"File +too large."`. If the second warning contains this message too, #2 will +match again and result in an upper-bound-violated error. + +If this is not what you want, you can ask an expectation to retire as +soon as it becomes saturated: + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 + .RetiresOnSaturation(); +``` + +Here #2 can be used only once, so if you have two warnings with the +message `"File too large."`, the first will match #2 and the second +will match #1 - there will be no error. + +# Using Actions # + +## Returning References from Mock Methods ## + +If a mock function's return type is a reference, you need to use +`ReturnRef()` instead of `Return()` to return a result: + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetBar, Bar&()); +}; +... + + MockFoo foo; + Bar bar; + EXPECT_CALL(foo, GetBar()) + .WillOnce(ReturnRef(bar)); +``` + +## Combining Actions ## + +Want to do more than one thing when a function is called? That's +fine. `DoAll()` allow you to do sequence of actions every time. Only +the return value of the last action in the sequence will be used. + +``` +using ::testing::DoAll; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Bar, bool(int n)); +}; +... + + EXPECT_CALL(foo, Bar(_)) + .WillOnce(DoAll(action_1, + action_2, + ... + action_n)); +``` + +## Mocking Side Effects ## + +Sometimes a method exhibits its effect not via returning a value but +via side effects. For example, it may change some global state or +modify an output argument. To mock side effects, in general you can +define your own action by implementing `::testing::ActionInterface`. + +If all you need to do is to change an output argument, the built-in +`SetArgumentPointee()` action is convenient: + +``` +using ::testing::SetArgumentPointee; + +class MockMutator : public Mutator { + public: + MOCK_METHOD2(Mutate, void(bool mutate, int* value)); + ... +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, Mutate(true, _)) + .WillOnce(SetArgumentPointee<1>(5)); +``` + +In this example, when `mutator.Mutate()` is called, we will assign 5 +to the `int` variable pointed to by argument #1 +(0-based). + +`SetArgumentPointee()` conveniently makes an internal copy of the +value you pass to it, removing the need to keep the value in scope and +alive. The implication however is that the value must have a copy +constructor and assignment operator. + +If the mock method also needs to return a value as well, you can chain +`SetArgumentPointee()` with `Return()` using `DoAll()`: + +``` +using ::testing::_; +using ::testing::Return; +using ::testing::SetArgumentPointee; + +class MockMutator : public Mutator { + public: + ... + MOCK_METHOD1(MutateInt, bool(int* value)); +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, MutateInt(_)) + .WillOnce(DoAll(SetArgumentPointee<0>(5), + Return(true))); +``` + +If the output argument is an array, use the +`SetArrayArgument(first, last)` action instead. It copies the +elements in source range `[first, last)` to the array pointed to by +the `N`-th (0-based) argument: + +``` +using ::testing::NotNull; +using ::testing::SetArrayArgument; + +class MockArrayMutator : public ArrayMutator { + public: + MOCK_METHOD2(Mutate, void(int* values, int num_values)); + ... +}; +... + + MockArrayMutator mutator; + int values[5] = { 1, 2, 3, 4, 5 }; + EXPECT_CALL(mutator, Mutate(NotNull(), 5)) + .WillOnce(SetArrayArgument<0>(values, values + 5)); +``` + +This also works when the argument is an output iterator: + +``` +using ::testing::_; +using ::testing::SeArrayArgument; + +class MockRolodex : public Rolodex { + public: + MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); + ... +}; +... + + MockRolodex rolodex; + vector names; + names.push_back("George"); + names.push_back("John"); + names.push_back("Thomas"); + EXPECT_CALL(rolodex, GetNames(_)) + .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); +``` + +## Changing a Mock Object's Behavior Based on the State ## + +If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: + +``` +using ::testing::InSequence; +using ::testing::Return; + +... + { + InSequence seq; + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(my_mock, Flush()); + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(false)); + } + my_mock.FlushIfDirty(); +``` + +This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. + +If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: + +``` +using ::testing::_; +using ::testing::SaveArg; +using ::testing::Return; + +ACTION_P(ReturnPointee, p) { return *p; } +... + int previous_value = 0; + EXPECT_CALL(my_mock, GetPrevValue()) + .WillRepeatedly(ReturnPointee(&previous_value)); + EXPECT_CALL(my_mock, UpdateValue(_)) + .WillRepeatedly(SaveArg<0>(&previous_value)); + my_mock.DoSomethingToUpdateValue(); +``` + +Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. + +## Setting the Default Value for a Return Type ## + +If a mock method's return type is a built-in C++ type or pointer, by +default it will return 0 when invoked. You only need to specify an +action if this default value doesn't work for you. + +Sometimes, you may want to change this default value, or you may want +to specify a default value for types Google Mock doesn't know +about. You can do this using the `::testing::DefaultValue` class +template: + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD0(CalculateBar, Bar()); +}; +... + + Bar default_bar; + // Sets the default return value for type Bar. + DefaultValue::Set(default_bar); + + MockFoo foo; + + // We don't need to specify an action here, as the default + // return value works for us. + EXPECT_CALL(foo, CalculateBar()); + + foo.CalculateBar(); // This should return default_bar. + + // Unsets the default return value. + DefaultValue::Clear(); +``` + +Please note that changing the default value for a type can make you +tests hard to understand. We recommend you to use this feature +judiciously. For example, you may want to make sure the `Set()` and +`Clear()` calls are right next to the code that uses your mock. + +## Setting the Default Actions for a Mock Method ## + +You've learned how to change the default value of a given +type. However, this may be too coarse for your purpose: perhaps you +have two mock methods with the same return type and you want them to +have different behaviors. The `ON_CALL()` macro allows you to +customize your mock's behavior at the method level: + +``` +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Gt; +using ::testing::Return; +... + ON_CALL(foo, Sign(_)) + .WillByDefault(Return(-1)); + ON_CALL(foo, Sign(0)) + .WillByDefault(Return(0)); + ON_CALL(foo, Sign(Gt(0))) + .WillByDefault(Return(1)); + + EXPECT_CALL(foo, Sign(_)) + .Times(AnyNumber()); + + foo.Sign(5); // This should return 1. + foo.Sign(-9); // This should return -1. + foo.Sign(0); // This should return 0. +``` + +As you may have guessed, when there are more than one `ON_CALL()` +statements, the news order take precedence over the older ones. In +other words, the **last** one that matches the function arguments will +be used. This matching order allows you to set up the common behavior +in a mock object's constructor or the test fixture's set-up phase and +specialize the mock's behavior later. + +## Using Functions/Methods/Functors as Actions ## + +If the built-in actions don't suit you, you can easily use an existing +function, method, or functor as an action: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(Sum, int(int x, int y)); + MOCK_METHOD1(ComplexJob, bool(int x)); +}; + +int CalculateSum(int x, int y) { return x + y; } + +class Helper { + public: + bool ComplexJob(int x); +}; +... + + MockFoo foo; + Helper helper; + EXPECT_CALL(foo, Sum(_, _)) + .WillOnce(Invoke(CalculateSum)); + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(Invoke(&helper, &Helper::ComplexJob)); + + foo.Sum(5, 6); // Invokes CalculateSum(5, 6). + foo.ComplexJob(10); // Invokes helper.ComplexJob(10); +``` + +The only requirement is that the type of the function, etc must be +_compatible_ with the signature of the mock function, meaning that the +latter's arguments can be implicitly converted to the corresponding +arguments of the former, and the former's return type can be +implicitly converted to that of the latter. So, you can invoke +something whose type is _not_ exactly the same as the mock function, +as long as it's safe to do so - nice, huh? + +## Invoking a Function/Method/Functor Without Arguments ## + +`Invoke()` is very useful for doing actions that are more complex. It +passes the mock function's arguments to the function or functor being +invoked such that the callee has the full context of the call to work +with. If the invoked function is not interested in some or all of the +arguments, it can simply ignore them. + +Yet, a common pattern is that a test author wants to invoke a function +without the arguments of the mock function. `Invoke()` allows her to +do that using a wrapper function that throws away the arguments before +invoking an underlining nullary function. Needless to say, this can be +tedious and obscures the intent of the test. + +`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except +that it doesn't pass the mock function's arguments to the +callee. Here's an example: + +``` +using ::testing::_; +using ::testing::InvokeWithoutArgs; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(ComplexJob, bool(int n)); +}; + +bool Job1() { ... } +... + + MockFoo foo; + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(InvokeWithoutArgs(Job1)); + + foo.ComplexJob(10); // Invokes Job1(). +``` + +## Invoking an Argument of the Mock Function ## + +Sometimes a mock function will receive a function pointer or a functor +(in other words, a "callable") as an argument, e.g. + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); +}; +``` + +and you may want to invoke this callable argument: + +``` +using ::testing::_; +... + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(...); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +Arghh, you need to refer to a mock function argument but C++ has no +lambda (yet), so you have to define your own action. :-( Or do you +really? + +Well, Google Mock has an action to solve _exactly_ this problem: + +``` + InvokeArgument(arg_1, arg_2, ..., arg_m) +``` + +will invoke the `N`-th (0-based) argument the mock function receives, +with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is +a function pointer or a functor, Google Mock handles them both. + +With that, you could write: + +``` +using ::testing::_; +using ::testing::InvokeArgument; +... + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(InvokeArgument<1>(5)); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +What if the callable takes an argument by reference? No problem - just +wrap it inside `ByRef()`: + +``` +... + MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); +... +using ::testing::_; +using ::testing::ByRef; +using ::testing::InvokeArgument; +... + + MockFoo foo; + Helper helper; + ... + EXPECT_CALL(foo, Bar(_)) + .WillOnce(InvokeArgument<0>(5, ByRef(helper))); + // ByRef(helper) guarantees that a reference to helper, not a copy of it, + // will be passed to the callable. +``` + +What if the callable takes an argument by reference and we do **not** +wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a +copy_ of the argument, and pass a _reference to the copy_, instead of +a reference to the original value, to the callable. This is especially +handy when the argument is a temporary value: + +``` +... + MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); +... +using ::testing::_; +using ::testing::InvokeArgument; +... + + MockFoo foo; + ... + EXPECT_CALL(foo, DoThat(_)) + .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); + // Will execute (*f)(5.0, string("Hi")), where f is the function pointer + // DoThat() receives. Note that the values 5.0 and string("Hi") are + // temporary and dead once the EXPECT_CALL() statement finishes. Yet + // it's fine to perform this action later, since a copy of the values + // are kept inside the InvokeArgument action. +``` + +## Ignoring an Action's Result ## + +Sometimes you have an action that returns _something_, but you need an +action that returns `void` (perhaps you want to use it in a mock +function that returns `void`, or perhaps it needs to be used in +`DoAll()` and it's not the last in the list). `IgnoreResult()` lets +you do that. For example: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; + +int Process(const MyData& data); +string DoSomething(); + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Abc, void(const MyData& data)); + MOCK_METHOD0(Xyz, bool()); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, Abc(_)) + // .WillOnce(Invoke(Process)); + // The above line won't compile as Process() returns int but Abc() needs + // to return void. + .WillOnce(IgnoreResult(Invoke(Process))); + + EXPECT_CALL(foo, Xyz()) + .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), + // Ignores the string DoSomething() returns. + Return(true))); +``` + +Note that you **cannot** use `IgnoreResult()` on an action that already +returns `void`. Doing so will lead to ugly compiler errors. + +## Selecting an Action's Arguments ## + +Say you have a mock function `Foo()` that takes seven arguments, and +you have a custom action that you want to invoke when `Foo()` is +called. Trouble is, the custom action only wants three arguments: + +``` +using ::testing::_; +using ::testing::Invoke; +... + MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight)); +... + +bool IsVisibleInQuadrant1(bool visible, int x, int y) { + return visible && x >= 0 && y >= 0; +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( +``` + +To please the compiler God, you can to define an "adaptor" that has +the same signature as `Foo()` and calls the custom action with the +right arguments: + +``` +using ::testing::_; +using ::testing::Invoke; + +bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight) { + return IsVisibleInQuadrant1(visible, x, y); +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. +``` + +But isn't this awkward? + +Google Mock provides a generic _action adaptor_, so you can spend your +time minding more important business than writing your own +adaptors. Here's the syntax: + +``` + WithArgs(action) +``` + +creates an action that passes the arguments of the mock function at +the given indices (0-based) to the inner `action` and performs +it. Using `WithArgs`, our original example can be written as: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::WithArgs; +... + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); + // No need to define your own adaptor. +``` + +For better readability, Google Mock also gives you: + + * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and + * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. + +As you may have realized, `InvokeWithoutArgs(...)` is just syntactic +sugar for `WithoutArgs(Inovke(...))`. + +Here are more tips: + + * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. + * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. + * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. + * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. + +## Ignoring Arguments in Action Functions ## + +The selecting-an-action's-arguments recipe showed us one way to make a +mock function and an action with incompatible argument lists fit +together. The downside is that wrapping the action in +`WithArgs<...>()` can get tedious for people writing the tests. + +If you are defining a function, method, or functor to be used with +`Invoke*()`, and you are not interested in some of its arguments, an +alternative to `WithArgs` is to declare the uninteresting arguments as +`Unused`. This makes the definition less cluttered and less fragile in +case the types of the uninteresting arguments change. It could also +increase the chance the action function can be reused. For example, +given + +``` + MOCK_METHOD3(Foo, double(const string& label, double x, double y)); + MOCK_METHOD3(Bar, double(int index, double x, double y)); +``` + +instead of + +``` +using ::testing::_; +using ::testing::Invoke; + +double DistanceToOriginWithLabel(const string& label, double x, double y) { + return sqrt(x*x + y*y); +} + +double DistanceToOriginWithIndex(int index, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOriginWithLabel)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOriginWithIndex)); +``` + +you could write + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Unused; + +double DistanceToOrigin(Unused, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOrigin)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOrigin)); +``` + +## Sharing Actions ## + +Just like matchers, a Google Mock action object consists of a pointer +to a ref-counted implementation object. Therefore copying actions is +also allowed and very efficient. When the last action that references +the implementation object dies, the implementation object will be +deleted. + +If you have some complex action that you want to use again and again, +you may not have to build it from scratch everytime. If the action +doesn't have an internal state (i.e. if it always does the same thing +no matter how many times it has been called), you can assign it to an +action variable and use that variable repeatedly. For example: + +``` + Action set_flag = DoAll(SetArgumentPointee<0>(5), + Return(true)); + ... use set_flag in .WillOnce() and .WillRepeatedly() ... +``` + +However, if the action has its own state, you may be surprised if you +share the action object. Suppose you have an action factory +`IncrementCounter(init)` which creates an action that increments and +returns a counter whose initial value is `init`, using two actions +created from the same expression and using a shared action will +exihibit different behaviors. Example: + +``` + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(IncrementCounter(0)); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(IncrementCounter(0)); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 1 - Blah() uses a different + // counter than Bar()'s. +``` + +versus + +``` + Action increment = IncrementCounter(0); + + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(increment); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(increment); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 3 - the counter is shared. +``` + +# Misc Recipes on Using Google Mock # + +## Forcing a Verification ## + +When it's being destoyed, your friendly mock object will automatically +verify that all expectations on it have been satisfied, and will +generate [Google Test](http://code.google.com/p/googletest/) failures +if not. This is convenient as it leaves you with one less thing to +worry about. That is, unless you are not sure if your mock object will +be destoyed. + +How could it be that your mock object won't eventually be destroyed? +Well, it might be created on the heap and owned by the code you are +testing. Suppose there's a bug in that code and it doesn't delete the +mock object properly - you could end up with a passing test when +there's actually a bug. + +Using a heap checker is a good idea and can alleviate the concern, but +its implementation may not be 100% reliable. So, sometimes you do want +to _force_ Google Mock to verify a mock object before it is +(hopefully) destructed. You can do this with +`Mock::VerifyAndClearExpectations(&mock_object)`: + +``` +TEST(MyServerTest, ProcessesRequest) { + using ::testing::Mock; + + MockFoo* const foo = new MockFoo; + EXPECT_CALL(*foo, ...)...; + // ... other expectations ... + + // server now owns foo. + MyServer server(foo); + server.ProcessRequest(...); + + // In case that server's destructor will forget to delete foo, + // this will verify the expectations anyway. + Mock::VerifyAndClearExpectations(foo); +} // server is destroyed when it goes out of scope here. +``` + +**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a +`bool` to indicate whether the verification was successful (`true` for +yes), so you can wrap that function call inside a `ASSERT_TRUE()` if +there is no point going further when the verification has failed. + +## Using Check Points ## + +Sometimes you may want to "reset" a mock object at various check +points in your test: at each check point, you verify that all existing +expectations on the mock object have been satisfied, and then you set +some new expectations on it as if it's newly created. This allows you +to work with a mock object in "phases" whose sizes are each +manageable. + +One such scenario is that in your test's `SetUp()` function, you may +want to put the object you are testing into a certain state, with the +help from a mock object. Once in the desired state, you want to clear +all expectations on the mock, such that in the `TEST_F` body you can +set fresh expectations on it. + +As you may have figured out, the `Mock::VerifyAndClearExpectations()` +function we saw in the previous recipe can help you here. Or, if you +are using `ON_CALL()` to set default actions on the mock object and +want to clear the default actions as well, use +`Mock::VerifyAndClear(&mock_object)` instead. This function does what +`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the +same `bool`, **plus** it clears the `ON_CALL()` statements on +`mock_object` too. + +Another trick you can use to achieve the same effect is to put the +expectations in sequences and insert calls to a dummy "check-point" +function at specific places. Then you can verify that the mock +function calls do happen at the right time. For example, if you are +exercising code: + +``` +Foo(1); +Foo(2); +Foo(3); +``` + +and want to verify that `Foo(1)` and `Foo(3)` both invoke +`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: + +``` +using ::testing::MockFunction; + +TEST(FooTest, InvokesBarCorrectly) { + MyMock mock; + // Class MockFunction has exactly one mock method. It is named + // Call() and has type F. + MockFunction check; + { + InSequence s; + + EXPECT_CALL(mock, Bar("a")); + EXPECT_CALL(check, Call("1")); + EXPECT_CALL(check, Call("2")); + EXPECT_CALL(mock, Bar("a")); + } + Foo(1); + check.Call("1"); + Foo(2); + check.Call("2"); + Foo(3); +} +``` + +The expectation spec says that the first `Bar("a")` must happen before +check point "1", the second `Bar("a")` must happen after check point "2", +and nothing should happen between the two check points. The explicit +check points make it easy to tell which `Bar("a")` is called by which +call to `Foo()`. + +## Mocking Destructors ## + +Sometimes you want to make sure a mock object is destructed at the +right time, e.g. after `bar->A()` is called but before `bar->B()` is +called. We already know that you can specify constraints on the order +of mock function calls, so all we need to do is to mock the destructor +of the mock function. + +This sounds simple, except for one problem: a destructor is a special +function with special syntax and special semantics, and the +`MOCK_METHOD0` macro doesn't work for it: + +``` + MOCK_METHOD0(~MockFoo, void()); // Won't compile! +``` + +The good news is that you can use a simple pattern to achieve the same +effect. First, add a mock function `Die()` to your mock class and call +it in the destructor, like this: + +``` +class MockFoo : public Foo { + ... + // Add the following two lines to the mock class. + MOCK_METHOD0(Die, void()); + virtual ~MockFoo() { Die(); } +}; +``` + +(If the name `Die()` clashes with an existing symbol, choose another +name.) Now, we have translated the problem of testing when a `MockFoo` +object dies to testing when its `Die()` method is called: + +``` + MockFoo* foo = new MockFoo; + MockBar* bar = new MockBar; + ... + { + InSequence s; + + // Expects *foo to die after bar->A() and before bar->B(). + EXPECT_CALL(*bar, A()); + EXPECT_CALL(*foo, Die()); + EXPECT_CALL(*bar, B()); + } +``` + +And that's that. + +## Using Google Mock and Threads ## + +**IMPORTANT NOTE:** What we describe in this recipe is **NOT** true yet, +as Google Mock is not currently thread-safe. However, all we need to +make it thread-safe is to implement some synchronization operations in +`` - and then the information below will +become true. + +In a **unit** test, it's best if you could isolate and test a piece of +code in a single-threaded context. That avoids race conditions and +dead locks, and makes debugging your test much easier. + +Yet many programs are multi-threaded, and sometimes to test something +we need to pound on it from more than one thread. Google Mock works +for this purpose too. + +Remember the steps for using a mock: + + 1. Create a mock object `foo`. + 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. + 1. The code under test calls methods of `foo`. + 1. Optionally, verify and reset the mock. + 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. + +If you follow the following simple rules, your mocks and threads can +live happily togeter: + + * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. + * Obviously, you can do step #1 without locking. + * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? + * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. + +If you violate the rules (for example, if you set expectations on a +mock while another thread is calling its methods), you get undefined +behavior. That's not fun, so don't do it. + +Google Mock guarantees that the action for a mock function is done in +the same thread that called the mock function. For example, in + +``` + EXPECT_CALL(mock, Foo(1)) + .WillOnce(action1); + EXPECT_CALL(mock, Foo(2)) + .WillOnce(action2); +``` + +if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, +Google Mock will execute `action1` in thread 1 and `action2` in thread +2. + +Google Mock does _not_ impose a sequence on actions performed in +different threads (doing so may create deadlocks as the actions may +need to cooperate). This means that the execution of `action1` and +`action2` in the above example _may_ interleave. If this is a problem, +you should add proper synchronization logic to `action1` and `action2` +to make the test thread-safe. + + +Also, remember that `DefaultValue` is a global resource that +potentially affects _all_ living mock objects in your +program. Naturally, you won't want to mess with it from multiple +threads or when there still are mocks in action. + +## Controlling How Much Information Google Mock Prints ## + +When Google Mock sees something that has the potential of being an +error (e.g. a mock function with no expectation is called, a.k.a. an +uninteresting call, which is allowed but perhaps you forgot to +explicitly ban the call), it prints some warning messages, including +the arguments of the function and the return value. Hopefully this +will remind you to take a look and see if there is indeed a problem. + +Sometimes you are confident that your tests are correct and may not +appreciate such friendly messages. Some other times, you are debugging +your tests or learning about the behavior of the code you are testing, +and wish you could observe every mock call that happens (including +argument values and the return value). Clearly, one size doesn't fit +all. + +You can control how much Google Mock tells you using the +`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string +with three possible values: + + * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. + * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. + * `error`: Google Mock will print errors only (least verbose). + +Alternatively, you can adjust the value of that flag from within your +tests like so: + +``` + ::testing::FLAGS_gmock_verbose = "error"; +``` + +Now, judiciously use the right flag to enable Google Mock serve you better! + +## Running Tests in Emacs ## + +If you build and run your tests in Emacs, the source file locations of +Google Mock and [Google Test](http://code.google.com/p/googletest/) +errors will be highlighted. Just press `` on one of them and +you'll be taken to the offending line. Or, you can just type `C-x `` +to jump to the next error. + +To make it even easier, you can add the following lines to your +`~/.emacs` file: + +``` +(global-set-key "\M-m" 'compile) ; m is for make +(global-set-key [M-down] 'next-error) +(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) +``` + +Then you can type `M-m` to start a build, or `M-up`/`M-down` to move +back and forth between errors. + +## Fusing Google Mock Source Files ## + +Google Mock's implementation consists of dozens of files (excluding +its own tests). Sometimes you may want them to be packaged up in +fewer files instead, such that you can easily copy them to a new +machine and start hacking there. For this we provide an experimental +Python script `fuse_gmock_files.py` in the `scripts/` directory +(starting with release 1.2.0). Assuming you have Python 2.4 or above +installed on your machine, just go to that directory and run +``` +python fuse_gmock_files.py OUTPUT_DIR +``` + +and you should see an `OUTPUT_DIR` directory being created with files +`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. +These three files contain everything you need to use Google Mock (and +Google Test). Just copy them to anywhere you want and you are ready +to write tests and use mocks. You can use the +[scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests +against them. + +# Extending Google Mock # + +## Writing New Matchers Quickly ## + +The `MATCHER*` family of macros can be used to define custom matchers +easily. The syntax: + +``` +MATCHER(name, "description string") { statements; } +``` + +will define a matcher with the given name that executes the +statements, which must return a `bool` to indicate if the match +succeeds. Inside the statements, you can refer to the value being +matched by `arg`, and refer to its type by `arg_type`. + +The description string documents what the matcher does, and is used to +generate the failure message when the match fails. Since a +`MATCHER()` is usually defined in a header file shared by multiple C++ +source files, we require the description to be a C-string _literal_ to +avoid possible side effects. It can be empty (`""`), in which case +Google Mock will use the sequence of words in the matcher name as the +description. + +For example: +``` +MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } +``` +allows you to write +``` + // Expects mock_foo.Bar(n) to be called where n is divisible by 7. + EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); +``` +or, +``` + // Verifies that the value of some_expression is divisible by 7. + EXPECT_THAT(some_expression, IsDivisibleBy7()); +``` +If the above assertion fails, it will print something like: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 +``` +where the description `"is divisible by 7"` is automatically calculated from the +matcher name `IsDivisibleBy7`. + +Optionally, you can stream additional information to a hidden argument +named `result_listener` to explain the match result. For example, a +better definition of `IsDivisibleBy7` is: +``` +MATCHER(IsDivisibleBy7, "") { + if ((arg % 7) == 0) + return true; + + *result_listener << "the remainder is " << (arg % 7); + return false; +} +``` + +With this definition, the above assertion will give a better message: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 (the remainder is 6) +``` + +You should let `MatchAndExplain()` print _any additional information_ +that can help a user understand the match result. Note that it should +explain why the match succeeds in case of a success (unless it's +obvious) - this is useful when the matcher is used inside +`Not()`. There is no need to print the argument value itself, as +Google Mock already prints it for you. + +**Notes:** + + 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. + 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. + +## Writing New Parameterized Matchers Quickly ## + +Sometimes you'll want to define a matcher that has parameters. For that you +can use the macro: +``` +MATCHER_P(name, param_name, "description string") { statements; } +``` + +For example: +``` +MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +``` +will allow you to write: +``` + EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +``` +which may lead to this message (assuming `n` is 10): +``` + Value of: Blah("a") + Expected: has absolute value 10 + Actual: -9 +``` + +Note that both the matcher description and its parameter are +printed, making the message human-friendly. + +In the matcher definition body, you can write `foo_type` to +reference the type of a parameter named `foo`. For example, in the +body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write +`value_type` to refer to the type of `value`. + +Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to +`MATCHER_P10` to support multi-parameter matchers: +``` +MATCHER_Pk(name, param_1, ..., param_k, "description string") { statements; } +``` + +Please note that the custom description string is for a particular +**instance** of the matcher, where the parameters have been bound to +actual values. Therefore usually you'll want the parameter values to +be part of the description. Google Mock lets you do that using +Python-style interpolations. The following syntaxes are supported +currently: + +| `%%` | a single `%` character | +|:-----|:-----------------------| +| `%(*)s` | all parameters of the matcher printed as a tuple | +| `%(foo)s` | value of the matcher parameter named `foo` | + +For example, +``` + MATCHER_P2(InClosedRange, low, hi, "is in range [%(low)s, %(hi)s]") { + return low <= arg && arg <= hi; + } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the message: +``` + Expected: is in range [4, 6] +``` + +If you specify `""` as the description, the failure message will +contain the sequence of words in the matcher name followed by the +parameter values printed as a tuple. For example, +``` + MATCHER_P2(InClosedRange, low, hi, "") { ... } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the text: +``` + Expected: in closed range (4, 6) +``` + +For the purpose of typing, you can view +``` +MATCHER_Pk(Foo, p1, ..., pk, "description string") { ... } +``` +as shorthand for +``` +template +FooMatcherPk +Foo(p1_type p1, ..., pk_type pk) { ... } +``` + +When you write `Foo(v1, ..., vk)`, the compiler infers the types of +the parameters `v1`, ..., and `vk` for you. If you are not happy with +the result of the type inference, you can specify the types by +explicitly instantiating the template, as in `Foo(5, false)`. +As said earlier, you don't get to (or need to) specify +`arg_type` as that's determined by the context in which the matcher +is used. + +You can assign the result of expression `Foo(p1, ..., pk)` to a +variable of type `FooMatcherPk`. This can be +useful when composing matchers. Matchers that don't have a parameter +or have only one parameter have special types: you can assign `Foo()` +to a `FooMatcher`-typed variable, and assign `Foo(p)` to a +`FooMatcherP`-typed variable. + +While you can instantiate a matcher template with reference types, +passing the parameters by pointer usually makes your code more +readable. If, however, you still want to pass a parameter by +reference, be aware that in the failure message generated by the +matcher you will see the value of the referenced object but not its +address. + +You can overload matchers with different numbers of parameters: +``` +MATCHER_P(Blah, a, "description string 1") { ... } +MATCHER_P2(Blah, a, b, "description string 2") { ... } +``` + +While it's tempting to always use the `MATCHER*` macros when defining +a new matcher, you should also consider implementing +`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see +the recipes that follow), especially if you need to use the matcher a +lot. While these approaches require more work, they give you more +control on the types of the value being matched and the matcher +parameters, which in general leads to better compiler error messages +that pay off in the long run. They also allow overloading matchers +based on parameter types (as opposed to just based on the number of +parameters). + +## Writing New Monomorphic Matchers ## + +A matcher of argument type `T` implements +`::testing::MatcherInterface` and does two things: it tests whether a +value of type `T` matches the matcher, and can describe what kind of +values it matches. The latter ability is used for generating readable +error messages when expectations are violated. + +The interface looks like this: + +``` +class MatchResultListener { + public: + ... + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x); + + // Returns the underlying ostream. + ::std::ostream* stream(); +}; + +template +class MatcherInterface { + public: + virtual ~MatcherInterface(); + + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Describes this matcher to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. + virtual void DescribeNegationTo(::std::ostream* os) const; +}; +``` + +If you need a custom matcher but `Truly()` is not a good option (for +example, you may not be happy with the way `Truly(predicate)` +describes itself, or you may want your matcher to be polymorphic as +`Eq(value)` is), you can define a matcher to do whatever you want in +two steps: first implement the matcher interface, and then define a +factory function to create a matcher instance. The second step is not +strictly needed but it makes the syntax of using the matcher nicer. + +For example, you can define a matcher to test whether an `int` is +divisible by 7 and then use it like this: +``` +using ::testing::MakeMatcher; +using ::testing::Matcher; +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { + return (n % 7) == 0; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is divisible by 7"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "is not divisible by 7"; + } +}; + +inline Matcher DivisibleBy7() { + return MakeMatcher(new DivisibleBy7Matcher); +} +... + + EXPECT_CALL(foo, Bar(DivisibleBy7())); +``` + +You may improve the matcher message by streaming additional +information to the `listener` argument in `MatchAndExplain()`: + +``` +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, + MatchResultListener* listener) const { + const int remainder = n % 7; + if (remainder != 0) { + *listener << "the remainder is " << remainder; + } + return remainder == 0; + } + ... +}; +``` + +Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: +``` +Value of: x +Expected: is divisible by 7 + Actual: 23 (the remainder is 2) +``` + +## Writing New Polymorphic Matchers ## + +You've learned how to write your own matchers in the previous +recipe. Just one problem: a matcher created using `MakeMatcher()` only +works for one particular type of arguments. If you want a +_polymorphic_ matcher that works with arguments of several types (for +instance, `Eq(x)` can be used to match a `value` as long as `value` == +`x` compiles -- `value` and `x` don't have to share the same type), +you can learn the trick from `` but it's a bit +involved. + +Fortunately, most of the time you can define a polymorphic matcher +easily with the help of `MakePolymorphicMatcher()`. Here's how you can +define `NotNull()` as an example: + +``` +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +using ::testing::NotNull; +using ::testing::PolymorphicMatcher; + +class NotNullMatcher { + public: + // To implement a polymorphic matcher, first define a COPYABLE class + // that has three members MatchAndExplain(), DescribeTo(), and + // DescribeNegationTo(), like the following. + + // In this example, we want to use NotNull() with any pointer, so + // MatchAndExplain() accepts a pointer of any type as its first argument. + // In general, you can define MatchAndExplain() as an ordinary method or + // a method template, or even overload it. + template + bool MatchAndExplain(T* p, + MatchResultListener* /* listener */) const { + return p != NULL; + } + + // Describes the property of a value matching this matcher. + void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } + + // Describes the property of a value NOT matching this matcher. + void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } +}; + +// To construct a polymorphic matcher, pass an instance of the class +// to MakePolymorphicMatcher(). Note the return type. +inline PolymorphicMatcher NotNull() { + return MakePolymorphicMatcher(NotNullMatcher()); +} +... + + EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. +``` + +**Note:** Your polymorphic matcher class does **not** need to inherit from +`MatcherInterface` or any other class, and its methods do **not** need +to be virtual. + +Like in a monomorphic matcher, you may explain the match result by +streaming additional information to the `listener` argument in +`MatchAndExplain()`. + +## Writing New Cardinalities ## + +A cardinality is used in `Times()` to tell Google Mock how many times +you expect a call to occur. It doesn't have to be exact. For example, +you can say `AtLeast(5)` or `Between(2, 4)`. + +If the built-in set of cardinalities doesn't suit you, you are free to +define your own by implementing the following interface (in namespace +`testing`): + +``` +class CardinalityInterface { + public: + virtual ~CardinalityInterface(); + + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; +``` + +For example, to specify that a call must occur even number of times, +you can write + +``` +using ::testing::Cardinality; +using ::testing::CardinalityInterface; +using ::testing::MakeCardinality; + +class EvenNumberCardinality : public CardinalityInterface { + public: + virtual bool IsSatisfiedByCallCount(int call_count) const { + return (call_count % 2) == 0; + } + + virtual bool IsSaturatedByCallCount(int call_count) const { + return false; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "called even number of times"; + } +}; + +Cardinality EvenNumber() { + return MakeCardinality(new EvenNumberCardinality); +} +... + + EXPECT_CALL(foo, Bar(3)) + .Times(EvenNumber()); +``` + +## Writing New Actions Quickly ## + +If the built-in actions don't work for you, and you find it +inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` +family to quickly define a new action that can be used in your code as +if it's a built-in action. + +By writing +``` +ACTION(name) { statements; } +``` +in a namespace scope (i.e. not inside a class or function), you will +define an action with the given name that executes the statements. +The value returned by `statements` will be used as the return value of +the action. Inside the statements, you can refer to the K-th +(0-based) argument of the mock function as `argK`. For example: +``` +ACTION(IncrementArg1) { return ++(*arg1); } +``` +allows you to write +``` +... WillOnce(IncrementArg1()); +``` + +Note that you don't need to specify the types of the mock function +arguments. Rest assured that your code is type-safe though: +you'll get a compiler error if `*arg1` doesn't support the `++` +operator, or if the type of `++(*arg1)` isn't compatible with the mock +function's return type. + +Another example: +``` +ACTION(Foo) { + (*arg2)(5); + Blah(); + *arg1 = 0; + return arg0; +} +``` +defines an action `Foo()` that invokes argument #2 (a function pointer) +with 5, calls function `Blah()`, sets the value pointed to by argument +#1 to 0, and returns argument #0. + +For more convenience and flexibility, you can also use the following +pre-defined symbols in the body of `ACTION`: + +| `argK_type` | The type of the K-th (0-based) argument of the mock function | +|:------------|:-------------------------------------------------------------| +| `args` | All arguments of the mock function as a tuple | +| `args_type` | The type of all arguments of the mock function as a tuple | +| `return_type` | The return type of the mock function | +| `function_type` | The type of the mock function | + +For example, when using an `ACTION` as a stub action for mock function: +``` +int DoSomething(bool flag, int* ptr); +``` +we have: +| **Pre-defined Symbol** | **Is Bound To** | +|:-----------------------|:----------------| +| `arg0` | the value of `flag` | +| `arg0_type` | the type `bool` | +| `arg1` | the value of `ptr` | +| `arg1_type` | the type `int*` | +| `args` | the tuple `(flag, ptr)` | +| `args_type` | the type `std::tr1::tuple` | +| `return_type` | the type `int` | +| `function_type` | the type `int(bool, int*)` | + +## Writing New Parameterized Actions Quickly ## + +Sometimes you'll want to parameterize an action you define. For that +we have another macro +``` +ACTION_P(name, param) { statements; } +``` + +For example, +``` +ACTION_P(Add, n) { return arg0 + n; } +``` +will allow you to write +``` +// Returns argument #0 + 5. +... WillOnce(Add(5)); +``` + +For convenience, we use the term _arguments_ for the values used to +invoke the mock function, and the term _parameters_ for the values +used to instantiate an action. + +Note that you don't need to provide the type of the parameter either. +Suppose the parameter is named `param`, you can also use the +Google-Mock-defined symbol `param_type` to refer to the type of the +parameter as inferred by the compiler. For example, in the body of +`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. + +Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support +multi-parameter actions. For example, +``` +ACTION_P2(ReturnDistanceTo, x, y) { + double dx = arg0 - x; + double dy = arg1 - y; + return sqrt(dx*dx + dy*dy); +} +``` +lets you write +``` +... WillOnce(ReturnDistanceTo(5.0, 26.5)); +``` + +You can view `ACTION` as a degenerated parameterized action where the +number of parameters is 0. + +You can also easily define actions overloaded on the number of parameters: +``` +ACTION_P(Plus, a) { ... } +ACTION_P2(Plus, a, b) { ... } +``` + +## Restricting the Type of an Argument or Parameter in an ACTION ## + +For maximum brevity and reusability, the `ACTION*` macros don't ask +you to provide the types of the mock function arguments and the action +parameters. Instead, we let the compiler infer the types for us. + +Sometimes, however, we may want to be more explicit about the types. +There are several tricks to do that. For example: +``` +ACTION(Foo) { + // Makes sure arg0 can be converted to int. + int n = arg0; + ... use n instead of arg0 here ... +} + +ACTION_P(Bar, param) { + // Makes sure the type of arg1 is const char*. + ::testing::StaticAssertTypeEq(); + + // Makes sure param can be converted to bool. + bool flag = param; +} +``` +where `StaticAssertTypeEq` is a compile-time assertion in Google Test +that verifies two types are the same. + +## Writing New Action Templates Quickly ## + +Sometimes you want to give an action explicit template parameters that +cannot be inferred from its value parameters. `ACTION_TEMPLATE()` +supports that and can be viewed as an extension to `ACTION()` and +`ACTION_P*()`. + +The syntax: +``` +ACTION_TEMPLATE(ActionName, + HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), + AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } +``` + +defines an action template that takes _m_ explicit template parameters +and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is +between 0 and 10. `name_i` is the name of the i-th template +parameter, and `kind_i` specifies whether it's a `typename`, an +integral constant, or a template. `p_i` is the name of the i-th value +parameter. + +Example: +``` +// DuplicateArg(output) converts the k-th argument of the mock +// function to type T and copies it to *output. +ACTION_TEMPLATE(DuplicateArg, + // Note the comma between int and k: + HAS_2_TEMPLATE_PARAMS(int, k, typename, T), + AND_1_VALUE_PARAMS(output)) { + *output = T(std::tr1::get(args)); +} +``` + +To create an instance of an action template, write: +``` + ActionName(v1, ..., v_n) +``` +where the `t`s are the template arguments and the +`v`s are the value arguments. The value argument +types are inferred by the compiler. For example: +``` +using ::testing::_; +... + int n; + EXPECT_CALL(mock, Foo(_, _)) + .WillOnce(DuplicateArg<1, unsigned char>(&n)); +``` + +If you want to explicitly specify the value argument types, you can +provide additional template arguments: +``` + ActionName(v1, ..., v_n) +``` +where `u_i` is the desired type of `v_i`. + +`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the +number of value parameters, but not on the number of template +parameters. Without the restriction, the meaning of the following is +unclear: + +``` + OverloadedAction(x); +``` + +Are we using a single-template-parameter action where `bool` refers to +the type of `x`, or a two-template-parameter action where the compiler +is asked to infer the type of `x`? + +## Using the ACTION Object's Type ## + +If you are writing a function that returns an `ACTION` object, you'll +need to know its type. The type depends on the macro used to define +the action and the parameter types. The rule is relatively simple: +| **Given Definition** | **Expression** | **Has Type** | +|:---------------------|:---------------|:-------------| +| `ACTION(Foo)` | `Foo()` | `FooAction` | +| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | +| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | +| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | +| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | +| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | +| ... | ... | ... | + +Note that we have to pick different suffixes (`Action`, `ActionP`, +`ActionP2`, and etc) for actions with different numbers of value +parameters, or the action definitions cannot be overloaded on the +number of them. + +## Writing New Monomorphic Actions ## + +While the `ACTION*` macros are very convenient, sometimes they are +inappropriate. For example, despite the tricks shown in the previous +recipes, they don't let you directly specify the types of the mock +function arguments and the action parameters, which in general leads +to unoptimized compiler error messages that can baffle unfamiliar +users. They also don't allow overloading actions based on parameter +types without jumping through some hoops. + +An alternative to the `ACTION*` macros is to implement +`::testing::ActionInterface`, where `F` is the type of the mock +function in which the action will be used. For example: + +``` +template class ActionInterface { + public: + virtual ~ActionInterface(); + + // Performs the action. Result is the return type of function type + // F, and ArgumentTuple is the tuple of arguments of F. + // + // For example, if F is int(bool, const string&), then Result would + // be int, and ArgumentTuple would be tr1::tuple. + virtual Result Perform(const ArgumentTuple& args) = 0; +}; + +using ::testing::_; +using ::testing::Action; +using ::testing::ActionInterface; +using ::testing::MakeAction; + +typedef int IncrementMethod(int*); + +class IncrementArgumentAction : public ActionInterface { + public: + virtual int Perform(const tr1::tuple& args) { + int* p = tr1::get<0>(args); // Grabs the first argument. + return *p++; + } +}; + +Action IncrementArgument() { + return MakeAction(new IncrementArgumentAction); +} +... + + EXPECT_CALL(foo, Baz(_)) + .WillOnce(IncrementArgument()); + + int n = 5; + foo.Baz(&n); // Should return 5 and change n to 6. +``` + +## Writing New Polymorphic Actions ## + +The previous recipe showed you how to define your own action. This is +all good, except that you need to know the type of the function in +which the action will be used. Sometimes that can be a problem. For +example, if you want to use the action in functions with _different_ +types (e.g. like `Return()` and `SetArgumentPointee()`). + +If an action can be used in several types of mock functions, we say +it's _polymorphic_. The `MakePolymorphicAction()` function template +makes it easy to define such an action: + +``` +namespace testing { + +template +PolymorphicAction MakePolymorphicAction(const Impl& impl); + +} // namespace testing +``` + +As an example, let's define an action that returns the second argument +in the mock function's argument list. The first step is to define an +implementation class: + +``` +class ReturnSecondArgumentAction { + public: + template + Result Perform(const ArgumentTuple& args) const { + // To get the i-th (0-based) argument, use tr1::get(args). + return tr1::get<1>(args); + } +}; +``` + +This implementation class does _not_ need to inherit from any +particular class. What matters is that it must have a `Perform()` +method template. This method template takes the mock function's +arguments as a tuple in a **single** argument, and returns the result of +the action. It can be either `const` or not, but must be invokable +with exactly one template argument, which is the result type. In other +words, you must be able to call `Perform(args)` where `R` is the +mock function's return type and `args` is its arguments in a tuple. + +Next, we use `MakePolymorphicAction()` to turn an instance of the +implementation class into the polymorphic action we need. It will be +convenient to have a wrapper for this: + +``` +using ::testing::MakePolymorphicAction; +using ::testing::PolymorphicAction; + +PolymorphicAction ReturnSecondArgument() { + return MakePolymorphicAction(ReturnSecondArgumentAction()); +} +``` + +Now, you can use this polymorphic action the same way you use the +built-in ones: + +``` +using ::testing::_; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, int(bool flag, int n)); + MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(ReturnSecondArgument()); + EXPECT_CALL(foo, DoThat(_, _, _)) + .WillOnce(ReturnSecondArgument()); + ... + foo.DoThis(true, 5); // Will return 5. + foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". +``` + +## Teaching Google Mock How to Print Your Values ## + +When an uninteresting or unexpected call occurs, Google Mock prints +the argument values to help you debug. The `EXPECT_THAT` and +`ASSERT_THAT` assertions also print the value being validated when the +test fails. Google Mock does this using the user-extensible value +printer defined in ``. + +This printer knows how to print the built-in C++ types, native arrays, +STL containers, and any type that supports the `<<` operator. For +other types, it prints the raw bytes in the value and hope you the +user can figure it out. + +Did I say that the printer is `extensible`? That means you can teach +it to do a better job at printing your particular type than to dump +the bytes. To do that, you just need to define `<<` for your type: + +``` +#include + +namespace foo { + +class Foo { ... }; + +// It's important that the << operator is defined in the SAME +// namespace that defines Foo. C++'s look-up rules rely on that. +::std::ostream& operator<<(::std::ostream& os, const Foo& foo) { + return os << foo.DebugString(); // Whatever needed to print foo to os. +} + +} // namespace foo +``` + +Sometimes, this might not be an option. For example, your team may +consider it dangerous or bad style to have a `<<` operator for `Foo`, +or `Foo` may already have a `<<` operator that doesn't do what you +want (and you cannot change it). Don't despair though - Google Mock +gives you a second chance to get it right. Namely, you can define a +`PrintTo()` function like this: + +``` +#include + +namespace foo { + +class Foo { ... }; + +// It's important that PrintTo() is defined in the SAME +// namespace that defines Foo. C++'s look-up rules rely on that. +void PrintTo(const Foo& foo, ::std::ostream* os) { + *os << foo.DebugString(); // Whatever needed to print foo to os. +} + +} // namespace foo +``` + +What if you have both `<<` and `PrintTo()`? In this case, the latter +will override the former when Google Mock is concerned. This allows +you to customize how the value should appear in Google Mock's output +without affecting code that relies on the behavior of its `<<` +operator. + +**Note:** When printing a pointer of type `T*`, Google Mock calls +`PrintTo(T*, std::ostream* os)` instead of `operator<<(std::ostream&, T*)`. +Therefore the only way to affect how a pointer is printed by Google +Mock is to define `PrintTo()` for it. Also note that `T*` and `const T*` +are different types, so you may need to define `PrintTo()` for both. + +Why does Google Mock treat pointers specially? There are several reasons: + + * We cannot use `operator<<` to print a `signed char*` or `unsigned char*`, since it will print the pointer as a NUL-terminated C string, which likely will cause an access violation. + * We want `NULL` pointers to be printed as `"NULL"`, but `operator<<` prints it as `"0"`, `"nullptr"`, or something else, depending on the compiler. + * With some compilers, printing a `NULL` `char*` using `operator<<` will segfault. + * `operator<<` prints a function pointer as a `bool` (hence it always prints `"1"`), which is not very useful. \ No newline at end of file diff --git a/googlemock/docs/v1_5/Documentation.md b/googlemock/docs/v1_5/Documentation.md new file mode 100644 index 0000000..315b0a2 --- /dev/null +++ b/googlemock/docs/v1_5/Documentation.md @@ -0,0 +1,11 @@ +This page lists all documentation wiki pages for Google Mock **version 1.5.0** -- **if you use a different version of Google Mock, please read the documentation for that specific version instead.** + + * [ForDummies](V1_5_ForDummies.md) -- start here if you are new to Google Mock. + * [CheatSheet](V1_5_CheatSheet.md) -- a quick reference. + * [CookBook](V1_5_CookBook.md) -- recipes for doing various tasks using Google Mock. + * [FrequentlyAskedQuestions](V1_5_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. + +To contribute code to Google Mock, read: + + * DevGuide -- read this _before_ writing your first patch. + * [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files. \ No newline at end of file diff --git a/googlemock/docs/v1_5/ForDummies.md b/googlemock/docs/v1_5/ForDummies.md new file mode 100644 index 0000000..fcc3b56 --- /dev/null +++ b/googlemock/docs/v1_5/ForDummies.md @@ -0,0 +1,439 @@ + + +(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](V1_5_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md).) + +# What Is Google C++ Mocking Framework? # +When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). + +**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: + + * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. + * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. + +If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. + +**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. + +Using Google Mock involves three basic steps: + + 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; + 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; + 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. + +# Why Google Mock? # +While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: + + * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. + * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. + * The knowledge you gained from using one mock doesn't transfer to the next. + +In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. + +Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: + + * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". + * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). + * Your tests are brittle as some resources they use are unreliable (e.g. the network). + * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. + * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. + * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. + +We encourage you to use Google Mock as: + + * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! + * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. + +# Getting Started # +Using Google Mock is easy! Inside your C++ source file, just `#include` `` and ``, and you are ready to go. + +# A Case for Mock Turtles # +Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: + +``` +class Turtle { + ... + virtual ~Turtle() {} + virtual void PenUp() = 0; + virtual void PenDown() = 0; + virtual void Forward(int distance) = 0; + virtual void Turn(int degrees) = 0; + virtual void GoTo(int x, int y) = 0; + virtual int GetX() const = 0; + virtual int GetY() const = 0; +}; +``` + +(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) + +You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. + +Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. + +# Writing the Mock Class # +If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) + +## How to Define It ## +Using the `Turtle` interface as example, here are the simple steps you need to follow: + + 1. Derive a class `MockTurtle` from `Turtle`. + 1. Take a virtual function of `Turtle`. Count how many arguments it has. + 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. + 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). + 1. Repeat until all virtual functions you want to mock are done. + +After the process, you should have something like: + +``` +#include // Brings in Google Mock. +class MockTurtle : public Turtle { + public: + ... + MOCK_METHOD0(PenUp, void()); + MOCK_METHOD0(PenDown, void()); + MOCK_METHOD1(Forward, void(int distance)); + MOCK_METHOD1(Turn, void(int degrees)); + MOCK_METHOD2(GoTo, void(int x, int y)); + MOCK_CONST_METHOD0(GetX, int()); + MOCK_CONST_METHOD0(GetY, int()); +}; +``` + +You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. + +**Tip:** If even this is too much work for you, you'll find the +`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line +tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, +and it will print the definition of the mock class for you. Due to the +complexity of the C++ language, this script may not always work, but +it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). + +## Where to Put It ## +When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) + +So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. + +Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. + +# Using Mocks in Tests # +Once you have a mock class, using it is easy. The typical work flow is: + + 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). + 1. Create some mock objects. + 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). + 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. + 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. + +Here's an example: + +``` +#include "path/to/mock-turtle.h" +#include +#include +using ::testing::AtLeast; // #1 + +TEST(PainterTest, CanDrawSomething) { + MockTurtle turtle; // #2 + EXPECT_CALL(turtle, PenDown()) // #3 + .Times(AtLeast(1)); + + Painter painter(&turtle); // #4 + + EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); +} // #5 + +int main(int argc, char** argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} +``` + +As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: + +``` +path/to/my_test.cc:119: Failure +Actual function call count doesn't match this expectation: +Actually: never called; +Expected: called at least once. +``` + +**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. + +**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. + +**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. + +This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. + +Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. + +## Using Google Mock with Any Testing Framework ## +If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or +[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: +``` +int main(int argc, char** argv) { + // The following line causes Google Mock to throw an exception on failure, + // which will be interpreted by your testing framework as a test failure. + ::testing::GTEST_FLAG(throw_on_failure) = true; + ::testing::InitGoogleMock(&argc, argv); + ... whatever your testing framework requires ... +} +``` + +This approach has a catch: it makes Google Mock throw an exception +from a mock object's destructor sometimes. With some compilers, this +sometimes causes the test program to crash. You'll still be able to +notice that the test has failed, but it's not a graceful failure. + +A better solution is to use Google Test's +[event listener API](http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) +to report a test failure to your testing framework properly. You'll need to +implement the `OnTestPartResult()` method of the event listener interface, but it +should be straightforward. + +If this turns out to be too much work, we suggest that you stick with +Google Test, which works with Google Mock seamlessly (in fact, it is +technically part of Google Mock.). If there is a reason that you +cannot use Google Test, please let us know. + +# Setting Expectations # +The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." + +## General Syntax ## +In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: + +``` +EXPECT_CALL(mock_object, method(matchers)) + .Times(cardinality) + .WillOnce(action) + .WillRepeatedly(action); +``` + +The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) + +The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. + +This syntax is designed to make an expectation read like English. For example, you can probably guess that + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .Times(5) + .WillOnce(Return(100)) + .WillOnce(Return(150)) + .WillRepeatedly(Return(200)); +``` + +says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). + +**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. + +## Matchers: What Arguments Do We Expect? ## +When a mock function takes arguments, we must specify what arguments we are expecting; for example: + +``` +// Expects the turtle to move forward by 100 units. +EXPECT_CALL(turtle, Forward(100)); +``` + +Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": + +``` +using ::testing::_; +... +// Expects the turtle to move forward. +EXPECT_CALL(turtle, Forward(_)); +``` + +`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. + +A list of built-in matchers can be found in the [CheatSheet](V1_5_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: + +``` +using ::testing::Ge;... +EXPECT_CALL(turtle, Forward(Ge(100))); +``` + +This checks that the turtle will be told to go forward by at least 100 units. + +## Cardinalities: How Many Times Will It Be Called? ## +The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. + +An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. + +We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_5_CheatSheet.md). + +The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: + + * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. + * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. + * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. + +**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? + +## Actions: What Should It Do? ## +Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. + +First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. + +Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillOnce(Return(300)); +``` + +This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillRepeatedly(Return(300)); +``` + +says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. + +Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). + +What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](V1_5_CheatSheet#Actions.md). + +**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: + +``` +int n = 100; +EXPECT_CALL(turtle, GetX()) +.Times(4) +.WillOnce(Return(n++)); +``` + +Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_5_CookBook.md). + +Time for another quiz! What do you think the following means? + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) +.Times(4) +.WillOnce(Return(100)); +``` + +Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. + +## Using Multiple Expectations ## +So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. + +By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: + +``` +using ::testing::_;... +EXPECT_CALL(turtle, Forward(_)); // #1 +EXPECT_CALL(turtle, Forward(10)) // #2 + .Times(2); +``` + +If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. + +**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. + +## Ordered vs Unordered Calls ## +By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. + +Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: + +``` +using ::testing::InSequence;... +TEST(FooTest, DrawsLineSegment) { + ... + { + InSequence dummy; + + EXPECT_CALL(turtle, PenDown()); + EXPECT_CALL(turtle, Forward(100)); + EXPECT_CALL(turtle, PenUp()); + } + Foo(); +} +``` + +By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. + +In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. + +(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_5_CookBook.md).) + +## All Expectations Are Sticky (Unless Said Otherwise) ## +Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? + +After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): + +``` +using ::testing::_;... +EXPECT_CALL(turtle, GoTo(_, _)) // #1 + .Times(AnyNumber()); +EXPECT_CALL(turtle, GoTo(0, 0)) // #2 + .Times(2); +``` + +Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. + +This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). + +Simple? Let's see if you've really understood it: what does the following code say? + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)); +} +``` + +If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! + +One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); +} +``` + +And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: + +``` +using ::testing::InSequence; +using ::testing::Return; +... +{ + InSequence s; + + for (int i = 1; i <= n; i++) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); + } +} +``` + +By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). + +## Uninteresting Calls ## +A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. + +In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. + +# What Now? # +Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. + +Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_5_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. \ No newline at end of file diff --git a/googlemock/docs/v1_5/FrequentlyAskedQuestions.md b/googlemock/docs/v1_5/FrequentlyAskedQuestions.md new file mode 100644 index 0000000..7593243 --- /dev/null +++ b/googlemock/docs/v1_5/FrequentlyAskedQuestions.md @@ -0,0 +1,624 @@ + + +Please send your questions to the +[googlemock](http://groups.google.com/group/googlemock) discussion +group. If you need help with compiler errors, make sure you have +tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. + +## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## + +After version 1.4.0 of Google Mock was released, we had an idea on how +to make it easier to write matchers that can generate informative +messages efficiently. We experimented with this idea and liked what +we saw. Therefore we decided to implement it. + +Unfortunately, this means that if you have defined your own matchers +by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, +your definitions will no longer compile. Matchers defined using the +`MATCHER*` family of macros are not affected. + +Sorry for the hassle if your matchers are affected. We believe it's +in everyone's long-term interest to make this change sooner than +later. Fortunately, it's usually not hard to migrate an existing +matcher to the new API. Here's what you need to do: + +If you wrote your matcher like this: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` + +you'll need to change it to: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` +(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second +argument of type `MatchResultListener*`.) + +If you were also using `ExplainMatchResultTo()` to improve the matcher +message: +``` +// Old matcher definition that doesn't work with the lastest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + + virtual void ExplainMatchResultTo(MyType value, + ::std::ostream* os) const { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Foo property is " << value.GetFoo(); + } + ... +}; +``` + +you should move the logic of `ExplainMatchResultTo()` into +`MatchAndExplain()`, using the `MatchResultListener` argument where +the `::std::ostream` was used: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Foo property is " << value.GetFoo(); + return value.GetFoo() > 5; + } + ... +}; +``` + +If your matcher is defined using `MakePolymorphicMatcher()`: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you should rename the `Matches()` method to `MatchAndExplain()` and +add a `MatchResultListener*` argument (the same as what you need to do +for matchers defined by implementing `MatcherInterface`): +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +If your polymorphic matcher uses `ExplainMatchResultTo()` for better +failure messages: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +void ExplainMatchResultTo(const MyGreatMatcher& matcher, + MyType value, + ::std::ostream* os) { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Bar property is " << value.GetBar(); +} +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you'll need to move the logic inside `ExplainMatchResultTo()` to +`MatchAndExplain()`: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Bar property is " << value.GetBar(); + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +For more information, you can read these +[two](V1_5_CookBook#Writing_New_Monomorphic_Matchers.md) +[recipes](V1_5_CookBook#Writing_New_Polymorphic_Matchers.md) +from the cookbook. As always, you +are welcome to post questions on `googlemock@googlegroups.com` if you +need any help. + +## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## + +Google Mock works out of the box with Google Test. However, it's easy +to configure it to work with any testing framework of your choice. +[Here](V1_5_ForDummies#Using_Google_Mock_with_Any_Testing_Framework.md) is how. + +## How am I supposed to make sense of these horrible template errors? ## + +If you are confused by the compiler errors gcc threw at you, +try consulting the _Google Mock Doctor_ tool first. What it does is to +scan stdin for gcc error messages, and spit out diagnoses on the +problems (we call them diseases) your code has. + +To "install", run command: +``` +alias gmd='/scripts/gmock_doctor.py' +``` + +To use it, do: +``` + 2>&1 | gmd +``` + +For example: +``` +make my_test 2>&1 | gmd +``` + +Or you can run `gmd` and copy-n-paste gcc's error messages to it. + +## Can I mock a variadic function? ## + +You cannot mock a variadic function (i.e. a function taking ellipsis +(`...`) arguments) directly in Google Mock. + +The problem is that in general, there is _no way_ for a mock object to +know how many arguments are passed to the variadic method, and what +the arguments' types are. Only the _author of the base class_ knows +the protocol, and we cannot look into his head. + +Therefore, to mock such a function, the _user_ must teach the mock +object how to figure out the number of arguments and their types. One +way to do it is to provide overloaded versions of the function. + +Ellipsis arguments are inherited from C and not really a C++ feature. +They are unsafe to use and don't work with arguments that have +constructors or destructors. Therefore we recommend to avoid them in +C++ as much as possible. + +## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## + +If you compile this using Microsoft Visual C++ 2005 SP1: +``` +class Foo { + ... + virtual void Bar(const int i) = 0; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Bar, void(const int i)); +}; +``` +You may get the following warning: +``` +warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier +``` + +This is a MSVC bug. The same code compiles fine with gcc ,for +example. If you use Visual C++ 2008 SP1, you would get the warning: +``` +warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers +``` + +In C++, if you _declare_ a function with a `const` parameter, the +`const` modifier is _ignored_. Therefore, the `Foo` base class above +is equivalent to: +``` +class Foo { + ... + virtual void Bar(int i) = 0; // int or const int? Makes no difference. +}; +``` + +In fact, you can _declare_ Bar() with an `int` parameter, and _define_ +it with a `const int` parameter. The compiler will still match them +up. + +Since making a parameter `const` is meaningless in the method +_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. +That should workaround the VC bug. + +Note that we are talking about the _top-level_ `const` modifier here. +If the function parameter is passed by pointer or reference, declaring +the _pointee_ or _referee_ as `const` is still meaningful. For +example, the following two declarations are _not_ equivalent: +``` +void Bar(int* p); // Neither p nor *p is const. +void Bar(const int* p); // p is not const, but *p is. +``` + +## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## + +We've noticed that when the `/clr` compiler flag is used, Visual C++ +uses 5~6 times as much memory when compiling a mock class. We suggest +to avoid `/clr` when compiling native C++ mocks. + +## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## + +You might want to run your test with +`--gmock_verbose=info`. This flag lets Google Mock print a trace +of every mock function call it receives. By studying the trace, +you'll gain insights on why the expectations you set are not met. + +## How can I assert that a function is NEVER called? ## + +``` +EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## + +When Google Mock detects a failure, it prints relevant information +(the mock function arguments, the state of relevant expectations, and +etc) to help the user debug. If another failure is detected, Google +Mock will do the same, including printing the state of relevant +expectations. + +Sometimes an expectation's state didn't change between two failures, +and you'll see the same description of the state twice. They are +however _not_ redundant, as they refer to _different points in time_. +The fact they are the same _is_ interesting information. + +## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## + +Does the class (hopefully a pure interface) you are mocking have a +virtual destructor? + +Whenever you derive from a base class, make sure its destructor is +virtual. Otherwise Bad Things will happen. Consider the following +code: + +``` +class Base { + public: + // Not virtual, but should be. + ~Base() { ... } + ... +}; + +class Derived : public Base { + public: + ... + private: + std::string value_; +}; + +... + Base* p = new Derived; + ... + delete p; // Surprise! ~Base() will be called, but ~Derived() will not + // - value_ is leaked. +``` + +By changing `~Base()` to virtual, `~Derived()` will be correctly +called when `delete p` is executed, and the heap checker +will be happy. + +## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## + +When people complain about this, often they are referring to code like: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. However, I have to write the expectations in the +// reverse order. This sucks big time!!! +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); +``` + +The problem is that they didn't pick the **best** way to express the test's +intent. + +By default, expectations don't have to be matched in _any_ particular +order. If you want them to match in a certain order, you need to be +explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's +easy to accidentally over-specify your tests, and we want to make it +harder to do so. + +There are two better ways to write the test spec. You could either +put the expectations in sequence: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. Using a sequence, we can write the expectations +// in their natural order. +{ + InSequence s; + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +} +``` + +or you can put the sequence of actions in the same expectation: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +``` + +Back to the original questions: why does Google Mock search the +expectations (and `ON_CALL`s) from back to front? Because this +allows a user to set up a mock's behavior for the common case early +(e.g. in the mock's constructor or the test fixture's set-up phase) +and customize it with more specific rules later. If Google Mock +searches from front to back, this very useful pattern won't be +possible. + +## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## + +When choosing between being neat and being safe, we lean toward the +latter. So the answer is that we think it's better to show the +warning. + +Often people write `ON_CALL`s in the mock object's +constructor or `SetUp()`, as the default behavior rarely changes from +test to test. Then in the test body they set the expectations, which +are often different for each test. Having an `ON_CALL` in the set-up +part of a test doesn't mean that the calls are expected. If there's +no `EXPECT_CALL` and the method is called, it's possibly an error. If +we quietly let the call go through without notifying the user, bugs +may creep in unnoticed. + +If, however, you are sure that the calls are OK, you can write + +``` +EXPECT_CALL(foo, Bar(_)) + .WillRepeatedly(...); +``` + +instead of + +``` +ON_CALL(foo, Bar(_)) + .WillByDefault(...); +``` + +This tells Google Mock that you do expect the calls and no warning should be +printed. + +Also, you can control the verbosity using the `--gmock_verbose` flag. +If you find the output too noisy when debugging, just choose a less +verbose level. + +## How can I delete the mock function's argument in an action? ## + +If you find yourself needing to perform some action that's not +supported by Google Mock directly, remember that you can define your own +actions using +[MakeAction()](V1_5_CookBook#Writing_New_Actions.md) or +[MakePolymorphicAction()](V1_5_CookBook#Writing_New_Polymorphic_Actions.md), +or you can write a stub function and invoke it using +[Invoke()](V1_5_CookBook#Using_Functions_Methods_Functors.md). + +## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## + +What?! I think it's beautiful. :-) + +While which syntax looks more natural is a subjective matter to some +extent, Google Mock's syntax was chosen for several practical advantages it +has. + +Try to mock a function that takes a map as an argument: +``` +virtual int GetSize(const map& m); +``` + +Using the proposed syntax, it would be: +``` +MOCK_METHOD1(GetSize, int, const map& m); +``` + +Guess what? You'll get a compiler error as the compiler thinks that +`const map& m` are **two**, not one, arguments. To work +around this you can use `typedef` to give the map type a name, but +that gets in the way of your work. Google Mock's syntax avoids this +problem as the function's argument types are protected inside a pair +of parentheses: +``` +// This compiles fine. +MOCK_METHOD1(GetSize, int(const map& m)); +``` + +You still need a `typedef` if the return type contains an unprotected +comma, but that's much rarer. + +Other advantages include: + 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. + 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. + 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! + +## My code calls a static/global function. Can I mock it? ## + +You can, but you need to make some changes. + +In general, if you find yourself needing to mock a static function, +it's a sign that your modules are too tightly coupled (and less +flexible, less reusable, less testable, etc). You are probably better +off defining a small interface and call the function through that +interface, which then can be easily mocked. It's a bit of work +initially, but usually pays for itself quickly. + +This Google Testing Blog +[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) +says it excellently. Check it out. + +## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## + +I know it's not a question, but you get an answer for free any way. :-) + +With Google Mock, you can create mocks in C++ easily. And people might be +tempted to use them everywhere. Sometimes they work great, and +sometimes you may find them, well, a pain to use. So, what's wrong in +the latter case? + +When you write a test without using mocks, you exercise the code and +assert that it returns the correct value or that the system is in an +expected state. This is sometimes called "state-based testing". + +Mocks are great for what some call "interaction-based" testing: +instead of checking the system state at the very end, mock objects +verify that they are invoked the right way and report an error as soon +as it arises, giving you a handle on the precise context in which the +error was triggered. This is often more effective and economical to +do than state-based testing. + +If you are doing state-based testing and using a test double just to +simulate the real object, you are probably better off using a fake. +Using a mock in this case causes pain, as it's not a strong point for +mocks to perform complex actions. If you experience this and think +that mocks suck, you are just not using the right tool for your +problem. Or, you might be trying to solve the wrong problem. :-) + +## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## + +By all means, NO! It's just an FYI. + +What it means is that you have a mock function, you haven't set any +expectations on it (by Google Mock's rule this means that you are not +interested in calls to this function and therefore it can be called +any number of times), and it is called. That's OK - you didn't say +it's not OK to call the function! + +What if you actually meant to disallow this function to be called, but +forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While +one can argue that it's the user's fault, Google Mock tries to be nice and +prints you a note. + +So, when you see the message and believe that there shouldn't be any +uninteresting calls, you should investigate what's going on. To make +your life easier, Google Mock prints the function name and arguments +when an uninteresting call is encountered. + +## I want to define a custom action. Should I use Invoke() or implement the action interface? ## + +Either way is fine - you want to choose the one that's more convenient +for your circumstance. + +Usually, if your action is for a particular function type, defining it +using `Invoke()` should be easier; if your action can be used in +functions of different types (e.g. if you are defining +`Return(value)`), `MakePolymorphicAction()` is +easiest. Sometimes you want precise control on what types of +functions the action can be used in, and implementing +`ActionInterface` is the way to go here. See the implementation of +`Return()` in `include/gmock/gmock-actions.h` for an example. + +## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## + +You got this error as Google Mock has no idea what value it should return +when the mock method is called. `SetArgumentPointee()` says what the +side effect is, but doesn't say what the return value should be. You +need `DoAll()` to chain a `SetArgumentPointee()` with a `Return()`. + +See this [recipe](V1_5_CookBook#Mocking_Side_Effects.md) for more details and an example. + + +## My question is not in your FAQ! ## + +If you cannot find the answer to your question in this FAQ, there are +some other resources you can use: + + 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), + 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), + 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). + +Please note that creating an issue in the +[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ +a good way to get your answer, as it is monitored infrequently by a +very small number of people. + +When asking a question, it's helpful to provide as much of the +following information as possible (people cannot help you if there's +not enough information in your question): + + * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), + * your operating system, + * the name and version of your compiler, + * the complete command line flags you give to your compiler, + * the complete compiler error messages (if the question is about compilation), + * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. \ No newline at end of file diff --git a/googlemock/docs/v1_6/CheatSheet.md b/googlemock/docs/v1_6/CheatSheet.md new file mode 100644 index 0000000..91de1d2 --- /dev/null +++ b/googlemock/docs/v1_6/CheatSheet.md @@ -0,0 +1,534 @@ + + +# Defining a Mock Class # + +## Mocking a Normal Class ## + +Given +``` +class Foo { + ... + virtual ~Foo(); + virtual int GetSize() const = 0; + virtual string Describe(const char* name) = 0; + virtual string Describe(int type) = 0; + virtual bool Process(Bar elem, int count) = 0; +}; +``` +(note that `~Foo()` **must** be virtual) we can define its mock as +``` +#include "gmock/gmock.h" + +class MockFoo : public Foo { + MOCK_CONST_METHOD0(GetSize, int()); + MOCK_METHOD1(Describe, string(const char* name)); + MOCK_METHOD1(Describe, string(int type)); + MOCK_METHOD2(Process, bool(Bar elem, int count)); +}; +``` + +To create a "nice" mock object which ignores all uninteresting calls, +or a "strict" mock object, which treats them as failures: +``` +NiceMock nice_foo; // The type is a subclass of MockFoo. +StrictMock strict_foo; // The type is a subclass of MockFoo. +``` + +## Mocking a Class Template ## + +To mock +``` +template +class StackInterface { + public: + ... + virtual ~StackInterface(); + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; +``` +(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: +``` +template +class MockStack : public StackInterface { + public: + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Specifying Calling Conventions for Mock Functions ## + +If your mock function doesn't use the default calling convention, you +can specify it by appending `_WITH_CALLTYPE` to any of the macros +described in the previous two sections and supplying the calling +convention as the first argument to the macro. For example, +``` + MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); + MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); +``` +where `STDMETHODCALLTYPE` is defined by `` on Windows. + +# Using Mocks in Tests # + +The typical flow is: + 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. + 1. Create the mock objects. + 1. Optionally, set the default actions of the mock objects. + 1. Set your expectations on the mock objects (How will they be called? What wil they do?). + 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. + 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. + +Here is an example: +``` +using ::testing::Return; // #1 + +TEST(BarTest, DoesThis) { + MockFoo foo; // #2 + + ON_CALL(foo, GetSize()) // #3 + .WillByDefault(Return(1)); + // ... other default actions ... + + EXPECT_CALL(foo, Describe(5)) // #4 + .Times(3) + .WillRepeatedly(Return("Category 5")); + // ... other expectations ... + + EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 +} // #6 +``` + +# Setting Default Actions # + +Google Mock has a **built-in default action** for any function that +returns `void`, `bool`, a numeric value, or a pointer. + +To customize the default action for functions with return type `T` globally: +``` +using ::testing::DefaultValue; + +DefaultValue::Set(value); // Sets the default value to be returned. +// ... use the mocks ... +DefaultValue::Clear(); // Resets the default value. +``` + +To customize the default action for a particular method, use `ON_CALL()`: +``` +ON_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .WillByDefault(action); +``` + +# Setting Expectations # + +`EXPECT_CALL()` sets **expectations** on a mock method (How will it be +called? What will it do?): +``` +EXPECT_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .Times(cardinality) ? + .InSequence(sequences) * + .After(expectations) * + .WillOnce(action) * + .WillRepeatedly(action) ? + .RetiresOnSaturation(); ? +``` + +If `Times()` is omitted, the cardinality is assumed to be: + + * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; + * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or + * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. + +A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. + +# Matchers # + +A **matcher** matches a _single_ argument. You can use it inside +`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value +directly: + +| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | +|:------------------------------|:----------------------------------------| +| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | + +Built-in matchers (where `argument` is the function argument) are +divided into several categories: + +## Wildcard ## +|`_`|`argument` can be any value of the correct type.| +|:--|:-----------------------------------------------| +|`A()` or `An()`|`argument` can be any value of type `type`. | + +## Generic Comparison ## + +|`Eq(value)` or `value`|`argument == value`| +|:---------------------|:------------------| +|`Ge(value)` |`argument >= value`| +|`Gt(value)` |`argument > value` | +|`Le(value)` |`argument <= value`| +|`Lt(value)` |`argument < value` | +|`Ne(value)` |`argument != value`| +|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| +|`NotNull()` |`argument` is a non-null pointer (raw or smart).| +|`Ref(variable)` |`argument` is a reference to `variable`.| +|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| + +Except `Ref()`, these matchers make a _copy_ of `value` in case it's +modified or destructed later. If the compiler complains that `value` +doesn't have a public copy constructor, try wrap it in `ByRef()`, +e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure +`non_copyable_value` is not changed afterwards, or the meaning of your +matcher will be changed. + +## Floating-Point Matchers ## + +|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| +|:-------------------|:----------------------------------------------------------------------------------------------| +|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | +|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | +|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | + +These matchers use ULP-based comparison (the same as used in +[Google Test](http://code.google.com/p/googletest/)). They +automatically pick a reasonable error bound based on the absolute +value of the expected value. `DoubleEq()` and `FloatEq()` conform to +the IEEE standard, which requires comparing two NaNs for equality to +return false. The `NanSensitive*` version instead treats two NaNs as +equal, which is often what a user wants. + +## String Matchers ## + +The `argument` can be either a C string or a C++ string object: + +|`ContainsRegex(string)`|`argument` matches the given regular expression.| +|:----------------------|:-----------------------------------------------| +|`EndsWith(suffix)` |`argument` ends with string `suffix`. | +|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | +|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| +|`StartsWith(prefix)` |`argument` starts with string `prefix`. | +|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | +|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| +|`StrEq(string)` |`argument` is equal to `string`. | +|`StrNe(string)` |`argument` is not equal to `string`. | + +`ContainsRegex()` and `MatchesRegex()` use the regular expression +syntax defined +[here](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Regular_Expression_Syntax). +`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide +strings as well. + +## Container Matchers ## + +Most STL-style containers support `==`, so you can use +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. If you want to write the elements in-line, +match them more flexibly, or get more informative messages, you can use: + +| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | +|:--------------|:-------------------------------------------------------------------------------------------| +| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | +| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | +| `ElementsAreArray(array)` or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array. | +| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | +| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. | + +These matchers can also match: + + 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and + 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). + +where the array may be multi-dimensional (i.e. its elements can be arrays). + +## Member Matchers ## + +|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| +|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| +|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| +|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | +|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| + +## Matching the Result of a Function or Functor ## + +|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| +|:---------------|:---------------------------------------------------------------------| + +## Pointer Matchers ## + +|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| +|:-----------|:-----------------------------------------------------------------------------------------------| + +## Multiargument Matchers ## + +Technically, all matchers match a _single_ value. A "multi-argument" +matcher is just one that matches a _tuple_. The following matchers can +be used to match a tuple `(x, y)`: + +|`Eq()`|`x == y`| +|:-----|:-------| +|`Ge()`|`x >= y`| +|`Gt()`|`x > y` | +|`Le()`|`x <= y`| +|`Lt()`|`x < y` | +|`Ne()`|`x != y`| + +You can use the following selectors to pick a subset of the arguments +(or reorder them) to participate in the matching: + +|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| +|:-----------|:-------------------------------------------------------------------| +|`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| + +## Composite Matchers ## + +You can make a matcher from one or more other matchers: + +|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| +|:-----------------------|:---------------------------------------------------| +|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| +|`Not(m)` |`argument` doesn't match matcher `m`. | + +## Adapters for Matchers ## + +|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| +|:------------------|:--------------------------------------| +|`SafeMatcherCast(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Casting_Matchers) matcher `m` to type `Matcher`. | +|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| + +## Matchers as Predicates ## + +|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| +|:------------------|:---------------------------------------------------------------------------------------------| +|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | +|`Value(value, m)` |evaluates to `true` if `value` matches `m`. | + +## Defining Matchers ## + +| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | +|:-------------------------------------------------|:------------------------------------------------------| +| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | +| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | + +**Notes:** + + 1. The `MATCHER*` macros cannot be used inside a function or class. + 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). + 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. + +## Matchers as Test Assertions ## + +|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/V1_6_Primer#Assertions) if the value of `expression` doesn't match matcher `m`.| +|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | + +# Actions # + +**Actions** specify what a mock function should do when invoked. + +## Returning a Value ## + +|`Return()`|Return from a `void` mock function.| +|:---------|:----------------------------------| +|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| +|`ReturnArg()`|Return the `N`-th (0-based) argument.| +|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| +|`ReturnNull()`|Return a null pointer. | +|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| +|`ReturnRef(variable)`|Return a reference to `variable`. | +|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| + +## Side Effects ## + +|`Assign(&variable, value)`|Assign `value` to variable.| +|:-------------------------|:--------------------------| +| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | +| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | +| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | +| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | +|`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| +|`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| +|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| +|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| +|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| + +## Using a Function or a Functor as an Action ## + +|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| +|:----------|:-----------------------------------------------------------------------------------------------------------------| +|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | +|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | +|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | +|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| + +The return value of the invoked function is used as the return value +of the action. + +When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: +``` + double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } + ... + EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); +``` + +In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, +``` + InvokeArgument<2>(5, string("Hi"), ByRef(foo)) +``` +calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. + +## Default Action ## + +|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| +|:------------|:--------------------------------------------------------------------| + +**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. + +## Composite Actions ## + +|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | +|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| +|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | +|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | +|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | +|`WithoutArgs(a)` |Perform action `a` without any arguments. | + +## Defining Actions ## + +| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | +|:--------------------------------------|:---------------------------------------------------------------------------------------| +| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | +| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | + +The `ACTION*` macros cannot be used inside a function or class. + +# Cardinalities # + +These are used in `Times()` to specify how many times a mock function will be called: + +|`AnyNumber()`|The function can be called any number of times.| +|:------------|:----------------------------------------------| +|`AtLeast(n)` |The call is expected at least `n` times. | +|`AtMost(n)` |The call is expected at most `n` times. | +|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| +|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| + +# Expectation Order # + +By default, the expectations can be matched in _any_ order. If some +or all expectations must be matched in a given order, there are two +ways to specify it. They can be used either independently or +together. + +## The After Clause ## + +``` +using ::testing::Expectation; +... +Expectation init_x = EXPECT_CALL(foo, InitX()); +Expectation init_y = EXPECT_CALL(foo, InitY()); +EXPECT_CALL(foo, Bar()) + .After(init_x, init_y); +``` +says that `Bar()` can be called only after both `InitX()` and +`InitY()` have been called. + +If you don't know how many pre-requisites an expectation has when you +write it, you can use an `ExpectationSet` to collect them: + +``` +using ::testing::ExpectationSet; +... +ExpectationSet all_inits; +for (int i = 0; i < element_count; i++) { + all_inits += EXPECT_CALL(foo, InitElement(i)); +} +EXPECT_CALL(foo, Bar()) + .After(all_inits); +``` +says that `Bar()` can be called only after all elements have been +initialized (but we don't care about which elements get initialized +before the others). + +Modifying an `ExpectationSet` after using it in an `.After()` doesn't +affect the meaning of the `.After()`. + +## Sequences ## + +When you have a long chain of sequential expectations, it's easier to +specify the order using **sequences**, which don't require you to given +each expectation in the chain a different name. All expected
+calls
in the same sequence must occur in the order they are +specified. + +``` +using ::testing::Sequence; +Sequence s1, s2; +... +EXPECT_CALL(foo, Reset()) + .InSequence(s1, s2) + .WillOnce(Return(true)); +EXPECT_CALL(foo, GetSize()) + .InSequence(s1) + .WillOnce(Return(1)); +EXPECT_CALL(foo, Describe(A())) + .InSequence(s2) + .WillOnce(Return("dummy")); +``` +says that `Reset()` must be called before _both_ `GetSize()` _and_ +`Describe()`, and the latter two can occur in any order. + +To put many expectations in a sequence conveniently: +``` +using ::testing::InSequence; +{ + InSequence dummy; + + EXPECT_CALL(...)...; + EXPECT_CALL(...)...; + ... + EXPECT_CALL(...)...; +} +``` +says that all expected calls in the scope of `dummy` must occur in +strict order. The name `dummy` is irrelevant.) + +# Verifying and Resetting a Mock # + +Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: +``` +using ::testing::Mock; +... +// Verifies and removes the expectations on mock_obj; +// returns true iff successful. +Mock::VerifyAndClearExpectations(&mock_obj); +... +// Verifies and removes the expectations on mock_obj; +// also removes the default actions set by ON_CALL(); +// returns true iff successful. +Mock::VerifyAndClear(&mock_obj); +``` + +You can also tell Google Mock that a mock object can be leaked and doesn't +need to be verified: +``` +Mock::AllowLeak(&mock_obj); +``` + +# Mock Classes # + +Google Mock defines a convenient mock class template +``` +class MockFunction { + public: + MOCK_METHODn(Call, R(A1, ..., An)); +}; +``` +See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Check_Points) for one application of it. + +# Flags # + +| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | +|:-------------------------------|:----------------------------------------------| +| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | \ No newline at end of file diff --git a/googlemock/docs/v1_6/CookBook.md b/googlemock/docs/v1_6/CookBook.md new file mode 100644 index 0000000..f5975a0 --- /dev/null +++ b/googlemock/docs/v1_6/CookBook.md @@ -0,0 +1,3342 @@ + + +You can find recipes for using Google Mock here. If you haven't yet, +please read the [ForDummies](V1_6_ForDummies.md) document first to make sure you understand +the basics. + +**Note:** Google Mock lives in the `testing` name space. For +readability, it is recommended to write `using ::testing::Foo;` once in +your file before using the name `Foo` defined by Google Mock. We omit +such `using` statements in this page for brevity, but you should do it +in your own code. + +# Creating Mock Classes # + +## Mocking Private or Protected Methods ## + +You must always put a mock method definition (`MOCK_METHOD*`) in a +`public:` section of the mock class, regardless of the method being +mocked being `public`, `protected`, or `private` in the base class. +This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function +from outside of the mock class. (Yes, C++ allows a subclass to change +the access level of a virtual function in the base class.) Example: + +``` +class Foo { + public: + ... + virtual bool Transform(Gadget* g) = 0; + + protected: + virtual void Resume(); + + private: + virtual int GetTimeOut(); +}; + +class MockFoo : public Foo { + public: + ... + MOCK_METHOD1(Transform, bool(Gadget* g)); + + // The following must be in the public section, even though the + // methods are protected or private in the base class. + MOCK_METHOD0(Resume, void()); + MOCK_METHOD0(GetTimeOut, int()); +}; +``` + +## Mocking Overloaded Methods ## + +You can mock overloaded functions as usual. No special attention is required: + +``` +class Foo { + ... + + // Must be virtual as we'll inherit from Foo. + virtual ~Foo(); + + // Overloaded on the types and/or numbers of arguments. + virtual int Add(Element x); + virtual int Add(int times, Element x); + + // Overloaded on the const-ness of this object. + virtual Bar& GetBar(); + virtual const Bar& GetBar() const; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Add, int(Element x)); + MOCK_METHOD2(Add, int(int times, Element x); + + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +``` + +**Note:** if you don't mock all versions of the overloaded method, the +compiler will give you a warning about some methods in the base class +being hidden. To fix that, use `using` to bring them in scope: + +``` +class MockFoo : public Foo { + ... + using Foo::Add; + MOCK_METHOD1(Add, int(Element x)); + // We don't want to mock int Add(int times, Element x); + ... +}; +``` + +## Mocking Class Templates ## + +To mock a class template, append `_T` to the `MOCK_*` macros: + +``` +template +class StackInterface { + ... + // Must be virtual as we'll inherit from StackInterface. + virtual ~StackInterface(); + + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; + +template +class MockStack : public StackInterface { + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Mocking Nonvirtual Methods ## + +Google Mock can mock non-virtual functions to be used in what we call _hi-perf +dependency injection_. + +In this case, instead of sharing a common base class with the real +class, your mock class will be _unrelated_ to the real class, but +contain methods with the same signatures. The syntax for mocking +non-virtual methods is the _same_ as mocking virtual methods: + +``` +// A simple packet stream class. None of its members is virtual. +class ConcretePacketStream { + public: + void AppendPacket(Packet* new_packet); + const Packet* GetPacket(size_t packet_number) const; + size_t NumberOfPackets() const; + ... +}; + +// A mock packet stream class. It inherits from no other, but defines +// GetPacket() and NumberOfPackets(). +class MockPacketStream { + public: + MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); + MOCK_CONST_METHOD0(NumberOfPackets, size_t()); + ... +}; +``` + +Note that the mock class doesn't define `AppendPacket()`, unlike the +real class. That's fine as long as the test doesn't need to call it. + +Next, you need a way to say that you want to use +`ConcretePacketStream` in production code, and use `MockPacketStream` +in tests. Since the functions are not virtual and the two classes are +unrelated, you must specify your choice at _compile time_ (as opposed +to run time). + +One way to do it is to templatize your code that needs to use a packet +stream. More specifically, you will give your code a template type +argument for the type of the packet stream. In production, you will +instantiate your template with `ConcretePacketStream` as the type +argument. In tests, you will instantiate the same template with +`MockPacketStream`. For example, you may write: + +``` +template +void CreateConnection(PacketStream* stream) { ... } + +template +class PacketReader { + public: + void ReadPackets(PacketStream* stream, size_t packet_num); +}; +``` + +Then you can use `CreateConnection()` and +`PacketReader` in production code, and use +`CreateConnection()` and +`PacketReader` in tests. + +``` + MockPacketStream mock_stream; + EXPECT_CALL(mock_stream, ...)...; + .. set more expectations on mock_stream ... + PacketReader reader(&mock_stream); + ... exercise reader ... +``` + +## Mocking Free Functions ## + +It's possible to use Google Mock to mock a free function (i.e. a +C-style function or a static method). You just need to rewrite your +code to use an interface (abstract class). + +Instead of calling a free function (say, `OpenFile`) directly, +introduce an interface for it and have a concrete subclass that calls +the free function: + +``` +class FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) = 0; +}; + +class File : public FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) { + return OpenFile(path, mode); + } +}; +``` + +Your code should talk to `FileInterface` to open a file. Now it's +easy to mock out the function. + +This may seem much hassle, but in practice you often have multiple +related functions that you can put in the same interface, so the +per-function syntactic overhead will be much lower. + +If you are concerned about the performance overhead incurred by +virtual functions, and profiling confirms your concern, you can +combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). + +## Nice Mocks and Strict Mocks ## + +If a mock method has no `EXPECT_CALL` spec but is called, Google Mock +will print a warning about the "uninteresting call". The rationale is: + + * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. + * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. + +However, sometimes you may want to suppress all "uninteresting call" +warnings, while sometimes you may want the opposite, i.e. to treat all +of them as errors. Google Mock lets you make the decision on a +per-mock-object basis. + +Suppose your test uses a mock class `MockFoo`: + +``` +TEST(...) { + MockFoo mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +If a method of `mock_foo` other than `DoThis()` is called, it will be +reported by Google Mock as a warning. However, if you rewrite your +test to use `NiceMock` instead, the warning will be gone, +resulting in a cleaner test output: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +`NiceMock` is a subclass of `MockFoo`, so it can be used +wherever `MockFoo` is accepted. + +It also works if `MockFoo`'s constructor takes some arguments, as +`NiceMock` "inherits" `MockFoo`'s constructors: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +The usage of `StrictMock` is similar, except that it makes all +uninteresting calls failures: + +``` +using ::testing::StrictMock; + +TEST(...) { + StrictMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... + + // The test will fail if a method of mock_foo other than DoThis() + // is called. +} +``` + +There are some caveats though (I don't like them just as much as the +next guy, but sadly they are side effects of C++'s limitations): + + 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. + 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). + 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) + +Finally, you should be **very cautious** when using this feature, as the +decision you make applies to **all** future changes to the mock +class. If an important change is made in the interface you are mocking +(and thus in the mock class), it could break your tests (if you use +`StrictMock`) or let bugs pass through without a warning (if you use +`NiceMock`). Therefore, try to specify the mock's behavior using +explicit `EXPECT_CALL` first, and only turn to `NiceMock` or +`StrictMock` as the last resort. + +## Simplifying the Interface without Breaking Existing Code ## + +Sometimes a method has a long list of arguments that is mostly +uninteresting. For example, + +``` +class LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const struct tm* tm_time, + const char* message, size_t message_len) = 0; +}; +``` + +This method's argument list is lengthy and hard to work with (let's +say that the `message` argument is not even 0-terminated). If we mock +it as is, using the mock will be awkward. If, however, we try to +simplify this interface, we'll need to fix all clients depending on +it, which is often infeasible. + +The trick is to re-dispatch the method in the mock class: + +``` +class ScopedMockLog : public LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, const tm* tm_time, + const char* message, size_t message_len) { + // We are only interested in the log severity, full file name, and + // log message. + Log(severity, full_filename, std::string(message, message_len)); + } + + // Implements the mock method: + // + // void Log(LogSeverity severity, + // const string& file_path, + // const string& message); + MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, + const string& message)); +}; +``` + +By defining a new mock method with a trimmed argument list, we make +the mock class much more user-friendly. + +## Alternative to Mocking Concrete Classes ## + +Often you may find yourself using classes that don't implement +interfaces. In order to test your code that uses such a class (let's +call it `Concrete`), you may be tempted to make the methods of +`Concrete` virtual and then mock it. + +Try not to do that. + +Making a non-virtual function virtual is a big decision. It creates an +extension point where subclasses can tweak your class' behavior. This +weakens your control on the class because now it's harder to maintain +the class' invariants. You should make a function virtual only when +there is a valid reason for a subclass to override it. + +Mocking concrete classes directly is problematic as it creates a tight +coupling between the class and the tests - any small change in the +class may invalidate your tests and make test maintenance a pain. + +To avoid such problems, many programmers have been practicing "coding +to interfaces": instead of talking to the `Concrete` class, your code +would define an interface and talk to it. Then you implement that +interface as an adaptor on top of `Concrete`. In tests, you can easily +mock that interface to observe how your code is doing. + +This technique incurs some overhead: + + * You pay the cost of virtual function calls (usually not a problem). + * There is more abstraction for the programmers to learn. + +However, it can also bring significant benefits in addition to better +testability: + + * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. + * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. + +Some people worry that if everyone is practicing this technique, they +will end up writing lots of redundant code. This concern is totally +understandable. However, there are two reasons why it may not be the +case: + + * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. + * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. + +You need to weigh the pros and cons carefully for your particular +problem, but I'd like to assure you that the Java community has been +practicing this for a long time and it's a proven effective technique +applicable in a wide variety of situations. :-) + +## Delegating Calls to a Fake ## + +Some times you have a non-trivial fake implementation of an +interface. For example: + +``` +class Foo { + public: + virtual ~Foo() {} + virtual char DoThis(int n) = 0; + virtual void DoThat(const char* s, int* p) = 0; +}; + +class FakeFoo : public Foo { + public: + virtual char DoThis(int n) { + return (n > 0) ? '+' : + (n < 0) ? '-' : '0'; + } + + virtual void DoThat(const char* s, int* p) { + *p = strlen(s); + } +}; +``` + +Now you want to mock this interface such that you can set expectations +on it. However, you also want to use `FakeFoo` for the default +behavior, as duplicating it in the mock object is, well, a lot of +work. + +When you define the mock class using Google Mock, you can have it +delegate its default action to a fake class you already have, using +this pattern: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + // Normal mock method definitions using Google Mock. + MOCK_METHOD1(DoThis, char(int n)); + MOCK_METHOD2(DoThat, void(const char* s, int* p)); + + // Delegates the default actions of the methods to a FakeFoo object. + // This must be called *before* the custom ON_CALL() statements. + void DelegateToFake() { + ON_CALL(*this, DoThis(_)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); + ON_CALL(*this, DoThat(_, _)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); + } + private: + FakeFoo fake_; // Keeps an instance of the fake in the mock. +}; +``` + +With that, you can use `MockFoo` in your tests as usual. Just remember +that if you don't explicitly set an action in an `ON_CALL()` or +`EXPECT_CALL()`, the fake will be called upon to do it: + +``` +using ::testing::_; + +TEST(AbcTest, Xyz) { + MockFoo foo; + foo.DelegateToFake(); // Enables the fake for delegation. + + // Put your ON_CALL(foo, ...)s here, if any. + + // No action specified, meaning to use the default action. + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(foo, DoThat(_, _)); + + int n = 0; + EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. + foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. + EXPECT_EQ(2, n); +} +``` + +**Some tips:** + + * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. + * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. + * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. + * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. + +Regarding the tip on mixing a mock and a fake, here's an example on +why it may be a bad sign: Suppose you have a class `System` for +low-level system operations. In particular, it does file and I/O +operations. And suppose you want to test how your code uses `System` +to do I/O, and you just want the file operations to work normally. If +you mock out the entire `System` class, you'll have to provide a fake +implementation for the file operation part, which suggests that +`System` is taking on too many roles. + +Instead, you can define a `FileOps` interface and an `IOOps` interface +and split `System`'s functionalities into the two. Then you can mock +`IOOps` without mocking `FileOps`. + +## Delegating Calls to a Real Object ## + +When using testing doubles (mocks, fakes, stubs, and etc), sometimes +their behaviors will differ from those of the real objects. This +difference could be either intentional (as in simulating an error such +that you can test the error handling code) or unintentional. If your +mocks have different behaviors than the real objects by mistake, you +could end up with code that passes the tests but fails in production. + +You can use the _delegating-to-real_ technique to ensure that your +mock has the same behavior as the real object while retaining the +ability to validate calls. This technique is very similar to the +delegating-to-fake technique, the difference being that we use a real +object instead of a fake. Here's an example: + +``` +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MockFoo() { + // By default, all calls are delegated to the real object. + ON_CALL(*this, DoThis()) + .WillByDefault(Invoke(&real_, &Foo::DoThis)); + ON_CALL(*this, DoThat(_)) + .WillByDefault(Invoke(&real_, &Foo::DoThat)); + ... + } + MOCK_METHOD0(DoThis, ...); + MOCK_METHOD1(DoThat, ...); + ... + private: + Foo real_; +}; +... + + MockFoo mock; + + EXPECT_CALL(mock, DoThis()) + .Times(3); + EXPECT_CALL(mock, DoThat("Hi")) + .Times(AtLeast(1)); + ... use mock in test ... +``` + +With this, Google Mock will verify that your code made the right calls +(with the right arguments, in the right order, called the right number +of times, etc), and a real object will answer the calls (so the +behavior will be the same as in production). This gives you the best +of both worlds. + +## Delegating Calls to a Parent Class ## + +Ideally, you should code to interfaces, whose methods are all pure +virtual. In reality, sometimes you do need to mock a virtual method +that is not pure (i.e, it already has an implementation). For example: + +``` +class Foo { + public: + virtual ~Foo(); + + virtual void Pure(int n) = 0; + virtual int Concrete(const char* str) { ... } +}; + +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); +}; +``` + +Sometimes you may want to call `Foo::Concrete()` instead of +`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub +action, or perhaps your test doesn't need to mock `Concrete()` at all +(but it would be oh-so painful to have to define a new mock class +whenever you don't need to mock one of its methods). + +The trick is to leave a back door in your mock class for accessing the +real methods in the base class: + +``` +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); + + // Use this to call Concrete() defined in Foo. + int FooConcrete(const char* str) { return Foo::Concrete(str); } +}; +``` + +Now, you can call `Foo::Concrete()` inside an action by: + +``` +using ::testing::_; +using ::testing::Invoke; +... + EXPECT_CALL(foo, Concrete(_)) + .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +or tell the mock object that you don't want to mock `Concrete()`: + +``` +using ::testing::Invoke; +... + ON_CALL(foo, Concrete(_)) + .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do +that, `MockFoo::Concrete()` will be called (and cause an infinite +recursion) since `Foo::Concrete()` is virtual. That's just how C++ +works.) + +# Using Matchers # + +## Matching Argument Values Exactly ## + +You can specify exactly which arguments a mock method is expecting: + +``` +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(5)) + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", bar)); +``` + +## Using Simple Matchers ## + +You can use matchers to match arguments that have a certain property: + +``` +using ::testing::Ge; +using ::testing::NotNull; +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", NotNull())); + // The second argument must not be NULL. +``` + +A frequently used matcher is `_`, which matches anything: + +``` +using ::testing::_; +using ::testing::NotNull; +... + EXPECT_CALL(foo, DoThat(_, NotNull())); +``` + +## Combining Matchers ## + +You can build complex matchers from existing ones using `AllOf()`, +`AnyOf()`, and `Not()`: + +``` +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::HasSubstr; +using ::testing::Ne; +using ::testing::Not; +... + // The argument must be > 5 and != 10. + EXPECT_CALL(foo, DoThis(AllOf(Gt(5), + Ne(10)))); + + // The first argument must not contain sub-string "blah". + EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), + NULL)); +``` + +## Casting Matchers ## + +Google Mock matchers are statically typed, meaning that the compiler +can catch your mistake if you use a matcher of the wrong type (for +example, if you use `Eq(5)` to match a `string` argument). Good for +you! + +Sometimes, however, you know what you're doing and want the compiler +to give you some slack. One example is that you have a matcher for +`long` and the argument you want to match is `int`. While the two +types aren't exactly the same, there is nothing really wrong with +using a `Matcher` to match an `int` - after all, we can first +convert the `int` argument to a `long` before giving it to the +matcher. + +To support this need, Google Mock gives you the +`SafeMatcherCast(m)` function. It casts a matcher `m` to type +`Matcher`. To ensure safety, Google Mock checks that (let `U` be the +type `m` accepts): + + 1. Type `T` can be implicitly cast to type `U`; + 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and + 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). + +The code won't compile if any of these conditions isn't met. + +Here's one example: + +``` +using ::testing::SafeMatcherCast; + +// A base class and a child class. +class Base { ... }; +class Derived : public Base { ... }; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(DoThis, void(Derived* derived)); +}; +... + + MockFoo foo; + // m is a Matcher we got from somewhere. + EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); +``` + +If you find `SafeMatcherCast(m)` too limiting, you can use a similar +function `MatcherCast(m)`. The difference is that `MatcherCast` works +as long as you can `static_cast` type `T` to type `U`. + +`MatcherCast` essentially lets you bypass C++'s type system +(`static_cast` isn't always safe as it could throw away information, +for example), so be careful not to misuse/abuse it. + +## Selecting Between Overloaded Functions ## + +If you expect an overloaded function to be called, the compiler may +need some help on which overloaded version it is. + +To disambiguate functions overloaded on the const-ness of this object, +use the `Const()` argument wrapper. + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + ... + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +... + + MockFoo foo; + Bar bar1, bar2; + EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). + .WillOnce(ReturnRef(bar1)); + EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). + .WillOnce(ReturnRef(bar2)); +``` + +(`Const()` is defined by Google Mock and returns a `const` reference +to its argument.) + +To disambiguate overloaded functions with the same number of arguments +but different argument types, you may need to specify the exact type +of a matcher, either by wrapping your matcher in `Matcher()`, or +using a matcher whose type is fixed (`TypedEq`, `An()`, +etc): + +``` +using ::testing::An; +using ::testing::Lt; +using ::testing::Matcher; +using ::testing::TypedEq; + +class MockPrinter : public Printer { + public: + MOCK_METHOD1(Print, void(int n)); + MOCK_METHOD1(Print, void(char c)); +}; + +TEST(PrinterTest, Print) { + MockPrinter printer; + + EXPECT_CALL(printer, Print(An())); // void Print(int); + EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); + EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); + + printer.Print(3); + printer.Print(6); + printer.Print('a'); +} +``` + +## Performing Different Actions Based on the Arguments ## + +When a mock method is called, the _last_ matching expectation that's +still active will be selected (think "newer overrides older"). So, you +can make a method do different things depending on its argument values +like this: + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Return; +... + // The default case. + EXPECT_CALL(foo, DoThis(_)) + .WillRepeatedly(Return('b')); + + // The more specific case. + EXPECT_CALL(foo, DoThis(Lt(5))) + .WillRepeatedly(Return('a')); +``` + +Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will +be returned; otherwise `'b'` will be returned. + +## Matching Multiple Arguments as a Whole ## + +Sometimes it's not enough to match the arguments individually. For +example, we may want to say that the first argument must be less than +the second argument. The `With()` clause allows us to match +all arguments of a mock function as a whole. For example, + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Ne; +... + EXPECT_CALL(foo, InRange(Ne(0), _)) + .With(Lt()); +``` + +says that the first argument of `InRange()` must not be 0, and must be +less than the second argument. + +The expression inside `With()` must be a matcher of type +`Matcher >`, where `A1`, ..., `An` are the +types of the function arguments. + +You can also write `AllArgs(m)` instead of `m` inside `.With()`. The +two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable +than `.With(Lt())`. + +You can use `Args(m)` to match the `n` selected arguments +(as a tuple) against `m`. For example, + +``` +using ::testing::_; +using ::testing::AllOf; +using ::testing::Args; +using ::testing::Lt; +... + EXPECT_CALL(foo, Blah(_, _, _)) + .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); +``` + +says that `Blah()` will be called with arguments `x`, `y`, and `z` where +`x < y < z`. + +As a convenience and example, Google Mock provides some matchers for +2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_6_CheatSheet.md) for +the complete list. + +Note that if you want to pass the arguments to a predicate of your own +(e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be +written to take a `tr1::tuple` as its argument; Google Mock will pass the `n` +selected arguments as _one_ single tuple to the predicate. + +## Using Matchers as Predicates ## + +Have you noticed that a matcher is just a fancy predicate that also +knows how to describe itself? Many existing algorithms take predicates +as arguments (e.g. those defined in STL's `` header), and +it would be a shame if Google Mock matchers are not allowed to +participate. + +Luckily, you can use a matcher where a unary predicate functor is +expected by wrapping it inside the `Matches()` function. For example, + +``` +#include +#include + +std::vector v; +... +// How many elements in v are >= 10? +const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); +``` + +Since you can build complex matchers from simpler ones easily using +Google Mock, this gives you a way to conveniently construct composite +predicates (doing the same using STL's `` header is just +painful). For example, here's a predicate that's satisfied by any +number that is >= 0, <= 100, and != 50: + +``` +Matches(AllOf(Ge(0), Le(100), Ne(50))) +``` + +## Using Matchers in Google Test Assertions ## + +Since matchers are basically predicates that also know how to describe +themselves, there is a way to take advantage of them in +[Google Test](http://code.google.com/p/googletest/) assertions. It's +called `ASSERT_THAT` and `EXPECT_THAT`: + +``` + ASSERT_THAT(value, matcher); // Asserts that value matches matcher. + EXPECT_THAT(value, matcher); // The non-fatal version. +``` + +For example, in a Google Test test you can write: + +``` +#include "gmock/gmock.h" + +using ::testing::AllOf; +using ::testing::Ge; +using ::testing::Le; +using ::testing::MatchesRegex; +using ::testing::StartsWith; +... + + EXPECT_THAT(Foo(), StartsWith("Hello")); + EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); + ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); +``` + +which (as you can probably guess) executes `Foo()`, `Bar()`, and +`Baz()`, and verifies that: + + * `Foo()` returns a string that starts with `"Hello"`. + * `Bar()` returns a string that matches regular expression `"Line \\d+"`. + * `Baz()` returns a number in the range [5, 10]. + +The nice thing about these macros is that _they read like +English_. They generate informative messages too. For example, if the +first `EXPECT_THAT()` above fails, the message will be something like: + +``` +Value of: Foo() + Actual: "Hi, world!" +Expected: starts with "Hello" +``` + +**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the +[Hamcrest](http://code.google.com/p/hamcrest/) project, which adds +`assertThat()` to JUnit. + +## Using Predicates as Matchers ## + +Google Mock provides a built-in set of matchers. In case you find them +lacking, you can use an arbitray unary predicate function or functor +as a matcher - as long as the predicate accepts a value of the type +you want. You do this by wrapping the predicate inside the `Truly()` +function, for example: + +``` +using ::testing::Truly; + +int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } +... + + // Bar() must be called with an even number. + EXPECT_CALL(foo, Bar(Truly(IsEven))); +``` + +Note that the predicate function / functor doesn't have to return +`bool`. It works as long as the return value can be used as the +condition in statement `if (condition) ...`. + +## Matching Arguments that Are Not Copyable ## + +When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves +away a copy of `bar`. When `Foo()` is called later, Google Mock +compares the argument to `Foo()` with the saved copy of `bar`. This +way, you don't need to worry about `bar` being modified or destroyed +after the `EXPECT_CALL()` is executed. The same is true when you use +matchers like `Eq(bar)`, `Le(bar)`, and so on. + +But what if `bar` cannot be copied (i.e. has no copy constructor)? You +could define your own matcher function and use it with `Truly()`, as +the previous couple of recipes have shown. Or, you may be able to get +away from it if you can guarantee that `bar` won't be changed after +the `EXPECT_CALL()` is executed. Just tell Google Mock that it should +save a reference to `bar`, instead of a copy of it. Here's how: + +``` +using ::testing::Eq; +using ::testing::ByRef; +using ::testing::Lt; +... + // Expects that Foo()'s argument == bar. + EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); + + // Expects that Foo()'s argument < bar. + EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); +``` + +Remember: if you do this, don't change `bar` after the +`EXPECT_CALL()`, or the result is undefined. + +## Validating a Member of an Object ## + +Often a mock function takes a reference to object as an argument. When +matching the argument, you may not want to compare the entire object +against a fixed object, as that may be over-specification. Instead, +you may need to validate a certain member variable or the result of a +certain getter method of the object. You can do this with `Field()` +and `Property()`. More specifically, + +``` +Field(&Foo::bar, m) +``` + +is a matcher that matches a `Foo` object whose `bar` member variable +satisfies matcher `m`. + +``` +Property(&Foo::baz, m) +``` + +is a matcher that matches a `Foo` object whose `baz()` method returns +a value that satisfies matcher `m`. + +For example: + +> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | +|:-----------------------------|:-----------------------------------| +> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | + +Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no +argument and be declared as `const`. + +BTW, `Field()` and `Property()` can also match plain pointers to +objects. For instance, + +``` +Field(&Foo::number, Ge(3)) +``` + +matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, +the match will always fail regardless of the inner matcher. + +What if you want to validate more than one members at the same time? +Remember that there is `AllOf()`. + +## Validating the Value Pointed to by a Pointer Argument ## + +C++ functions often take pointers as arguments. You can use matchers +like `NULL`, `NotNull()`, and other comparison matchers to match a +pointer, but what if you want to make sure the value _pointed to_ by +the pointer, instead of the pointer itself, has a certain property? +Well, you can use the `Pointee(m)` matcher. + +`Pointee(m)` matches a pointer iff `m` matches the value the pointer +points to. For example: + +``` +using ::testing::Ge; +using ::testing::Pointee; +... + EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); +``` + +expects `foo.Bar()` to be called with a pointer that points to a value +greater than or equal to 3. + +One nice thing about `Pointee()` is that it treats a `NULL` pointer as +a match failure, so you can write `Pointee(m)` instead of + +``` + AllOf(NotNull(), Pointee(m)) +``` + +without worrying that a `NULL` pointer will crash your test. + +Also, did we tell you that `Pointee()` works with both raw pointers +**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and +etc)? + +What if you have a pointer to pointer? You guessed it - you can use +nested `Pointee()` to probe deeper inside the value. For example, +`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer +that points to a number less than 3 (what a mouthful...). + +## Testing a Certain Property of an Object ## + +Sometimes you want to specify that an object argument has a certain +property, but there is no existing matcher that does this. If you want +good error messages, you should define a matcher. If you want to do it +quick and dirty, you could get away with writing an ordinary function. + +Let's say you have a mock function that takes an object of type `Foo`, +which has an `int bar()` method and an `int baz()` method, and you +want to constrain that the argument's `bar()` value plus its `baz()` +value is a given number. Here's how you can define a matcher to do it: + +``` +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class BarPlusBazEqMatcher : public MatcherInterface { + public: + explicit BarPlusBazEqMatcher(int expected_sum) + : expected_sum_(expected_sum) {} + + virtual bool MatchAndExplain(const Foo& foo, + MatchResultListener* listener) const { + return (foo.bar() + foo.baz()) == expected_sum_; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "bar() + baz() equals " << expected_sum_; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "bar() + baz() does not equal " << expected_sum_; + } + private: + const int expected_sum_; +}; + +inline Matcher BarPlusBazEq(int expected_sum) { + return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); +} + +... + + EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; +``` + +## Matching Containers ## + +Sometimes an STL container (e.g. list, vector, map, ...) is passed to +a mock function and you may want to validate it. Since most STL +containers support the `==` operator, you can write +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. + +Sometimes, though, you may want to be more flexible (for example, the +first element must be an exact match, but the second element can be +any positive number, and so on). Also, containers used in tests often +have a small number of elements, and having to define the expected +container out-of-line is a bit of a hassle. + +You can use the `ElementsAre()` matcher in such cases: + +``` +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Gt; +... + + MOCK_METHOD1(Foo, void(const vector& numbers)); +... + + EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); +``` + +The above matcher says that the container must have 4 elements, which +must be 1, greater than 0, anything, and 5 respectively. + +`ElementsAre()` is overloaded to take 0 to 10 arguments. If more are +needed, you can place them in a C-style array and use +`ElementsAreArray()` instead: + +``` +using ::testing::ElementsAreArray; +... + + // ElementsAreArray accepts an array of element values. + const int expected_vector1[] = { 1, 5, 2, 4, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); + + // Or, an array of element matchers. + Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); +``` + +In case the array needs to be dynamically created (and therefore the +array size cannot be inferred by the compiler), you can give +`ElementsAreArray()` an additional argument to specify the array size: + +``` +using ::testing::ElementsAreArray; +... + int* const expected_vector3 = new int[count]; + ... fill expected_vector3 with values ... + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); +``` + +**Tips:** + + * `ElementAre*()` works with _any_ container that implements the STL iterator concept (i.e. it has a `const_iterator` type and supports `begin()/end()`) and supports `size()`, not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. + * You can use nested `ElementAre*()` to match nested (multi-dimensional) containers. + * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. + * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). + +## Sharing Matchers ## + +Under the hood, a Google Mock matcher object consists of a pointer to +a ref-counted implementation object. Copying matchers is allowed and +very efficient, as only the pointer is copied. When the last matcher +that references the implementation object dies, the implementation +object will be deleted. + +Therefore, if you have some complex matcher that you want to use again +and again, there is no need to build it everytime. Just assign it to a +matcher variable and use that variable repeatedly! For example, + +``` + Matcher in_range = AllOf(Gt(5), Le(10)); + ... use in_range as a matcher in multiple EXPECT_CALLs ... +``` + +# Setting Expectations # + +## Ignoring Uninteresting Calls ## + +If you are not interested in how a mock method is called, just don't +say anything about it. In this case, if the method is ever called, +Google Mock will perform its default action to allow the test program +to continue. If you are not happy with the default action taken by +Google Mock, you can override it using `DefaultValue::Set()` +(described later in this document) or `ON_CALL()`. + +Please note that once you expressed interest in a particular mock +method (via `EXPECT_CALL()`), all invocations to it must match some +expectation. If this function is called but the arguments don't match +any `EXPECT_CALL()` statement, it will be an error. + +## Disallowing Unexpected Calls ## + +If a mock method shouldn't be called at all, explicitly say so: + +``` +using ::testing::_; +... + EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +If some calls to the method are allowed, but the rest are not, just +list all the expected calls: + +``` +using ::testing::AnyNumber; +using ::testing::Gt; +... + EXPECT_CALL(foo, Bar(5)); + EXPECT_CALL(foo, Bar(Gt(10))) + .Times(AnyNumber()); +``` + +A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` +statements will be an error. + +## Expecting Ordered Calls ## + +Although an `EXPECT_CALL()` statement defined earlier takes precedence +when Google Mock tries to match a function call with an expectation, +by default calls don't have to happen in the order `EXPECT_CALL()` +statements are written. For example, if the arguments match the +matchers in the third `EXPECT_CALL()`, but not those in the first two, +then the third expectation will be used. + +If you would rather have all calls occur in the order of the +expectations, put the `EXPECT_CALL()` statements in a block where you +define a variable of type `InSequence`: + +``` + using ::testing::_; + using ::testing::InSequence; + + { + InSequence s; + + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(bar, DoThat(_)) + .Times(2); + EXPECT_CALL(foo, DoThis(6)); + } +``` + +In this example, we expect a call to `foo.DoThis(5)`, followed by two +calls to `bar.DoThat()` where the argument can be anything, which are +in turn followed by a call to `foo.DoThis(6)`. If a call occurred +out-of-order, Google Mock will report an error. + +## Expecting Partially Ordered Calls ## + +Sometimes requiring everything to occur in a predetermined order can +lead to brittle tests. For example, we may care about `A` occurring +before both `B` and `C`, but aren't interested in the relative order +of `B` and `C`. In this case, the test should reflect our real intent, +instead of being overly constraining. + +Google Mock allows you to impose an arbitrary DAG (directed acyclic +graph) on the calls. One way to express the DAG is to use the +[After](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#The_After_Clause) clause of `EXPECT_CALL`. + +Another way is via the `InSequence()` clause (not the same as the +`InSequence` class), which we borrowed from jMock 2. It's less +flexible than `After()`, but more convenient when you have long chains +of sequential calls, as it doesn't require you to come up with +different names for the expectations in the chains. Here's how it +works: + +If we view `EXPECT_CALL()` statements as nodes in a graph, and add an +edge from node A to node B wherever A must occur before B, we can get +a DAG. We use the term "sequence" to mean a directed path in this +DAG. Now, if we decompose the DAG into sequences, we just need to know +which sequences each `EXPECT_CALL()` belongs to in order to be able to +reconstruct the orginal DAG. + +So, to specify the partial order on the expectations we need to do two +things: first to define some `Sequence` objects, and then for each +`EXPECT_CALL()` say which `Sequence` objects it is part +of. Expectations in the same sequence must occur in the order they are +written. For example, + +``` + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(foo, A()) + .InSequence(s1, s2); + EXPECT_CALL(bar, B()) + .InSequence(s1); + EXPECT_CALL(bar, C()) + .InSequence(s2); + EXPECT_CALL(foo, D()) + .InSequence(s2); +``` + +specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> +C -> D`): + +``` + +---> B + | + A ---| + | + +---> C ---> D +``` + +This means that A must occur before B and C, and C must occur before +D. There's no restriction about the order other than these. + +## Controlling When an Expectation Retires ## + +When a mock method is called, Google Mock only consider expectations +that are still active. An expectation is active when created, and +becomes inactive (aka _retires_) when a call that has to occur later +has occurred. For example, in + +``` + using ::testing::_; + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 + .Times(AnyNumber()) + .InSequence(s1, s2); + EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 + .InSequence(s1); + EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 + .InSequence(s2); +``` + +as soon as either #2 or #3 is matched, #1 will retire. If a warning +`"File too large."` is logged after this, it will be an error. + +Note that an expectation doesn't retire automatically when it's +saturated. For example, + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 +``` + +says that there will be exactly one warning with the message `"File +too large."`. If the second warning contains this message too, #2 will +match again and result in an upper-bound-violated error. + +If this is not what you want, you can ask an expectation to retire as +soon as it becomes saturated: + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 + .RetiresOnSaturation(); +``` + +Here #2 can be used only once, so if you have two warnings with the +message `"File too large."`, the first will match #2 and the second +will match #1 - there will be no error. + +# Using Actions # + +## Returning References from Mock Methods ## + +If a mock function's return type is a reference, you need to use +`ReturnRef()` instead of `Return()` to return a result: + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetBar, Bar&()); +}; +... + + MockFoo foo; + Bar bar; + EXPECT_CALL(foo, GetBar()) + .WillOnce(ReturnRef(bar)); +``` + +## Returning Live Values from Mock Methods ## + +The `Return(x)` action saves a copy of `x` when the action is +_created_, and always returns the same value whenever it's +executed. Sometimes you may want to instead return the _live_ value of +`x` (i.e. its value at the time when the action is _executed_.). + +If the mock function's return type is a reference, you can do it using +`ReturnRef(x)`, as shown in the previous recipe ("Returning References +from Mock Methods"). However, Google Mock doesn't let you use +`ReturnRef()` in a mock function whose return type is not a reference, +as doing that usually indicates a user error. So, what shall you do? + +You may be tempted to try `ByRef()`: + +``` +using testing::ByRef; +using testing::Return; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetValue, int()); +}; +... + int x = 0; + MockFoo foo; + EXPECT_CALL(foo, GetValue()) + .WillRepeatedly(Return(ByRef(x))); + x = 42; + EXPECT_EQ(42, foo.GetValue()); +``` + +Unfortunately, it doesn't work here. The above code will fail with error: + +``` +Value of: foo.GetValue() + Actual: 0 +Expected: 42 +``` + +The reason is that `Return(value)` converts `value` to the actual +return type of the mock function at the time when the action is +_created_, not when it is _executed_. (This behavior was chosen for +the action to be safe when `value` is a proxy object that references +some temporary objects.) As a result, `ByRef(x)` is converted to an +`int` value (instead of a `const int&`) when the expectation is set, +and `Return(ByRef(x))` will always return 0. + +`ReturnPointee(pointer)` was provided to solve this problem +specifically. It returns the value pointed to by `pointer` at the time +the action is _executed_: + +``` +using testing::ReturnPointee; +... + int x = 0; + MockFoo foo; + EXPECT_CALL(foo, GetValue()) + .WillRepeatedly(ReturnPointee(&x)); // Note the & here. + x = 42; + EXPECT_EQ(42, foo.GetValue()); // This will succeed now. +``` + +## Combining Actions ## + +Want to do more than one thing when a function is called? That's +fine. `DoAll()` allow you to do sequence of actions every time. Only +the return value of the last action in the sequence will be used. + +``` +using ::testing::DoAll; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Bar, bool(int n)); +}; +... + + EXPECT_CALL(foo, Bar(_)) + .WillOnce(DoAll(action_1, + action_2, + ... + action_n)); +``` + +## Mocking Side Effects ## + +Sometimes a method exhibits its effect not via returning a value but +via side effects. For example, it may change some global state or +modify an output argument. To mock side effects, in general you can +define your own action by implementing `::testing::ActionInterface`. + +If all you need to do is to change an output argument, the built-in +`SetArgPointee()` action is convenient: + +``` +using ::testing::SetArgPointee; + +class MockMutator : public Mutator { + public: + MOCK_METHOD2(Mutate, void(bool mutate, int* value)); + ... +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, Mutate(true, _)) + .WillOnce(SetArgPointee<1>(5)); +``` + +In this example, when `mutator.Mutate()` is called, we will assign 5 +to the `int` variable pointed to by argument #1 +(0-based). + +`SetArgPointee()` conveniently makes an internal copy of the +value you pass to it, removing the need to keep the value in scope and +alive. The implication however is that the value must have a copy +constructor and assignment operator. + +If the mock method also needs to return a value as well, you can chain +`SetArgPointee()` with `Return()` using `DoAll()`: + +``` +using ::testing::_; +using ::testing::Return; +using ::testing::SetArgPointee; + +class MockMutator : public Mutator { + public: + ... + MOCK_METHOD1(MutateInt, bool(int* value)); +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, MutateInt(_)) + .WillOnce(DoAll(SetArgPointee<0>(5), + Return(true))); +``` + +If the output argument is an array, use the +`SetArrayArgument(first, last)` action instead. It copies the +elements in source range `[first, last)` to the array pointed to by +the `N`-th (0-based) argument: + +``` +using ::testing::NotNull; +using ::testing::SetArrayArgument; + +class MockArrayMutator : public ArrayMutator { + public: + MOCK_METHOD2(Mutate, void(int* values, int num_values)); + ... +}; +... + + MockArrayMutator mutator; + int values[5] = { 1, 2, 3, 4, 5 }; + EXPECT_CALL(mutator, Mutate(NotNull(), 5)) + .WillOnce(SetArrayArgument<0>(values, values + 5)); +``` + +This also works when the argument is an output iterator: + +``` +using ::testing::_; +using ::testing::SeArrayArgument; + +class MockRolodex : public Rolodex { + public: + MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); + ... +}; +... + + MockRolodex rolodex; + vector names; + names.push_back("George"); + names.push_back("John"); + names.push_back("Thomas"); + EXPECT_CALL(rolodex, GetNames(_)) + .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); +``` + +## Changing a Mock Object's Behavior Based on the State ## + +If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: + +``` +using ::testing::InSequence; +using ::testing::Return; + +... + { + InSequence seq; + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(my_mock, Flush()); + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(false)); + } + my_mock.FlushIfDirty(); +``` + +This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. + +If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: + +``` +using ::testing::_; +using ::testing::SaveArg; +using ::testing::Return; + +ACTION_P(ReturnPointee, p) { return *p; } +... + int previous_value = 0; + EXPECT_CALL(my_mock, GetPrevValue()) + .WillRepeatedly(ReturnPointee(&previous_value)); + EXPECT_CALL(my_mock, UpdateValue(_)) + .WillRepeatedly(SaveArg<0>(&previous_value)); + my_mock.DoSomethingToUpdateValue(); +``` + +Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. + +## Setting the Default Value for a Return Type ## + +If a mock method's return type is a built-in C++ type or pointer, by +default it will return 0 when invoked. You only need to specify an +action if this default value doesn't work for you. + +Sometimes, you may want to change this default value, or you may want +to specify a default value for types Google Mock doesn't know +about. You can do this using the `::testing::DefaultValue` class +template: + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD0(CalculateBar, Bar()); +}; +... + + Bar default_bar; + // Sets the default return value for type Bar. + DefaultValue::Set(default_bar); + + MockFoo foo; + + // We don't need to specify an action here, as the default + // return value works for us. + EXPECT_CALL(foo, CalculateBar()); + + foo.CalculateBar(); // This should return default_bar. + + // Unsets the default return value. + DefaultValue::Clear(); +``` + +Please note that changing the default value for a type can make you +tests hard to understand. We recommend you to use this feature +judiciously. For example, you may want to make sure the `Set()` and +`Clear()` calls are right next to the code that uses your mock. + +## Setting the Default Actions for a Mock Method ## + +You've learned how to change the default value of a given +type. However, this may be too coarse for your purpose: perhaps you +have two mock methods with the same return type and you want them to +have different behaviors. The `ON_CALL()` macro allows you to +customize your mock's behavior at the method level: + +``` +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Gt; +using ::testing::Return; +... + ON_CALL(foo, Sign(_)) + .WillByDefault(Return(-1)); + ON_CALL(foo, Sign(0)) + .WillByDefault(Return(0)); + ON_CALL(foo, Sign(Gt(0))) + .WillByDefault(Return(1)); + + EXPECT_CALL(foo, Sign(_)) + .Times(AnyNumber()); + + foo.Sign(5); // This should return 1. + foo.Sign(-9); // This should return -1. + foo.Sign(0); // This should return 0. +``` + +As you may have guessed, when there are more than one `ON_CALL()` +statements, the news order take precedence over the older ones. In +other words, the **last** one that matches the function arguments will +be used. This matching order allows you to set up the common behavior +in a mock object's constructor or the test fixture's set-up phase and +specialize the mock's behavior later. + +## Using Functions/Methods/Functors as Actions ## + +If the built-in actions don't suit you, you can easily use an existing +function, method, or functor as an action: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(Sum, int(int x, int y)); + MOCK_METHOD1(ComplexJob, bool(int x)); +}; + +int CalculateSum(int x, int y) { return x + y; } + +class Helper { + public: + bool ComplexJob(int x); +}; +... + + MockFoo foo; + Helper helper; + EXPECT_CALL(foo, Sum(_, _)) + .WillOnce(Invoke(CalculateSum)); + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(Invoke(&helper, &Helper::ComplexJob)); + + foo.Sum(5, 6); // Invokes CalculateSum(5, 6). + foo.ComplexJob(10); // Invokes helper.ComplexJob(10); +``` + +The only requirement is that the type of the function, etc must be +_compatible_ with the signature of the mock function, meaning that the +latter's arguments can be implicitly converted to the corresponding +arguments of the former, and the former's return type can be +implicitly converted to that of the latter. So, you can invoke +something whose type is _not_ exactly the same as the mock function, +as long as it's safe to do so - nice, huh? + +## Invoking a Function/Method/Functor Without Arguments ## + +`Invoke()` is very useful for doing actions that are more complex. It +passes the mock function's arguments to the function or functor being +invoked such that the callee has the full context of the call to work +with. If the invoked function is not interested in some or all of the +arguments, it can simply ignore them. + +Yet, a common pattern is that a test author wants to invoke a function +without the arguments of the mock function. `Invoke()` allows her to +do that using a wrapper function that throws away the arguments before +invoking an underlining nullary function. Needless to say, this can be +tedious and obscures the intent of the test. + +`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except +that it doesn't pass the mock function's arguments to the +callee. Here's an example: + +``` +using ::testing::_; +using ::testing::InvokeWithoutArgs; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(ComplexJob, bool(int n)); +}; + +bool Job1() { ... } +... + + MockFoo foo; + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(InvokeWithoutArgs(Job1)); + + foo.ComplexJob(10); // Invokes Job1(). +``` + +## Invoking an Argument of the Mock Function ## + +Sometimes a mock function will receive a function pointer or a functor +(in other words, a "callable") as an argument, e.g. + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); +}; +``` + +and you may want to invoke this callable argument: + +``` +using ::testing::_; +... + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(...); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +Arghh, you need to refer to a mock function argument but C++ has no +lambda (yet), so you have to define your own action. :-( Or do you +really? + +Well, Google Mock has an action to solve _exactly_ this problem: + +``` + InvokeArgument(arg_1, arg_2, ..., arg_m) +``` + +will invoke the `N`-th (0-based) argument the mock function receives, +with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is +a function pointer or a functor, Google Mock handles them both. + +With that, you could write: + +``` +using ::testing::_; +using ::testing::InvokeArgument; +... + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(InvokeArgument<1>(5)); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +What if the callable takes an argument by reference? No problem - just +wrap it inside `ByRef()`: + +``` +... + MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); +... +using ::testing::_; +using ::testing::ByRef; +using ::testing::InvokeArgument; +... + + MockFoo foo; + Helper helper; + ... + EXPECT_CALL(foo, Bar(_)) + .WillOnce(InvokeArgument<0>(5, ByRef(helper))); + // ByRef(helper) guarantees that a reference to helper, not a copy of it, + // will be passed to the callable. +``` + +What if the callable takes an argument by reference and we do **not** +wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a +copy_ of the argument, and pass a _reference to the copy_, instead of +a reference to the original value, to the callable. This is especially +handy when the argument is a temporary value: + +``` +... + MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); +... +using ::testing::_; +using ::testing::InvokeArgument; +... + + MockFoo foo; + ... + EXPECT_CALL(foo, DoThat(_)) + .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); + // Will execute (*f)(5.0, string("Hi")), where f is the function pointer + // DoThat() receives. Note that the values 5.0 and string("Hi") are + // temporary and dead once the EXPECT_CALL() statement finishes. Yet + // it's fine to perform this action later, since a copy of the values + // are kept inside the InvokeArgument action. +``` + +## Ignoring an Action's Result ## + +Sometimes you have an action that returns _something_, but you need an +action that returns `void` (perhaps you want to use it in a mock +function that returns `void`, or perhaps it needs to be used in +`DoAll()` and it's not the last in the list). `IgnoreResult()` lets +you do that. For example: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; + +int Process(const MyData& data); +string DoSomething(); + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Abc, void(const MyData& data)); + MOCK_METHOD0(Xyz, bool()); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, Abc(_)) + // .WillOnce(Invoke(Process)); + // The above line won't compile as Process() returns int but Abc() needs + // to return void. + .WillOnce(IgnoreResult(Invoke(Process))); + + EXPECT_CALL(foo, Xyz()) + .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), + // Ignores the string DoSomething() returns. + Return(true))); +``` + +Note that you **cannot** use `IgnoreResult()` on an action that already +returns `void`. Doing so will lead to ugly compiler errors. + +## Selecting an Action's Arguments ## + +Say you have a mock function `Foo()` that takes seven arguments, and +you have a custom action that you want to invoke when `Foo()` is +called. Trouble is, the custom action only wants three arguments: + +``` +using ::testing::_; +using ::testing::Invoke; +... + MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight)); +... + +bool IsVisibleInQuadrant1(bool visible, int x, int y) { + return visible && x >= 0 && y >= 0; +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( +``` + +To please the compiler God, you can to define an "adaptor" that has +the same signature as `Foo()` and calls the custom action with the +right arguments: + +``` +using ::testing::_; +using ::testing::Invoke; + +bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight) { + return IsVisibleInQuadrant1(visible, x, y); +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. +``` + +But isn't this awkward? + +Google Mock provides a generic _action adaptor_, so you can spend your +time minding more important business than writing your own +adaptors. Here's the syntax: + +``` + WithArgs(action) +``` + +creates an action that passes the arguments of the mock function at +the given indices (0-based) to the inner `action` and performs +it. Using `WithArgs`, our original example can be written as: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::WithArgs; +... + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); + // No need to define your own adaptor. +``` + +For better readability, Google Mock also gives you: + + * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and + * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. + +As you may have realized, `InvokeWithoutArgs(...)` is just syntactic +sugar for `WithoutArgs(Inovke(...))`. + +Here are more tips: + + * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. + * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. + * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. + * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. + +## Ignoring Arguments in Action Functions ## + +The selecting-an-action's-arguments recipe showed us one way to make a +mock function and an action with incompatible argument lists fit +together. The downside is that wrapping the action in +`WithArgs<...>()` can get tedious for people writing the tests. + +If you are defining a function, method, or functor to be used with +`Invoke*()`, and you are not interested in some of its arguments, an +alternative to `WithArgs` is to declare the uninteresting arguments as +`Unused`. This makes the definition less cluttered and less fragile in +case the types of the uninteresting arguments change. It could also +increase the chance the action function can be reused. For example, +given + +``` + MOCK_METHOD3(Foo, double(const string& label, double x, double y)); + MOCK_METHOD3(Bar, double(int index, double x, double y)); +``` + +instead of + +``` +using ::testing::_; +using ::testing::Invoke; + +double DistanceToOriginWithLabel(const string& label, double x, double y) { + return sqrt(x*x + y*y); +} + +double DistanceToOriginWithIndex(int index, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOriginWithLabel)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOriginWithIndex)); +``` + +you could write + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Unused; + +double DistanceToOrigin(Unused, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOrigin)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOrigin)); +``` + +## Sharing Actions ## + +Just like matchers, a Google Mock action object consists of a pointer +to a ref-counted implementation object. Therefore copying actions is +also allowed and very efficient. When the last action that references +the implementation object dies, the implementation object will be +deleted. + +If you have some complex action that you want to use again and again, +you may not have to build it from scratch everytime. If the action +doesn't have an internal state (i.e. if it always does the same thing +no matter how many times it has been called), you can assign it to an +action variable and use that variable repeatedly. For example: + +``` + Action set_flag = DoAll(SetArgPointee<0>(5), + Return(true)); + ... use set_flag in .WillOnce() and .WillRepeatedly() ... +``` + +However, if the action has its own state, you may be surprised if you +share the action object. Suppose you have an action factory +`IncrementCounter(init)` which creates an action that increments and +returns a counter whose initial value is `init`, using two actions +created from the same expression and using a shared action will +exihibit different behaviors. Example: + +``` + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(IncrementCounter(0)); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(IncrementCounter(0)); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 1 - Blah() uses a different + // counter than Bar()'s. +``` + +versus + +``` + Action increment = IncrementCounter(0); + + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(increment); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(increment); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 3 - the counter is shared. +``` + +# Misc Recipes on Using Google Mock # + +## Making the Compilation Faster ## + +Believe it or not, the _vast majority_ of the time spent on compiling +a mock class is in generating its constructor and destructor, as they +perform non-trivial tasks (e.g. verification of the +expectations). What's more, mock methods with different signatures +have different types and thus their constructors/destructors need to +be generated by the compiler separately. As a result, if you mock many +different types of methods, compiling your mock class can get really +slow. + +If you are experiencing slow compilation, you can move the definition +of your mock class' constructor and destructor out of the class body +and into a `.cpp` file. This way, even if you `#include` your mock +class in N files, the compiler only needs to generate its constructor +and destructor once, resulting in a much faster compilation. + +Let's illustrate the idea using an example. Here's the definition of a +mock class before applying this recipe: + +``` +// File mock_foo.h. +... +class MockFoo : public Foo { + public: + // Since we don't declare the constructor or the destructor, + // the compiler will generate them in every translation unit + // where this mock class is used. + + MOCK_METHOD0(DoThis, int()); + MOCK_METHOD1(DoThat, bool(const char* str)); + ... more mock methods ... +}; +``` + +After the change, it would look like: + +``` +// File mock_foo.h. +... +class MockFoo : public Foo { + public: + // The constructor and destructor are declared, but not defined, here. + MockFoo(); + virtual ~MockFoo(); + + MOCK_METHOD0(DoThis, int()); + MOCK_METHOD1(DoThat, bool(const char* str)); + ... more mock methods ... +}; +``` +and +``` +// File mock_foo.cpp. +#include "path/to/mock_foo.h" + +// The definitions may appear trivial, but the functions actually do a +// lot of things through the constructors/destructors of the member +// variables used to implement the mock methods. +MockFoo::MockFoo() {} +MockFoo::~MockFoo() {} +``` + +## Forcing a Verification ## + +When it's being destoyed, your friendly mock object will automatically +verify that all expectations on it have been satisfied, and will +generate [Google Test](http://code.google.com/p/googletest/) failures +if not. This is convenient as it leaves you with one less thing to +worry about. That is, unless you are not sure if your mock object will +be destoyed. + +How could it be that your mock object won't eventually be destroyed? +Well, it might be created on the heap and owned by the code you are +testing. Suppose there's a bug in that code and it doesn't delete the +mock object properly - you could end up with a passing test when +there's actually a bug. + +Using a heap checker is a good idea and can alleviate the concern, but +its implementation may not be 100% reliable. So, sometimes you do want +to _force_ Google Mock to verify a mock object before it is +(hopefully) destructed. You can do this with +`Mock::VerifyAndClearExpectations(&mock_object)`: + +``` +TEST(MyServerTest, ProcessesRequest) { + using ::testing::Mock; + + MockFoo* const foo = new MockFoo; + EXPECT_CALL(*foo, ...)...; + // ... other expectations ... + + // server now owns foo. + MyServer server(foo); + server.ProcessRequest(...); + + // In case that server's destructor will forget to delete foo, + // this will verify the expectations anyway. + Mock::VerifyAndClearExpectations(foo); +} // server is destroyed when it goes out of scope here. +``` + +**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a +`bool` to indicate whether the verification was successful (`true` for +yes), so you can wrap that function call inside a `ASSERT_TRUE()` if +there is no point going further when the verification has failed. + +## Using Check Points ## + +Sometimes you may want to "reset" a mock object at various check +points in your test: at each check point, you verify that all existing +expectations on the mock object have been satisfied, and then you set +some new expectations on it as if it's newly created. This allows you +to work with a mock object in "phases" whose sizes are each +manageable. + +One such scenario is that in your test's `SetUp()` function, you may +want to put the object you are testing into a certain state, with the +help from a mock object. Once in the desired state, you want to clear +all expectations on the mock, such that in the `TEST_F` body you can +set fresh expectations on it. + +As you may have figured out, the `Mock::VerifyAndClearExpectations()` +function we saw in the previous recipe can help you here. Or, if you +are using `ON_CALL()` to set default actions on the mock object and +want to clear the default actions as well, use +`Mock::VerifyAndClear(&mock_object)` instead. This function does what +`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the +same `bool`, **plus** it clears the `ON_CALL()` statements on +`mock_object` too. + +Another trick you can use to achieve the same effect is to put the +expectations in sequences and insert calls to a dummy "check-point" +function at specific places. Then you can verify that the mock +function calls do happen at the right time. For example, if you are +exercising code: + +``` +Foo(1); +Foo(2); +Foo(3); +``` + +and want to verify that `Foo(1)` and `Foo(3)` both invoke +`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: + +``` +using ::testing::MockFunction; + +TEST(FooTest, InvokesBarCorrectly) { + MyMock mock; + // Class MockFunction has exactly one mock method. It is named + // Call() and has type F. + MockFunction check; + { + InSequence s; + + EXPECT_CALL(mock, Bar("a")); + EXPECT_CALL(check, Call("1")); + EXPECT_CALL(check, Call("2")); + EXPECT_CALL(mock, Bar("a")); + } + Foo(1); + check.Call("1"); + Foo(2); + check.Call("2"); + Foo(3); +} +``` + +The expectation spec says that the first `Bar("a")` must happen before +check point "1", the second `Bar("a")` must happen after check point "2", +and nothing should happen between the two check points. The explicit +check points make it easy to tell which `Bar("a")` is called by which +call to `Foo()`. + +## Mocking Destructors ## + +Sometimes you want to make sure a mock object is destructed at the +right time, e.g. after `bar->A()` is called but before `bar->B()` is +called. We already know that you can specify constraints on the order +of mock function calls, so all we need to do is to mock the destructor +of the mock function. + +This sounds simple, except for one problem: a destructor is a special +function with special syntax and special semantics, and the +`MOCK_METHOD0` macro doesn't work for it: + +``` + MOCK_METHOD0(~MockFoo, void()); // Won't compile! +``` + +The good news is that you can use a simple pattern to achieve the same +effect. First, add a mock function `Die()` to your mock class and call +it in the destructor, like this: + +``` +class MockFoo : public Foo { + ... + // Add the following two lines to the mock class. + MOCK_METHOD0(Die, void()); + virtual ~MockFoo() { Die(); } +}; +``` + +(If the name `Die()` clashes with an existing symbol, choose another +name.) Now, we have translated the problem of testing when a `MockFoo` +object dies to testing when its `Die()` method is called: + +``` + MockFoo* foo = new MockFoo; + MockBar* bar = new MockBar; + ... + { + InSequence s; + + // Expects *foo to die after bar->A() and before bar->B(). + EXPECT_CALL(*bar, A()); + EXPECT_CALL(*foo, Die()); + EXPECT_CALL(*bar, B()); + } +``` + +And that's that. + +## Using Google Mock and Threads ## + +**IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on +platforms where Google Mock is thread-safe. Currently these are only +platforms that support the pthreads library (this includes Linux and Mac). +To make it thread-safe on other platforms we only need to implement +some synchronization operations in `"gtest/internal/gtest-port.h"`. + +In a **unit** test, it's best if you could isolate and test a piece of +code in a single-threaded context. That avoids race conditions and +dead locks, and makes debugging your test much easier. + +Yet many programs are multi-threaded, and sometimes to test something +we need to pound on it from more than one thread. Google Mock works +for this purpose too. + +Remember the steps for using a mock: + + 1. Create a mock object `foo`. + 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. + 1. The code under test calls methods of `foo`. + 1. Optionally, verify and reset the mock. + 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. + +If you follow the following simple rules, your mocks and threads can +live happily togeter: + + * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. + * Obviously, you can do step #1 without locking. + * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? + * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. + +If you violate the rules (for example, if you set expectations on a +mock while another thread is calling its methods), you get undefined +behavior. That's not fun, so don't do it. + +Google Mock guarantees that the action for a mock function is done in +the same thread that called the mock function. For example, in + +``` + EXPECT_CALL(mock, Foo(1)) + .WillOnce(action1); + EXPECT_CALL(mock, Foo(2)) + .WillOnce(action2); +``` + +if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, +Google Mock will execute `action1` in thread 1 and `action2` in thread +2. + +Google Mock does _not_ impose a sequence on actions performed in +different threads (doing so may create deadlocks as the actions may +need to cooperate). This means that the execution of `action1` and +`action2` in the above example _may_ interleave. If this is a problem, +you should add proper synchronization logic to `action1` and `action2` +to make the test thread-safe. + + +Also, remember that `DefaultValue` is a global resource that +potentially affects _all_ living mock objects in your +program. Naturally, you won't want to mess with it from multiple +threads or when there still are mocks in action. + +## Controlling How Much Information Google Mock Prints ## + +When Google Mock sees something that has the potential of being an +error (e.g. a mock function with no expectation is called, a.k.a. an +uninteresting call, which is allowed but perhaps you forgot to +explicitly ban the call), it prints some warning messages, including +the arguments of the function and the return value. Hopefully this +will remind you to take a look and see if there is indeed a problem. + +Sometimes you are confident that your tests are correct and may not +appreciate such friendly messages. Some other times, you are debugging +your tests or learning about the behavior of the code you are testing, +and wish you could observe every mock call that happens (including +argument values and the return value). Clearly, one size doesn't fit +all. + +You can control how much Google Mock tells you using the +`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string +with three possible values: + + * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. + * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. + * `error`: Google Mock will print errors only (least verbose). + +Alternatively, you can adjust the value of that flag from within your +tests like so: + +``` + ::testing::FLAGS_gmock_verbose = "error"; +``` + +Now, judiciously use the right flag to enable Google Mock serve you better! + +## Running Tests in Emacs ## + +If you build and run your tests in Emacs, the source file locations of +Google Mock and [Google Test](http://code.google.com/p/googletest/) +errors will be highlighted. Just press `` on one of them and +you'll be taken to the offending line. Or, you can just type `C-x `` +to jump to the next error. + +To make it even easier, you can add the following lines to your +`~/.emacs` file: + +``` +(global-set-key "\M-m" 'compile) ; m is for make +(global-set-key [M-down] 'next-error) +(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) +``` + +Then you can type `M-m` to start a build, or `M-up`/`M-down` to move +back and forth between errors. + +## Fusing Google Mock Source Files ## + +Google Mock's implementation consists of dozens of files (excluding +its own tests). Sometimes you may want them to be packaged up in +fewer files instead, such that you can easily copy them to a new +machine and start hacking there. For this we provide an experimental +Python script `fuse_gmock_files.py` in the `scripts/` directory +(starting with release 1.2.0). Assuming you have Python 2.4 or above +installed on your machine, just go to that directory and run +``` +python fuse_gmock_files.py OUTPUT_DIR +``` + +and you should see an `OUTPUT_DIR` directory being created with files +`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. +These three files contain everything you need to use Google Mock (and +Google Test). Just copy them to anywhere you want and you are ready +to write tests and use mocks. You can use the +[scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests +against them. + +# Extending Google Mock # + +## Writing New Matchers Quickly ## + +The `MATCHER*` family of macros can be used to define custom matchers +easily. The syntax: + +``` +MATCHER(name, description_string_expression) { statements; } +``` + +will define a matcher with the given name that executes the +statements, which must return a `bool` to indicate if the match +succeeds. Inside the statements, you can refer to the value being +matched by `arg`, and refer to its type by `arg_type`. + +The description string is a `string`-typed expression that documents +what the matcher does, and is used to generate the failure message +when the match fails. It can (and should) reference the special +`bool` variable `negation`, and should evaluate to the description of +the matcher when `negation` is `false`, or that of the matcher's +negation when `negation` is `true`. + +For convenience, we allow the description string to be empty (`""`), +in which case Google Mock will use the sequence of words in the +matcher name as the description. + +For example: +``` +MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } +``` +allows you to write +``` + // Expects mock_foo.Bar(n) to be called where n is divisible by 7. + EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); +``` +or, +``` +using ::testing::Not; +... + EXPECT_THAT(some_expression, IsDivisibleBy7()); + EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); +``` +If the above assertions fail, they will print something like: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 +... + Value of: some_other_expression + Expected: not (is divisible by 7) + Actual: 21 +``` +where the descriptions `"is divisible by 7"` and `"not (is divisible +by 7)"` are automatically calculated from the matcher name +`IsDivisibleBy7`. + +As you may have noticed, the auto-generated descriptions (especially +those for the negation) may not be so great. You can always override +them with a string expression of your own: +``` +MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + + " divisible by 7") { + return (arg % 7) == 0; +} +``` + +Optionally, you can stream additional information to a hidden argument +named `result_listener` to explain the match result. For example, a +better definition of `IsDivisibleBy7` is: +``` +MATCHER(IsDivisibleBy7, "") { + if ((arg % 7) == 0) + return true; + + *result_listener << "the remainder is " << (arg % 7); + return false; +} +``` + +With this definition, the above assertion will give a better message: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 (the remainder is 6) +``` + +You should let `MatchAndExplain()` print _any additional information_ +that can help a user understand the match result. Note that it should +explain why the match succeeds in case of a success (unless it's +obvious) - this is useful when the matcher is used inside +`Not()`. There is no need to print the argument value itself, as +Google Mock already prints it for you. + +**Notes:** + + 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. + 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. + +## Writing New Parameterized Matchers Quickly ## + +Sometimes you'll want to define a matcher that has parameters. For that you +can use the macro: +``` +MATCHER_P(name, param_name, description_string) { statements; } +``` +where the description string can be either `""` or a string expression +that references `negation` and `param_name`. + +For example: +``` +MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +``` +will allow you to write: +``` + EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +``` +which may lead to this message (assuming `n` is 10): +``` + Value of: Blah("a") + Expected: has absolute value 10 + Actual: -9 +``` + +Note that both the matcher description and its parameter are +printed, making the message human-friendly. + +In the matcher definition body, you can write `foo_type` to +reference the type of a parameter named `foo`. For example, in the +body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write +`value_type` to refer to the type of `value`. + +Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to +`MATCHER_P10` to support multi-parameter matchers: +``` +MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } +``` + +Please note that the custom description string is for a particular +**instance** of the matcher, where the parameters have been bound to +actual values. Therefore usually you'll want the parameter values to +be part of the description. Google Mock lets you do that by +referencing the matcher parameters in the description string +expression. + +For example, +``` + using ::testing::PrintToString; + MATCHER_P2(InClosedRange, low, hi, + std::string(negation ? "isn't" : "is") + " in range [" + + PrintToString(low) + ", " + PrintToString(hi) + "]") { + return low <= arg && arg <= hi; + } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the message: +``` + Expected: is in range [4, 6] +``` + +If you specify `""` as the description, the failure message will +contain the sequence of words in the matcher name followed by the +parameter values printed as a tuple. For example, +``` + MATCHER_P2(InClosedRange, low, hi, "") { ... } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the text: +``` + Expected: in closed range (4, 6) +``` + +For the purpose of typing, you can view +``` +MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +``` +as shorthand for +``` +template +FooMatcherPk +Foo(p1_type p1, ..., pk_type pk) { ... } +``` + +When you write `Foo(v1, ..., vk)`, the compiler infers the types of +the parameters `v1`, ..., and `vk` for you. If you are not happy with +the result of the type inference, you can specify the types by +explicitly instantiating the template, as in `Foo(5, false)`. +As said earlier, you don't get to (or need to) specify +`arg_type` as that's determined by the context in which the matcher +is used. + +You can assign the result of expression `Foo(p1, ..., pk)` to a +variable of type `FooMatcherPk`. This can be +useful when composing matchers. Matchers that don't have a parameter +or have only one parameter have special types: you can assign `Foo()` +to a `FooMatcher`-typed variable, and assign `Foo(p)` to a +`FooMatcherP`-typed variable. + +While you can instantiate a matcher template with reference types, +passing the parameters by pointer usually makes your code more +readable. If, however, you still want to pass a parameter by +reference, be aware that in the failure message generated by the +matcher you will see the value of the referenced object but not its +address. + +You can overload matchers with different numbers of parameters: +``` +MATCHER_P(Blah, a, description_string_1) { ... } +MATCHER_P2(Blah, a, b, description_string_2) { ... } +``` + +While it's tempting to always use the `MATCHER*` macros when defining +a new matcher, you should also consider implementing +`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see +the recipes that follow), especially if you need to use the matcher a +lot. While these approaches require more work, they give you more +control on the types of the value being matched and the matcher +parameters, which in general leads to better compiler error messages +that pay off in the long run. They also allow overloading matchers +based on parameter types (as opposed to just based on the number of +parameters). + +## Writing New Monomorphic Matchers ## + +A matcher of argument type `T` implements +`::testing::MatcherInterface` and does two things: it tests whether a +value of type `T` matches the matcher, and can describe what kind of +values it matches. The latter ability is used for generating readable +error messages when expectations are violated. + +The interface looks like this: + +``` +class MatchResultListener { + public: + ... + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x); + + // Returns the underlying ostream. + ::std::ostream* stream(); +}; + +template +class MatcherInterface { + public: + virtual ~MatcherInterface(); + + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Describes this matcher to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. + virtual void DescribeNegationTo(::std::ostream* os) const; +}; +``` + +If you need a custom matcher but `Truly()` is not a good option (for +example, you may not be happy with the way `Truly(predicate)` +describes itself, or you may want your matcher to be polymorphic as +`Eq(value)` is), you can define a matcher to do whatever you want in +two steps: first implement the matcher interface, and then define a +factory function to create a matcher instance. The second step is not +strictly needed but it makes the syntax of using the matcher nicer. + +For example, you can define a matcher to test whether an `int` is +divisible by 7 and then use it like this: +``` +using ::testing::MakeMatcher; +using ::testing::Matcher; +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { + return (n % 7) == 0; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is divisible by 7"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "is not divisible by 7"; + } +}; + +inline Matcher DivisibleBy7() { + return MakeMatcher(new DivisibleBy7Matcher); +} +... + + EXPECT_CALL(foo, Bar(DivisibleBy7())); +``` + +You may improve the matcher message by streaming additional +information to the `listener` argument in `MatchAndExplain()`: + +``` +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, + MatchResultListener* listener) const { + const int remainder = n % 7; + if (remainder != 0) { + *listener << "the remainder is " << remainder; + } + return remainder == 0; + } + ... +}; +``` + +Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: +``` +Value of: x +Expected: is divisible by 7 + Actual: 23 (the remainder is 2) +``` + +## Writing New Polymorphic Matchers ## + +You've learned how to write your own matchers in the previous +recipe. Just one problem: a matcher created using `MakeMatcher()` only +works for one particular type of arguments. If you want a +_polymorphic_ matcher that works with arguments of several types (for +instance, `Eq(x)` can be used to match a `value` as long as `value` == +`x` compiles -- `value` and `x` don't have to share the same type), +you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit +involved. + +Fortunately, most of the time you can define a polymorphic matcher +easily with the help of `MakePolymorphicMatcher()`. Here's how you can +define `NotNull()` as an example: + +``` +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +using ::testing::NotNull; +using ::testing::PolymorphicMatcher; + +class NotNullMatcher { + public: + // To implement a polymorphic matcher, first define a COPYABLE class + // that has three members MatchAndExplain(), DescribeTo(), and + // DescribeNegationTo(), like the following. + + // In this example, we want to use NotNull() with any pointer, so + // MatchAndExplain() accepts a pointer of any type as its first argument. + // In general, you can define MatchAndExplain() as an ordinary method or + // a method template, or even overload it. + template + bool MatchAndExplain(T* p, + MatchResultListener* /* listener */) const { + return p != NULL; + } + + // Describes the property of a value matching this matcher. + void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } + + // Describes the property of a value NOT matching this matcher. + void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } +}; + +// To construct a polymorphic matcher, pass an instance of the class +// to MakePolymorphicMatcher(). Note the return type. +inline PolymorphicMatcher NotNull() { + return MakePolymorphicMatcher(NotNullMatcher()); +} +... + + EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. +``` + +**Note:** Your polymorphic matcher class does **not** need to inherit from +`MatcherInterface` or any other class, and its methods do **not** need +to be virtual. + +Like in a monomorphic matcher, you may explain the match result by +streaming additional information to the `listener` argument in +`MatchAndExplain()`. + +## Writing New Cardinalities ## + +A cardinality is used in `Times()` to tell Google Mock how many times +you expect a call to occur. It doesn't have to be exact. For example, +you can say `AtLeast(5)` or `Between(2, 4)`. + +If the built-in set of cardinalities doesn't suit you, you are free to +define your own by implementing the following interface (in namespace +`testing`): + +``` +class CardinalityInterface { + public: + virtual ~CardinalityInterface(); + + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; +``` + +For example, to specify that a call must occur even number of times, +you can write + +``` +using ::testing::Cardinality; +using ::testing::CardinalityInterface; +using ::testing::MakeCardinality; + +class EvenNumberCardinality : public CardinalityInterface { + public: + virtual bool IsSatisfiedByCallCount(int call_count) const { + return (call_count % 2) == 0; + } + + virtual bool IsSaturatedByCallCount(int call_count) const { + return false; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "called even number of times"; + } +}; + +Cardinality EvenNumber() { + return MakeCardinality(new EvenNumberCardinality); +} +... + + EXPECT_CALL(foo, Bar(3)) + .Times(EvenNumber()); +``` + +## Writing New Actions Quickly ## + +If the built-in actions don't work for you, and you find it +inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` +family to quickly define a new action that can be used in your code as +if it's a built-in action. + +By writing +``` +ACTION(name) { statements; } +``` +in a namespace scope (i.e. not inside a class or function), you will +define an action with the given name that executes the statements. +The value returned by `statements` will be used as the return value of +the action. Inside the statements, you can refer to the K-th +(0-based) argument of the mock function as `argK`. For example: +``` +ACTION(IncrementArg1) { return ++(*arg1); } +``` +allows you to write +``` +... WillOnce(IncrementArg1()); +``` + +Note that you don't need to specify the types of the mock function +arguments. Rest assured that your code is type-safe though: +you'll get a compiler error if `*arg1` doesn't support the `++` +operator, or if the type of `++(*arg1)` isn't compatible with the mock +function's return type. + +Another example: +``` +ACTION(Foo) { + (*arg2)(5); + Blah(); + *arg1 = 0; + return arg0; +} +``` +defines an action `Foo()` that invokes argument #2 (a function pointer) +with 5, calls function `Blah()`, sets the value pointed to by argument +#1 to 0, and returns argument #0. + +For more convenience and flexibility, you can also use the following +pre-defined symbols in the body of `ACTION`: + +| `argK_type` | The type of the K-th (0-based) argument of the mock function | +|:------------|:-------------------------------------------------------------| +| `args` | All arguments of the mock function as a tuple | +| `args_type` | The type of all arguments of the mock function as a tuple | +| `return_type` | The return type of the mock function | +| `function_type` | The type of the mock function | + +For example, when using an `ACTION` as a stub action for mock function: +``` +int DoSomething(bool flag, int* ptr); +``` +we have: +| **Pre-defined Symbol** | **Is Bound To** | +|:-----------------------|:----------------| +| `arg0` | the value of `flag` | +| `arg0_type` | the type `bool` | +| `arg1` | the value of `ptr` | +| `arg1_type` | the type `int*` | +| `args` | the tuple `(flag, ptr)` | +| `args_type` | the type `std::tr1::tuple` | +| `return_type` | the type `int` | +| `function_type` | the type `int(bool, int*)` | + +## Writing New Parameterized Actions Quickly ## + +Sometimes you'll want to parameterize an action you define. For that +we have another macro +``` +ACTION_P(name, param) { statements; } +``` + +For example, +``` +ACTION_P(Add, n) { return arg0 + n; } +``` +will allow you to write +``` +// Returns argument #0 + 5. +... WillOnce(Add(5)); +``` + +For convenience, we use the term _arguments_ for the values used to +invoke the mock function, and the term _parameters_ for the values +used to instantiate an action. + +Note that you don't need to provide the type of the parameter either. +Suppose the parameter is named `param`, you can also use the +Google-Mock-defined symbol `param_type` to refer to the type of the +parameter as inferred by the compiler. For example, in the body of +`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. + +Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support +multi-parameter actions. For example, +``` +ACTION_P2(ReturnDistanceTo, x, y) { + double dx = arg0 - x; + double dy = arg1 - y; + return sqrt(dx*dx + dy*dy); +} +``` +lets you write +``` +... WillOnce(ReturnDistanceTo(5.0, 26.5)); +``` + +You can view `ACTION` as a degenerated parameterized action where the +number of parameters is 0. + +You can also easily define actions overloaded on the number of parameters: +``` +ACTION_P(Plus, a) { ... } +ACTION_P2(Plus, a, b) { ... } +``` + +## Restricting the Type of an Argument or Parameter in an ACTION ## + +For maximum brevity and reusability, the `ACTION*` macros don't ask +you to provide the types of the mock function arguments and the action +parameters. Instead, we let the compiler infer the types for us. + +Sometimes, however, we may want to be more explicit about the types. +There are several tricks to do that. For example: +``` +ACTION(Foo) { + // Makes sure arg0 can be converted to int. + int n = arg0; + ... use n instead of arg0 here ... +} + +ACTION_P(Bar, param) { + // Makes sure the type of arg1 is const char*. + ::testing::StaticAssertTypeEq(); + + // Makes sure param can be converted to bool. + bool flag = param; +} +``` +where `StaticAssertTypeEq` is a compile-time assertion in Google Test +that verifies two types are the same. + +## Writing New Action Templates Quickly ## + +Sometimes you want to give an action explicit template parameters that +cannot be inferred from its value parameters. `ACTION_TEMPLATE()` +supports that and can be viewed as an extension to `ACTION()` and +`ACTION_P*()`. + +The syntax: +``` +ACTION_TEMPLATE(ActionName, + HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), + AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } +``` + +defines an action template that takes _m_ explicit template parameters +and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is +between 0 and 10. `name_i` is the name of the i-th template +parameter, and `kind_i` specifies whether it's a `typename`, an +integral constant, or a template. `p_i` is the name of the i-th value +parameter. + +Example: +``` +// DuplicateArg(output) converts the k-th argument of the mock +// function to type T and copies it to *output. +ACTION_TEMPLATE(DuplicateArg, + // Note the comma between int and k: + HAS_2_TEMPLATE_PARAMS(int, k, typename, T), + AND_1_VALUE_PARAMS(output)) { + *output = T(std::tr1::get(args)); +} +``` + +To create an instance of an action template, write: +``` + ActionName(v1, ..., v_n) +``` +where the `t`s are the template arguments and the +`v`s are the value arguments. The value argument +types are inferred by the compiler. For example: +``` +using ::testing::_; +... + int n; + EXPECT_CALL(mock, Foo(_, _)) + .WillOnce(DuplicateArg<1, unsigned char>(&n)); +``` + +If you want to explicitly specify the value argument types, you can +provide additional template arguments: +``` + ActionName(v1, ..., v_n) +``` +where `u_i` is the desired type of `v_i`. + +`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the +number of value parameters, but not on the number of template +parameters. Without the restriction, the meaning of the following is +unclear: + +``` + OverloadedAction(x); +``` + +Are we using a single-template-parameter action where `bool` refers to +the type of `x`, or a two-template-parameter action where the compiler +is asked to infer the type of `x`? + +## Using the ACTION Object's Type ## + +If you are writing a function that returns an `ACTION` object, you'll +need to know its type. The type depends on the macro used to define +the action and the parameter types. The rule is relatively simple: +| **Given Definition** | **Expression** | **Has Type** | +|:---------------------|:---------------|:-------------| +| `ACTION(Foo)` | `Foo()` | `FooAction` | +| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | +| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | +| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | +| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | +| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | +| ... | ... | ... | + +Note that we have to pick different suffixes (`Action`, `ActionP`, +`ActionP2`, and etc) for actions with different numbers of value +parameters, or the action definitions cannot be overloaded on the +number of them. + +## Writing New Monomorphic Actions ## + +While the `ACTION*` macros are very convenient, sometimes they are +inappropriate. For example, despite the tricks shown in the previous +recipes, they don't let you directly specify the types of the mock +function arguments and the action parameters, which in general leads +to unoptimized compiler error messages that can baffle unfamiliar +users. They also don't allow overloading actions based on parameter +types without jumping through some hoops. + +An alternative to the `ACTION*` macros is to implement +`::testing::ActionInterface`, where `F` is the type of the mock +function in which the action will be used. For example: + +``` +template class ActionInterface { + public: + virtual ~ActionInterface(); + + // Performs the action. Result is the return type of function type + // F, and ArgumentTuple is the tuple of arguments of F. + // + // For example, if F is int(bool, const string&), then Result would + // be int, and ArgumentTuple would be tr1::tuple. + virtual Result Perform(const ArgumentTuple& args) = 0; +}; + +using ::testing::_; +using ::testing::Action; +using ::testing::ActionInterface; +using ::testing::MakeAction; + +typedef int IncrementMethod(int*); + +class IncrementArgumentAction : public ActionInterface { + public: + virtual int Perform(const tr1::tuple& args) { + int* p = tr1::get<0>(args); // Grabs the first argument. + return *p++; + } +}; + +Action IncrementArgument() { + return MakeAction(new IncrementArgumentAction); +} +... + + EXPECT_CALL(foo, Baz(_)) + .WillOnce(IncrementArgument()); + + int n = 5; + foo.Baz(&n); // Should return 5 and change n to 6. +``` + +## Writing New Polymorphic Actions ## + +The previous recipe showed you how to define your own action. This is +all good, except that you need to know the type of the function in +which the action will be used. Sometimes that can be a problem. For +example, if you want to use the action in functions with _different_ +types (e.g. like `Return()` and `SetArgPointee()`). + +If an action can be used in several types of mock functions, we say +it's _polymorphic_. The `MakePolymorphicAction()` function template +makes it easy to define such an action: + +``` +namespace testing { + +template +PolymorphicAction MakePolymorphicAction(const Impl& impl); + +} // namespace testing +``` + +As an example, let's define an action that returns the second argument +in the mock function's argument list. The first step is to define an +implementation class: + +``` +class ReturnSecondArgumentAction { + public: + template + Result Perform(const ArgumentTuple& args) const { + // To get the i-th (0-based) argument, use tr1::get(args). + return tr1::get<1>(args); + } +}; +``` + +This implementation class does _not_ need to inherit from any +particular class. What matters is that it must have a `Perform()` +method template. This method template takes the mock function's +arguments as a tuple in a **single** argument, and returns the result of +the action. It can be either `const` or not, but must be invokable +with exactly one template argument, which is the result type. In other +words, you must be able to call `Perform(args)` where `R` is the +mock function's return type and `args` is its arguments in a tuple. + +Next, we use `MakePolymorphicAction()` to turn an instance of the +implementation class into the polymorphic action we need. It will be +convenient to have a wrapper for this: + +``` +using ::testing::MakePolymorphicAction; +using ::testing::PolymorphicAction; + +PolymorphicAction ReturnSecondArgument() { + return MakePolymorphicAction(ReturnSecondArgumentAction()); +} +``` + +Now, you can use this polymorphic action the same way you use the +built-in ones: + +``` +using ::testing::_; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, int(bool flag, int n)); + MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(ReturnSecondArgument()); + EXPECT_CALL(foo, DoThat(_, _, _)) + .WillOnce(ReturnSecondArgument()); + ... + foo.DoThis(true, 5); // Will return 5. + foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". +``` + +## Teaching Google Mock How to Print Your Values ## + +When an uninteresting or unexpected call occurs, Google Mock prints the +argument values and the stack trace to help you debug. Assertion +macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in +question when the assertion fails. Google Mock and Google Test do this using +Google Test's user-extensible value printer. + +This printer knows how to print built-in C++ types, native arrays, STL +containers, and any type that supports the `<<` operator. For other +types, it prints the raw bytes in the value and hopes that you the +user can figure it out. +[Google Test's advanced guide](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Teaching_Google_Test_How_to_Print_Your_Values) +explains how to extend the printer to do a better job at +printing your particular type than to dump the bytes. \ No newline at end of file diff --git a/googlemock/docs/v1_6/Documentation.md b/googlemock/docs/v1_6/Documentation.md new file mode 100644 index 0000000..dcc9156 --- /dev/null +++ b/googlemock/docs/v1_6/Documentation.md @@ -0,0 +1,12 @@ +This page lists all documentation wiki pages for Google Mock **1.6** +- **if you use a released version of Google Mock, please read the documentation for that specific version instead.** + + * [ForDummies](V1_6_ForDummies.md) -- start here if you are new to Google Mock. + * [CheatSheet](V1_6_CheatSheet.md) -- a quick reference. + * [CookBook](V1_6_CookBook.md) -- recipes for doing various tasks using Google Mock. + * [FrequentlyAskedQuestions](V1_6_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. + +To contribute code to Google Mock, read: + + * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. + * [Pump Manual](http://code.google.com/p/googletest/wiki/V1_6_PumpManual) -- how we generate some of Google Mock's source files. \ No newline at end of file diff --git a/googlemock/docs/v1_6/ForDummies.md b/googlemock/docs/v1_6/ForDummies.md new file mode 100644 index 0000000..19ee63a --- /dev/null +++ b/googlemock/docs/v1_6/ForDummies.md @@ -0,0 +1,439 @@ + + +(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_6_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).) + +# What Is Google C++ Mocking Framework? # +When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). + +**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: + + * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. + * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. + +If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. + +**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. + +Using Google Mock involves three basic steps: + + 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; + 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; + 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. + +# Why Google Mock? # +While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: + + * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. + * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. + * The knowledge you gained from using one mock doesn't transfer to the next. + +In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. + +Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: + + * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". + * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). + * Your tests are brittle as some resources they use are unreliable (e.g. the network). + * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. + * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. + * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. + +We encourage you to use Google Mock as: + + * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! + * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. + +# Getting Started # +Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. + +# A Case for Mock Turtles # +Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: + +``` +class Turtle { + ... + virtual ~Turtle() {} + virtual void PenUp() = 0; + virtual void PenDown() = 0; + virtual void Forward(int distance) = 0; + virtual void Turn(int degrees) = 0; + virtual void GoTo(int x, int y) = 0; + virtual int GetX() const = 0; + virtual int GetY() const = 0; +}; +``` + +(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) + +You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. + +Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. + +# Writing the Mock Class # +If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) + +## How to Define It ## +Using the `Turtle` interface as example, here are the simple steps you need to follow: + + 1. Derive a class `MockTurtle` from `Turtle`. + 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has. + 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. + 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). + 1. Repeat until all virtual functions you want to mock are done. + +After the process, you should have something like: + +``` +#include "gmock/gmock.h" // Brings in Google Mock. +class MockTurtle : public Turtle { + public: + ... + MOCK_METHOD0(PenUp, void()); + MOCK_METHOD0(PenDown, void()); + MOCK_METHOD1(Forward, void(int distance)); + MOCK_METHOD1(Turn, void(int degrees)); + MOCK_METHOD2(GoTo, void(int x, int y)); + MOCK_CONST_METHOD0(GetX, int()); + MOCK_CONST_METHOD0(GetY, int()); +}; +``` + +You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. + +**Tip:** If even this is too much work for you, you'll find the +`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line +tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, +and it will print the definition of the mock class for you. Due to the +complexity of the C++ language, this script may not always work, but +it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). + +## Where to Put It ## +When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) + +So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. + +Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. + +# Using Mocks in Tests # +Once you have a mock class, using it is easy. The typical work flow is: + + 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). + 1. Create some mock objects. + 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). + 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. + 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. + +Here's an example: + +``` +#include "path/to/mock-turtle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +using ::testing::AtLeast; // #1 + +TEST(PainterTest, CanDrawSomething) { + MockTurtle turtle; // #2 + EXPECT_CALL(turtle, PenDown()) // #3 + .Times(AtLeast(1)); + + Painter painter(&turtle); // #4 + + EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); +} // #5 + +int main(int argc, char** argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} +``` + +As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: + +``` +path/to/my_test.cc:119: Failure +Actual function call count doesn't match this expectation: +Actually: never called; +Expected: called at least once. +``` + +**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. + +**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. + +**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. + +This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. + +Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. + +## Using Google Mock with Any Testing Framework ## +If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or +[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: +``` +int main(int argc, char** argv) { + // The following line causes Google Mock to throw an exception on failure, + // which will be interpreted by your testing framework as a test failure. + ::testing::GTEST_FLAG(throw_on_failure) = true; + ::testing::InitGoogleMock(&argc, argv); + ... whatever your testing framework requires ... +} +``` + +This approach has a catch: it makes Google Mock throw an exception +from a mock object's destructor sometimes. With some compilers, this +sometimes causes the test program to crash. You'll still be able to +notice that the test has failed, but it's not a graceful failure. + +A better solution is to use Google Test's +[event listener API](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) +to report a test failure to your testing framework properly. You'll need to +implement the `OnTestPartResult()` method of the event listener interface, but it +should be straightforward. + +If this turns out to be too much work, we suggest that you stick with +Google Test, which works with Google Mock seamlessly (in fact, it is +technically part of Google Mock.). If there is a reason that you +cannot use Google Test, please let us know. + +# Setting Expectations # +The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." + +## General Syntax ## +In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: + +``` +EXPECT_CALL(mock_object, method(matchers)) + .Times(cardinality) + .WillOnce(action) + .WillRepeatedly(action); +``` + +The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) + +The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. + +This syntax is designed to make an expectation read like English. For example, you can probably guess that + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .Times(5) + .WillOnce(Return(100)) + .WillOnce(Return(150)) + .WillRepeatedly(Return(200)); +``` + +says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). + +**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. + +## Matchers: What Arguments Do We Expect? ## +When a mock function takes arguments, we must specify what arguments we are expecting; for example: + +``` +// Expects the turtle to move forward by 100 units. +EXPECT_CALL(turtle, Forward(100)); +``` + +Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": + +``` +using ::testing::_; +... +// Expects the turtle to move forward. +EXPECT_CALL(turtle, Forward(_)); +``` + +`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. + +A list of built-in matchers can be found in the [CheatSheet](V1_6_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: + +``` +using ::testing::Ge;... +EXPECT_CALL(turtle, Forward(Ge(100))); +``` + +This checks that the turtle will be told to go forward by at least 100 units. + +## Cardinalities: How Many Times Will It Be Called? ## +The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. + +An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. + +We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_6_CheatSheet.md). + +The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: + + * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. + * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. + * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. + +**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? + +## Actions: What Should It Do? ## +Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. + +First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. + +Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillOnce(Return(300)); +``` + +This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillRepeatedly(Return(300)); +``` + +says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. + +Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). + +What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#Actions). + +**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: + +``` +int n = 100; +EXPECT_CALL(turtle, GetX()) +.Times(4) +.WillRepeatedly(Return(n++)); +``` + +Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_6_CookBook.md). + +Time for another quiz! What do you think the following means? + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) +.Times(4) +.WillOnce(Return(100)); +``` + +Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. + +## Using Multiple Expectations ## +So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. + +By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: + +``` +using ::testing::_;... +EXPECT_CALL(turtle, Forward(_)); // #1 +EXPECT_CALL(turtle, Forward(10)) // #2 + .Times(2); +``` + +If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. + +**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. + +## Ordered vs Unordered Calls ## +By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. + +Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: + +``` +using ::testing::InSequence;... +TEST(FooTest, DrawsLineSegment) { + ... + { + InSequence dummy; + + EXPECT_CALL(turtle, PenDown()); + EXPECT_CALL(turtle, Forward(100)); + EXPECT_CALL(turtle, PenUp()); + } + Foo(); +} +``` + +By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. + +In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. + +(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_6_CookBook.md).) + +## All Expectations Are Sticky (Unless Said Otherwise) ## +Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? + +After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): + +``` +using ::testing::_;... +EXPECT_CALL(turtle, GoTo(_, _)) // #1 + .Times(AnyNumber()); +EXPECT_CALL(turtle, GoTo(0, 0)) // #2 + .Times(2); +``` + +Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. + +This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). + +Simple? Let's see if you've really understood it: what does the following code say? + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)); +} +``` + +If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! + +One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); +} +``` + +And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: + +``` +using ::testing::InSequence; +using ::testing::Return; +... +{ + InSequence s; + + for (int i = 1; i <= n; i++) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); + } +} +``` + +By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). + +## Uninteresting Calls ## +A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. + +In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. + +# What Now? # +Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. + +Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_6_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. \ No newline at end of file diff --git a/googlemock/docs/v1_6/FrequentlyAskedQuestions.md b/googlemock/docs/v1_6/FrequentlyAskedQuestions.md new file mode 100644 index 0000000..f74715d --- /dev/null +++ b/googlemock/docs/v1_6/FrequentlyAskedQuestions.md @@ -0,0 +1,628 @@ + + +Please send your questions to the +[googlemock](http://groups.google.com/group/googlemock) discussion +group. If you need help with compiler errors, make sure you have +tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. + +## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## + +In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods). + +## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## + +After version 1.4.0 of Google Mock was released, we had an idea on how +to make it easier to write matchers that can generate informative +messages efficiently. We experimented with this idea and liked what +we saw. Therefore we decided to implement it. + +Unfortunately, this means that if you have defined your own matchers +by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, +your definitions will no longer compile. Matchers defined using the +`MATCHER*` family of macros are not affected. + +Sorry for the hassle if your matchers are affected. We believe it's +in everyone's long-term interest to make this change sooner than +later. Fortunately, it's usually not hard to migrate an existing +matcher to the new API. Here's what you need to do: + +If you wrote your matcher like this: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` + +you'll need to change it to: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` +(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second +argument of type `MatchResultListener*`.) + +If you were also using `ExplainMatchResultTo()` to improve the matcher +message: +``` +// Old matcher definition that doesn't work with the lastest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + + virtual void ExplainMatchResultTo(MyType value, + ::std::ostream* os) const { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Foo property is " << value.GetFoo(); + } + ... +}; +``` + +you should move the logic of `ExplainMatchResultTo()` into +`MatchAndExplain()`, using the `MatchResultListener` argument where +the `::std::ostream` was used: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Foo property is " << value.GetFoo(); + return value.GetFoo() > 5; + } + ... +}; +``` + +If your matcher is defined using `MakePolymorphicMatcher()`: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you should rename the `Matches()` method to `MatchAndExplain()` and +add a `MatchResultListener*` argument (the same as what you need to do +for matchers defined by implementing `MatcherInterface`): +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +If your polymorphic matcher uses `ExplainMatchResultTo()` for better +failure messages: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +void ExplainMatchResultTo(const MyGreatMatcher& matcher, + MyType value, + ::std::ostream* os) { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Bar property is " << value.GetBar(); +} +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you'll need to move the logic inside `ExplainMatchResultTo()` to +`MatchAndExplain()`: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Bar property is " << value.GetBar(); + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +For more information, you can read these +[two](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Monomorphic_Matchers) +[recipes](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Matchers) +from the cookbook. As always, you +are welcome to post questions on `googlemock@googlegroups.com` if you +need any help. + +## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## + +Google Mock works out of the box with Google Test. However, it's easy +to configure it to work with any testing framework of your choice. +[Here](http://code.google.com/p/googlemock/wiki/V1_6_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how. + +## How am I supposed to make sense of these horrible template errors? ## + +If you are confused by the compiler errors gcc threw at you, +try consulting the _Google Mock Doctor_ tool first. What it does is to +scan stdin for gcc error messages, and spit out diagnoses on the +problems (we call them diseases) your code has. + +To "install", run command: +``` +alias gmd='/scripts/gmock_doctor.py' +``` + +To use it, do: +``` + 2>&1 | gmd +``` + +For example: +``` +make my_test 2>&1 | gmd +``` + +Or you can run `gmd` and copy-n-paste gcc's error messages to it. + +## Can I mock a variadic function? ## + +You cannot mock a variadic function (i.e. a function taking ellipsis +(`...`) arguments) directly in Google Mock. + +The problem is that in general, there is _no way_ for a mock object to +know how many arguments are passed to the variadic method, and what +the arguments' types are. Only the _author of the base class_ knows +the protocol, and we cannot look into his head. + +Therefore, to mock such a function, the _user_ must teach the mock +object how to figure out the number of arguments and their types. One +way to do it is to provide overloaded versions of the function. + +Ellipsis arguments are inherited from C and not really a C++ feature. +They are unsafe to use and don't work with arguments that have +constructors or destructors. Therefore we recommend to avoid them in +C++ as much as possible. + +## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## + +If you compile this using Microsoft Visual C++ 2005 SP1: +``` +class Foo { + ... + virtual void Bar(const int i) = 0; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Bar, void(const int i)); +}; +``` +You may get the following warning: +``` +warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier +``` + +This is a MSVC bug. The same code compiles fine with gcc ,for +example. If you use Visual C++ 2008 SP1, you would get the warning: +``` +warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers +``` + +In C++, if you _declare_ a function with a `const` parameter, the +`const` modifier is _ignored_. Therefore, the `Foo` base class above +is equivalent to: +``` +class Foo { + ... + virtual void Bar(int i) = 0; // int or const int? Makes no difference. +}; +``` + +In fact, you can _declare_ Bar() with an `int` parameter, and _define_ +it with a `const int` parameter. The compiler will still match them +up. + +Since making a parameter `const` is meaningless in the method +_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. +That should workaround the VC bug. + +Note that we are talking about the _top-level_ `const` modifier here. +If the function parameter is passed by pointer or reference, declaring +the _pointee_ or _referee_ as `const` is still meaningful. For +example, the following two declarations are _not_ equivalent: +``` +void Bar(int* p); // Neither p nor *p is const. +void Bar(const int* p); // p is not const, but *p is. +``` + +## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## + +We've noticed that when the `/clr` compiler flag is used, Visual C++ +uses 5~6 times as much memory when compiling a mock class. We suggest +to avoid `/clr` when compiling native C++ mocks. + +## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## + +You might want to run your test with +`--gmock_verbose=info`. This flag lets Google Mock print a trace +of every mock function call it receives. By studying the trace, +you'll gain insights on why the expectations you set are not met. + +## How can I assert that a function is NEVER called? ## + +``` +EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## + +When Google Mock detects a failure, it prints relevant information +(the mock function arguments, the state of relevant expectations, and +etc) to help the user debug. If another failure is detected, Google +Mock will do the same, including printing the state of relevant +expectations. + +Sometimes an expectation's state didn't change between two failures, +and you'll see the same description of the state twice. They are +however _not_ redundant, as they refer to _different points in time_. +The fact they are the same _is_ interesting information. + +## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## + +Does the class (hopefully a pure interface) you are mocking have a +virtual destructor? + +Whenever you derive from a base class, make sure its destructor is +virtual. Otherwise Bad Things will happen. Consider the following +code: + +``` +class Base { + public: + // Not virtual, but should be. + ~Base() { ... } + ... +}; + +class Derived : public Base { + public: + ... + private: + std::string value_; +}; + +... + Base* p = new Derived; + ... + delete p; // Surprise! ~Base() will be called, but ~Derived() will not + // - value_ is leaked. +``` + +By changing `~Base()` to virtual, `~Derived()` will be correctly +called when `delete p` is executed, and the heap checker +will be happy. + +## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## + +When people complain about this, often they are referring to code like: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. However, I have to write the expectations in the +// reverse order. This sucks big time!!! +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); +``` + +The problem is that they didn't pick the **best** way to express the test's +intent. + +By default, expectations don't have to be matched in _any_ particular +order. If you want them to match in a certain order, you need to be +explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's +easy to accidentally over-specify your tests, and we want to make it +harder to do so. + +There are two better ways to write the test spec. You could either +put the expectations in sequence: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. Using a sequence, we can write the expectations +// in their natural order. +{ + InSequence s; + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +} +``` + +or you can put the sequence of actions in the same expectation: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +``` + +Back to the original questions: why does Google Mock search the +expectations (and `ON_CALL`s) from back to front? Because this +allows a user to set up a mock's behavior for the common case early +(e.g. in the mock's constructor or the test fixture's set-up phase) +and customize it with more specific rules later. If Google Mock +searches from front to back, this very useful pattern won't be +possible. + +## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## + +When choosing between being neat and being safe, we lean toward the +latter. So the answer is that we think it's better to show the +warning. + +Often people write `ON_CALL`s in the mock object's +constructor or `SetUp()`, as the default behavior rarely changes from +test to test. Then in the test body they set the expectations, which +are often different for each test. Having an `ON_CALL` in the set-up +part of a test doesn't mean that the calls are expected. If there's +no `EXPECT_CALL` and the method is called, it's possibly an error. If +we quietly let the call go through without notifying the user, bugs +may creep in unnoticed. + +If, however, you are sure that the calls are OK, you can write + +``` +EXPECT_CALL(foo, Bar(_)) + .WillRepeatedly(...); +``` + +instead of + +``` +ON_CALL(foo, Bar(_)) + .WillByDefault(...); +``` + +This tells Google Mock that you do expect the calls and no warning should be +printed. + +Also, you can control the verbosity using the `--gmock_verbose` flag. +If you find the output too noisy when debugging, just choose a less +verbose level. + +## How can I delete the mock function's argument in an action? ## + +If you find yourself needing to perform some action that's not +supported by Google Mock directly, remember that you can define your own +actions using +[MakeAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Actions) or +[MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Actions), +or you can write a stub function and invoke it using +[Invoke()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Functions_Methods_Functors). + +## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## + +What?! I think it's beautiful. :-) + +While which syntax looks more natural is a subjective matter to some +extent, Google Mock's syntax was chosen for several practical advantages it +has. + +Try to mock a function that takes a map as an argument: +``` +virtual int GetSize(const map& m); +``` + +Using the proposed syntax, it would be: +``` +MOCK_METHOD1(GetSize, int, const map& m); +``` + +Guess what? You'll get a compiler error as the compiler thinks that +`const map& m` are **two**, not one, arguments. To work +around this you can use `typedef` to give the map type a name, but +that gets in the way of your work. Google Mock's syntax avoids this +problem as the function's argument types are protected inside a pair +of parentheses: +``` +// This compiles fine. +MOCK_METHOD1(GetSize, int(const map& m)); +``` + +You still need a `typedef` if the return type contains an unprotected +comma, but that's much rarer. + +Other advantages include: + 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. + 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. + 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! + +## My code calls a static/global function. Can I mock it? ## + +You can, but you need to make some changes. + +In general, if you find yourself needing to mock a static function, +it's a sign that your modules are too tightly coupled (and less +flexible, less reusable, less testable, etc). You are probably better +off defining a small interface and call the function through that +interface, which then can be easily mocked. It's a bit of work +initially, but usually pays for itself quickly. + +This Google Testing Blog +[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) +says it excellently. Check it out. + +## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## + +I know it's not a question, but you get an answer for free any way. :-) + +With Google Mock, you can create mocks in C++ easily. And people might be +tempted to use them everywhere. Sometimes they work great, and +sometimes you may find them, well, a pain to use. So, what's wrong in +the latter case? + +When you write a test without using mocks, you exercise the code and +assert that it returns the correct value or that the system is in an +expected state. This is sometimes called "state-based testing". + +Mocks are great for what some call "interaction-based" testing: +instead of checking the system state at the very end, mock objects +verify that they are invoked the right way and report an error as soon +as it arises, giving you a handle on the precise context in which the +error was triggered. This is often more effective and economical to +do than state-based testing. + +If you are doing state-based testing and using a test double just to +simulate the real object, you are probably better off using a fake. +Using a mock in this case causes pain, as it's not a strong point for +mocks to perform complex actions. If you experience this and think +that mocks suck, you are just not using the right tool for your +problem. Or, you might be trying to solve the wrong problem. :-) + +## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## + +By all means, NO! It's just an FYI. + +What it means is that you have a mock function, you haven't set any +expectations on it (by Google Mock's rule this means that you are not +interested in calls to this function and therefore it can be called +any number of times), and it is called. That's OK - you didn't say +it's not OK to call the function! + +What if you actually meant to disallow this function to be called, but +forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While +one can argue that it's the user's fault, Google Mock tries to be nice and +prints you a note. + +So, when you see the message and believe that there shouldn't be any +uninteresting calls, you should investigate what's going on. To make +your life easier, Google Mock prints the function name and arguments +when an uninteresting call is encountered. + +## I want to define a custom action. Should I use Invoke() or implement the action interface? ## + +Either way is fine - you want to choose the one that's more convenient +for your circumstance. + +Usually, if your action is for a particular function type, defining it +using `Invoke()` should be easier; if your action can be used in +functions of different types (e.g. if you are defining +`Return(value)`), `MakePolymorphicAction()` is +easiest. Sometimes you want precise control on what types of +functions the action can be used in, and implementing +`ActionInterface` is the way to go here. See the implementation of +`Return()` in `include/gmock/gmock-actions.h` for an example. + +## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## + +You got this error as Google Mock has no idea what value it should return +when the mock method is called. `SetArgPointee()` says what the +side effect is, but doesn't say what the return value should be. You +need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. + +See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Side_Effects) for more details and an example. + + +## My question is not in your FAQ! ## + +If you cannot find the answer to your question in this FAQ, there are +some other resources you can use: + + 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), + 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), + 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). + +Please note that creating an issue in the +[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ +a good way to get your answer, as it is monitored infrequently by a +very small number of people. + +When asking a question, it's helpful to provide as much of the +following information as possible (people cannot help you if there's +not enough information in your question): + + * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), + * your operating system, + * the name and version of your compiler, + * the complete command line flags you give to your compiler, + * the complete compiler error messages (if the question is about compilation), + * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. \ No newline at end of file diff --git a/googlemock/docs/v1_7/CheatSheet.md b/googlemock/docs/v1_7/CheatSheet.md new file mode 100644 index 0000000..db421e5 --- /dev/null +++ b/googlemock/docs/v1_7/CheatSheet.md @@ -0,0 +1,556 @@ + + +# Defining a Mock Class # + +## Mocking a Normal Class ## + +Given +``` +class Foo { + ... + virtual ~Foo(); + virtual int GetSize() const = 0; + virtual string Describe(const char* name) = 0; + virtual string Describe(int type) = 0; + virtual bool Process(Bar elem, int count) = 0; +}; +``` +(note that `~Foo()` **must** be virtual) we can define its mock as +``` +#include "gmock/gmock.h" + +class MockFoo : public Foo { + MOCK_CONST_METHOD0(GetSize, int()); + MOCK_METHOD1(Describe, string(const char* name)); + MOCK_METHOD1(Describe, string(int type)); + MOCK_METHOD2(Process, bool(Bar elem, int count)); +}; +``` + +To create a "nice" mock object which ignores all uninteresting calls, +or a "strict" mock object, which treats them as failures: +``` +NiceMock nice_foo; // The type is a subclass of MockFoo. +StrictMock strict_foo; // The type is a subclass of MockFoo. +``` + +## Mocking a Class Template ## + +To mock +``` +template +class StackInterface { + public: + ... + virtual ~StackInterface(); + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; +``` +(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: +``` +template +class MockStack : public StackInterface { + public: + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Specifying Calling Conventions for Mock Functions ## + +If your mock function doesn't use the default calling convention, you +can specify it by appending `_WITH_CALLTYPE` to any of the macros +described in the previous two sections and supplying the calling +convention as the first argument to the macro. For example, +``` + MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); + MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); +``` +where `STDMETHODCALLTYPE` is defined by `` on Windows. + +# Using Mocks in Tests # + +The typical flow is: + 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. + 1. Create the mock objects. + 1. Optionally, set the default actions of the mock objects. + 1. Set your expectations on the mock objects (How will they be called? What wil they do?). + 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. + 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. + +Here is an example: +``` +using ::testing::Return; // #1 + +TEST(BarTest, DoesThis) { + MockFoo foo; // #2 + + ON_CALL(foo, GetSize()) // #3 + .WillByDefault(Return(1)); + // ... other default actions ... + + EXPECT_CALL(foo, Describe(5)) // #4 + .Times(3) + .WillRepeatedly(Return("Category 5")); + // ... other expectations ... + + EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 +} // #6 +``` + +# Setting Default Actions # + +Google Mock has a **built-in default action** for any function that +returns `void`, `bool`, a numeric value, or a pointer. + +To customize the default action for functions with return type `T` globally: +``` +using ::testing::DefaultValue; + +DefaultValue::Set(value); // Sets the default value to be returned. +// ... use the mocks ... +DefaultValue::Clear(); // Resets the default value. +``` + +To customize the default action for a particular method, use `ON_CALL()`: +``` +ON_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .WillByDefault(action); +``` + +# Setting Expectations # + +`EXPECT_CALL()` sets **expectations** on a mock method (How will it be +called? What will it do?): +``` +EXPECT_CALL(mock_object, method(matchers)) + .With(multi_argument_matcher) ? + .Times(cardinality) ? + .InSequence(sequences) * + .After(expectations) * + .WillOnce(action) * + .WillRepeatedly(action) ? + .RetiresOnSaturation(); ? +``` + +If `Times()` is omitted, the cardinality is assumed to be: + + * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; + * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or + * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. + +A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. + +# Matchers # + +A **matcher** matches a _single_ argument. You can use it inside +`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value +directly: + +| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | +|:------------------------------|:----------------------------------------| +| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | + +Built-in matchers (where `argument` is the function argument) are +divided into several categories: + +## Wildcard ## +|`_`|`argument` can be any value of the correct type.| +|:--|:-----------------------------------------------| +|`A()` or `An()`|`argument` can be any value of type `type`. | + +## Generic Comparison ## + +|`Eq(value)` or `value`|`argument == value`| +|:---------------------|:------------------| +|`Ge(value)` |`argument >= value`| +|`Gt(value)` |`argument > value` | +|`Le(value)` |`argument <= value`| +|`Lt(value)` |`argument < value` | +|`Ne(value)` |`argument != value`| +|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| +|`NotNull()` |`argument` is a non-null pointer (raw or smart).| +|`Ref(variable)` |`argument` is a reference to `variable`.| +|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| + +Except `Ref()`, these matchers make a _copy_ of `value` in case it's +modified or destructed later. If the compiler complains that `value` +doesn't have a public copy constructor, try wrap it in `ByRef()`, +e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure +`non_copyable_value` is not changed afterwards, or the meaning of your +matcher will be changed. + +## Floating-Point Matchers ## + +|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| +|:-------------------|:----------------------------------------------------------------------------------------------| +|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | +|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | +|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | + +The above matchers use ULP-based comparison (the same as used in +[Google Test](http://code.google.com/p/googletest/)). They +automatically pick a reasonable error bound based on the absolute +value of the expected value. `DoubleEq()` and `FloatEq()` conform to +the IEEE standard, which requires comparing two NaNs for equality to +return false. The `NanSensitive*` version instead treats two NaNs as +equal, which is often what a user wants. + +|`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.| +|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------| +|`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | +|`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | +|`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | + +## String Matchers ## + +The `argument` can be either a C string or a C++ string object: + +|`ContainsRegex(string)`|`argument` matches the given regular expression.| +|:----------------------|:-----------------------------------------------| +|`EndsWith(suffix)` |`argument` ends with string `suffix`. | +|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | +|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| +|`StartsWith(prefix)` |`argument` starts with string `prefix`. | +|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | +|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| +|`StrEq(string)` |`argument` is equal to `string`. | +|`StrNe(string)` |`argument` is not equal to `string`. | + +`ContainsRegex()` and `MatchesRegex()` use the regular expression +syntax defined +[here](http://code.google.com/p/googletest/wiki/AdvancedGuide#Regular_Expression_Syntax). +`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide +strings as well. + +## Container Matchers ## + +Most STL-style containers support `==`, so you can use +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. If you want to write the elements in-line, +match them more flexibly, or get more informative messages, you can use: + +| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | +|:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------| +| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | +| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | +| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | +| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. | +| `IsEmpty()` | `argument` is an empty container (`container.empty()`). | +| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | +| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | +| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. | +| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. | +| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. | +| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | + +Notes: + + * These matchers can also match: + 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and + 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). + * The array being matched may be multi-dimensional (i.e. its elements can be arrays). + * `m` in `Pointwise(m, ...)` should be a matcher for `std::tr1::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write: + +``` +using ::std::tr1::get; +MATCHER(FooEq, "") { + return get<0>(arg).Equals(get<1>(arg)); +} +... +EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); +``` + +## Member Matchers ## + +|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| +|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| +|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| +|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | +|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| + +## Matching the Result of a Function or Functor ## + +|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| +|:---------------|:---------------------------------------------------------------------| + +## Pointer Matchers ## + +|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| +|:-----------|:-----------------------------------------------------------------------------------------------| + +## Multiargument Matchers ## + +Technically, all matchers match a _single_ value. A "multi-argument" +matcher is just one that matches a _tuple_. The following matchers can +be used to match a tuple `(x, y)`: + +|`Eq()`|`x == y`| +|:-----|:-------| +|`Ge()`|`x >= y`| +|`Gt()`|`x > y` | +|`Le()`|`x <= y`| +|`Lt()`|`x < y` | +|`Ne()`|`x != y`| + +You can use the following selectors to pick a subset of the arguments +(or reorder them) to participate in the matching: + +|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| +|:-----------|:-------------------------------------------------------------------| +|`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| + +## Composite Matchers ## + +You can make a matcher from one or more other matchers: + +|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| +|:-----------------------|:---------------------------------------------------| +|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| +|`Not(m)` |`argument` doesn't match matcher `m`. | + +## Adapters for Matchers ## + +|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| +|:------------------|:--------------------------------------| +|`SafeMatcherCast(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Casting_Matchers) matcher `m` to type `Matcher`. | +|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| + +## Matchers as Predicates ## + +|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| +|:------------------|:---------------------------------------------------------------------------------------------| +|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | +|`Value(value, m)` |evaluates to `true` if `value` matches `m`. | + +## Defining Matchers ## + +| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | +|:-------------------------------------------------|:------------------------------------------------------| +| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | +| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | + +**Notes:** + + 1. The `MATCHER*` macros cannot be used inside a function or class. + 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). + 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. + +## Matchers as Test Assertions ## + +|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/Primer#Assertions) if the value of `expression` doesn't match matcher `m`.| +|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| +|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | + +# Actions # + +**Actions** specify what a mock function should do when invoked. + +## Returning a Value ## + +|`Return()`|Return from a `void` mock function.| +|:---------|:----------------------------------| +|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| +|`ReturnArg()`|Return the `N`-th (0-based) argument.| +|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| +|`ReturnNull()`|Return a null pointer. | +|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| +|`ReturnRef(variable)`|Return a reference to `variable`. | +|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| + +## Side Effects ## + +|`Assign(&variable, value)`|Assign `value` to variable.| +|:-------------------------|:--------------------------| +| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | +| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | +| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | +| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | +|`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| +|`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| +|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| +|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| +|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| + +## Using a Function or a Functor as an Action ## + +|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| +|:----------|:-----------------------------------------------------------------------------------------------------------------| +|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | +|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | +|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | +|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| + +The return value of the invoked function is used as the return value +of the action. + +When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: +``` + double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } + ... + EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); +``` + +In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, +``` + InvokeArgument<2>(5, string("Hi"), ByRef(foo)) +``` +calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. + +## Default Action ## + +|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| +|:------------|:--------------------------------------------------------------------| + +**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. + +## Composite Actions ## + +|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | +|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| +|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | +|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | +|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | +|`WithoutArgs(a)` |Perform action `a` without any arguments. | + +## Defining Actions ## + +| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | +|:--------------------------------------|:---------------------------------------------------------------------------------------| +| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | +| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | + +The `ACTION*` macros cannot be used inside a function or class. + +# Cardinalities # + +These are used in `Times()` to specify how many times a mock function will be called: + +|`AnyNumber()`|The function can be called any number of times.| +|:------------|:----------------------------------------------| +|`AtLeast(n)` |The call is expected at least `n` times. | +|`AtMost(n)` |The call is expected at most `n` times. | +|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| +|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| + +# Expectation Order # + +By default, the expectations can be matched in _any_ order. If some +or all expectations must be matched in a given order, there are two +ways to specify it. They can be used either independently or +together. + +## The After Clause ## + +``` +using ::testing::Expectation; +... +Expectation init_x = EXPECT_CALL(foo, InitX()); +Expectation init_y = EXPECT_CALL(foo, InitY()); +EXPECT_CALL(foo, Bar()) + .After(init_x, init_y); +``` +says that `Bar()` can be called only after both `InitX()` and +`InitY()` have been called. + +If you don't know how many pre-requisites an expectation has when you +write it, you can use an `ExpectationSet` to collect them: + +``` +using ::testing::ExpectationSet; +... +ExpectationSet all_inits; +for (int i = 0; i < element_count; i++) { + all_inits += EXPECT_CALL(foo, InitElement(i)); +} +EXPECT_CALL(foo, Bar()) + .After(all_inits); +``` +says that `Bar()` can be called only after all elements have been +initialized (but we don't care about which elements get initialized +before the others). + +Modifying an `ExpectationSet` after using it in an `.After()` doesn't +affect the meaning of the `.After()`. + +## Sequences ## + +When you have a long chain of sequential expectations, it's easier to +specify the order using **sequences**, which don't require you to given +each expectation in the chain a different name. All expected
+calls
in the same sequence must occur in the order they are +specified. + +``` +using ::testing::Sequence; +Sequence s1, s2; +... +EXPECT_CALL(foo, Reset()) + .InSequence(s1, s2) + .WillOnce(Return(true)); +EXPECT_CALL(foo, GetSize()) + .InSequence(s1) + .WillOnce(Return(1)); +EXPECT_CALL(foo, Describe(A())) + .InSequence(s2) + .WillOnce(Return("dummy")); +``` +says that `Reset()` must be called before _both_ `GetSize()` _and_ +`Describe()`, and the latter two can occur in any order. + +To put many expectations in a sequence conveniently: +``` +using ::testing::InSequence; +{ + InSequence dummy; + + EXPECT_CALL(...)...; + EXPECT_CALL(...)...; + ... + EXPECT_CALL(...)...; +} +``` +says that all expected calls in the scope of `dummy` must occur in +strict order. The name `dummy` is irrelevant.) + +# Verifying and Resetting a Mock # + +Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: +``` +using ::testing::Mock; +... +// Verifies and removes the expectations on mock_obj; +// returns true iff successful. +Mock::VerifyAndClearExpectations(&mock_obj); +... +// Verifies and removes the expectations on mock_obj; +// also removes the default actions set by ON_CALL(); +// returns true iff successful. +Mock::VerifyAndClear(&mock_obj); +``` + +You can also tell Google Mock that a mock object can be leaked and doesn't +need to be verified: +``` +Mock::AllowLeak(&mock_obj); +``` + +# Mock Classes # + +Google Mock defines a convenient mock class template +``` +class MockFunction { + public: + MOCK_METHODn(Call, R(A1, ..., An)); +}; +``` +See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Check_Points) for one application of it. + +# Flags # + +| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | +|:-------------------------------|:----------------------------------------------| +| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | \ No newline at end of file diff --git a/googlemock/docs/v1_7/CookBook.md b/googlemock/docs/v1_7/CookBook.md new file mode 100644 index 0000000..419a001 --- /dev/null +++ b/googlemock/docs/v1_7/CookBook.md @@ -0,0 +1,3432 @@ + + +You can find recipes for using Google Mock here. If you haven't yet, +please read the [ForDummies](V1_7_ForDummies.md) document first to make sure you understand +the basics. + +**Note:** Google Mock lives in the `testing` name space. For +readability, it is recommended to write `using ::testing::Foo;` once in +your file before using the name `Foo` defined by Google Mock. We omit +such `using` statements in this page for brevity, but you should do it +in your own code. + +# Creating Mock Classes # + +## Mocking Private or Protected Methods ## + +You must always put a mock method definition (`MOCK_METHOD*`) in a +`public:` section of the mock class, regardless of the method being +mocked being `public`, `protected`, or `private` in the base class. +This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function +from outside of the mock class. (Yes, C++ allows a subclass to change +the access level of a virtual function in the base class.) Example: + +``` +class Foo { + public: + ... + virtual bool Transform(Gadget* g) = 0; + + protected: + virtual void Resume(); + + private: + virtual int GetTimeOut(); +}; + +class MockFoo : public Foo { + public: + ... + MOCK_METHOD1(Transform, bool(Gadget* g)); + + // The following must be in the public section, even though the + // methods are protected or private in the base class. + MOCK_METHOD0(Resume, void()); + MOCK_METHOD0(GetTimeOut, int()); +}; +``` + +## Mocking Overloaded Methods ## + +You can mock overloaded functions as usual. No special attention is required: + +``` +class Foo { + ... + + // Must be virtual as we'll inherit from Foo. + virtual ~Foo(); + + // Overloaded on the types and/or numbers of arguments. + virtual int Add(Element x); + virtual int Add(int times, Element x); + + // Overloaded on the const-ness of this object. + virtual Bar& GetBar(); + virtual const Bar& GetBar() const; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Add, int(Element x)); + MOCK_METHOD2(Add, int(int times, Element x); + + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +``` + +**Note:** if you don't mock all versions of the overloaded method, the +compiler will give you a warning about some methods in the base class +being hidden. To fix that, use `using` to bring them in scope: + +``` +class MockFoo : public Foo { + ... + using Foo::Add; + MOCK_METHOD1(Add, int(Element x)); + // We don't want to mock int Add(int times, Element x); + ... +}; +``` + +## Mocking Class Templates ## + +To mock a class template, append `_T` to the `MOCK_*` macros: + +``` +template +class StackInterface { + ... + // Must be virtual as we'll inherit from StackInterface. + virtual ~StackInterface(); + + virtual int GetSize() const = 0; + virtual void Push(const Elem& x) = 0; +}; + +template +class MockStack : public StackInterface { + ... + MOCK_CONST_METHOD0_T(GetSize, int()); + MOCK_METHOD1_T(Push, void(const Elem& x)); +}; +``` + +## Mocking Nonvirtual Methods ## + +Google Mock can mock non-virtual functions to be used in what we call _hi-perf +dependency injection_. + +In this case, instead of sharing a common base class with the real +class, your mock class will be _unrelated_ to the real class, but +contain methods with the same signatures. The syntax for mocking +non-virtual methods is the _same_ as mocking virtual methods: + +``` +// A simple packet stream class. None of its members is virtual. +class ConcretePacketStream { + public: + void AppendPacket(Packet* new_packet); + const Packet* GetPacket(size_t packet_number) const; + size_t NumberOfPackets() const; + ... +}; + +// A mock packet stream class. It inherits from no other, but defines +// GetPacket() and NumberOfPackets(). +class MockPacketStream { + public: + MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); + MOCK_CONST_METHOD0(NumberOfPackets, size_t()); + ... +}; +``` + +Note that the mock class doesn't define `AppendPacket()`, unlike the +real class. That's fine as long as the test doesn't need to call it. + +Next, you need a way to say that you want to use +`ConcretePacketStream` in production code, and use `MockPacketStream` +in tests. Since the functions are not virtual and the two classes are +unrelated, you must specify your choice at _compile time_ (as opposed +to run time). + +One way to do it is to templatize your code that needs to use a packet +stream. More specifically, you will give your code a template type +argument for the type of the packet stream. In production, you will +instantiate your template with `ConcretePacketStream` as the type +argument. In tests, you will instantiate the same template with +`MockPacketStream`. For example, you may write: + +``` +template +void CreateConnection(PacketStream* stream) { ... } + +template +class PacketReader { + public: + void ReadPackets(PacketStream* stream, size_t packet_num); +}; +``` + +Then you can use `CreateConnection()` and +`PacketReader` in production code, and use +`CreateConnection()` and +`PacketReader` in tests. + +``` + MockPacketStream mock_stream; + EXPECT_CALL(mock_stream, ...)...; + .. set more expectations on mock_stream ... + PacketReader reader(&mock_stream); + ... exercise reader ... +``` + +## Mocking Free Functions ## + +It's possible to use Google Mock to mock a free function (i.e. a +C-style function or a static method). You just need to rewrite your +code to use an interface (abstract class). + +Instead of calling a free function (say, `OpenFile`) directly, +introduce an interface for it and have a concrete subclass that calls +the free function: + +``` +class FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) = 0; +}; + +class File : public FileInterface { + public: + ... + virtual bool Open(const char* path, const char* mode) { + return OpenFile(path, mode); + } +}; +``` + +Your code should talk to `FileInterface` to open a file. Now it's +easy to mock out the function. + +This may seem much hassle, but in practice you often have multiple +related functions that you can put in the same interface, so the +per-function syntactic overhead will be much lower. + +If you are concerned about the performance overhead incurred by +virtual functions, and profiling confirms your concern, you can +combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). + +## The Nice, the Strict, and the Naggy ## + +If a mock method has no `EXPECT_CALL` spec but is called, Google Mock +will print a warning about the "uninteresting call". The rationale is: + + * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. + * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. + +However, sometimes you may want to suppress all "uninteresting call" +warnings, while sometimes you may want the opposite, i.e. to treat all +of them as errors. Google Mock lets you make the decision on a +per-mock-object basis. + +Suppose your test uses a mock class `MockFoo`: + +``` +TEST(...) { + MockFoo mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +If a method of `mock_foo` other than `DoThis()` is called, it will be +reported by Google Mock as a warning. However, if you rewrite your +test to use `NiceMock` instead, the warning will be gone, +resulting in a cleaner test output: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +`NiceMock` is a subclass of `MockFoo`, so it can be used +wherever `MockFoo` is accepted. + +It also works if `MockFoo`'s constructor takes some arguments, as +`NiceMock` "inherits" `MockFoo`'s constructors: + +``` +using ::testing::NiceMock; + +TEST(...) { + NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... +} +``` + +The usage of `StrictMock` is similar, except that it makes all +uninteresting calls failures: + +``` +using ::testing::StrictMock; + +TEST(...) { + StrictMock mock_foo; + EXPECT_CALL(mock_foo, DoThis()); + ... code that uses mock_foo ... + + // The test will fail if a method of mock_foo other than DoThis() + // is called. +} +``` + +There are some caveats though (I don't like them just as much as the +next guy, but sadly they are side effects of C++'s limitations): + + 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. + 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). + 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) + +Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. + +## Simplifying the Interface without Breaking Existing Code ## + +Sometimes a method has a long list of arguments that is mostly +uninteresting. For example, + +``` +class LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const struct tm* tm_time, + const char* message, size_t message_len) = 0; +}; +``` + +This method's argument list is lengthy and hard to work with (let's +say that the `message` argument is not even 0-terminated). If we mock +it as is, using the mock will be awkward. If, however, we try to +simplify this interface, we'll need to fix all clients depending on +it, which is often infeasible. + +The trick is to re-dispatch the method in the mock class: + +``` +class ScopedMockLog : public LogSink { + public: + ... + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, const tm* tm_time, + const char* message, size_t message_len) { + // We are only interested in the log severity, full file name, and + // log message. + Log(severity, full_filename, std::string(message, message_len)); + } + + // Implements the mock method: + // + // void Log(LogSeverity severity, + // const string& file_path, + // const string& message); + MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, + const string& message)); +}; +``` + +By defining a new mock method with a trimmed argument list, we make +the mock class much more user-friendly. + +## Alternative to Mocking Concrete Classes ## + +Often you may find yourself using classes that don't implement +interfaces. In order to test your code that uses such a class (let's +call it `Concrete`), you may be tempted to make the methods of +`Concrete` virtual and then mock it. + +Try not to do that. + +Making a non-virtual function virtual is a big decision. It creates an +extension point where subclasses can tweak your class' behavior. This +weakens your control on the class because now it's harder to maintain +the class' invariants. You should make a function virtual only when +there is a valid reason for a subclass to override it. + +Mocking concrete classes directly is problematic as it creates a tight +coupling between the class and the tests - any small change in the +class may invalidate your tests and make test maintenance a pain. + +To avoid such problems, many programmers have been practicing "coding +to interfaces": instead of talking to the `Concrete` class, your code +would define an interface and talk to it. Then you implement that +interface as an adaptor on top of `Concrete`. In tests, you can easily +mock that interface to observe how your code is doing. + +This technique incurs some overhead: + + * You pay the cost of virtual function calls (usually not a problem). + * There is more abstraction for the programmers to learn. + +However, it can also bring significant benefits in addition to better +testability: + + * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. + * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. + +Some people worry that if everyone is practicing this technique, they +will end up writing lots of redundant code. This concern is totally +understandable. However, there are two reasons why it may not be the +case: + + * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. + * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. + +You need to weigh the pros and cons carefully for your particular +problem, but I'd like to assure you that the Java community has been +practicing this for a long time and it's a proven effective technique +applicable in a wide variety of situations. :-) + +## Delegating Calls to a Fake ## + +Some times you have a non-trivial fake implementation of an +interface. For example: + +``` +class Foo { + public: + virtual ~Foo() {} + virtual char DoThis(int n) = 0; + virtual void DoThat(const char* s, int* p) = 0; +}; + +class FakeFoo : public Foo { + public: + virtual char DoThis(int n) { + return (n > 0) ? '+' : + (n < 0) ? '-' : '0'; + } + + virtual void DoThat(const char* s, int* p) { + *p = strlen(s); + } +}; +``` + +Now you want to mock this interface such that you can set expectations +on it. However, you also want to use `FakeFoo` for the default +behavior, as duplicating it in the mock object is, well, a lot of +work. + +When you define the mock class using Google Mock, you can have it +delegate its default action to a fake class you already have, using +this pattern: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + // Normal mock method definitions using Google Mock. + MOCK_METHOD1(DoThis, char(int n)); + MOCK_METHOD2(DoThat, void(const char* s, int* p)); + + // Delegates the default actions of the methods to a FakeFoo object. + // This must be called *before* the custom ON_CALL() statements. + void DelegateToFake() { + ON_CALL(*this, DoThis(_)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); + ON_CALL(*this, DoThat(_, _)) + .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); + } + private: + FakeFoo fake_; // Keeps an instance of the fake in the mock. +}; +``` + +With that, you can use `MockFoo` in your tests as usual. Just remember +that if you don't explicitly set an action in an `ON_CALL()` or +`EXPECT_CALL()`, the fake will be called upon to do it: + +``` +using ::testing::_; + +TEST(AbcTest, Xyz) { + MockFoo foo; + foo.DelegateToFake(); // Enables the fake for delegation. + + // Put your ON_CALL(foo, ...)s here, if any. + + // No action specified, meaning to use the default action. + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(foo, DoThat(_, _)); + + int n = 0; + EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. + foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. + EXPECT_EQ(2, n); +} +``` + +**Some tips:** + + * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. + * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. + * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). + * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. + +Regarding the tip on mixing a mock and a fake, here's an example on +why it may be a bad sign: Suppose you have a class `System` for +low-level system operations. In particular, it does file and I/O +operations. And suppose you want to test how your code uses `System` +to do I/O, and you just want the file operations to work normally. If +you mock out the entire `System` class, you'll have to provide a fake +implementation for the file operation part, which suggests that +`System` is taking on too many roles. + +Instead, you can define a `FileOps` interface and an `IOOps` interface +and split `System`'s functionalities into the two. Then you can mock +`IOOps` without mocking `FileOps`. + +## Delegating Calls to a Real Object ## + +When using testing doubles (mocks, fakes, stubs, and etc), sometimes +their behaviors will differ from those of the real objects. This +difference could be either intentional (as in simulating an error such +that you can test the error handling code) or unintentional. If your +mocks have different behaviors than the real objects by mistake, you +could end up with code that passes the tests but fails in production. + +You can use the _delegating-to-real_ technique to ensure that your +mock has the same behavior as the real object while retaining the +ability to validate calls. This technique is very similar to the +delegating-to-fake technique, the difference being that we use a real +object instead of a fake. Here's an example: + +``` +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MockFoo() { + // By default, all calls are delegated to the real object. + ON_CALL(*this, DoThis()) + .WillByDefault(Invoke(&real_, &Foo::DoThis)); + ON_CALL(*this, DoThat(_)) + .WillByDefault(Invoke(&real_, &Foo::DoThat)); + ... + } + MOCK_METHOD0(DoThis, ...); + MOCK_METHOD1(DoThat, ...); + ... + private: + Foo real_; +}; +... + + MockFoo mock; + + EXPECT_CALL(mock, DoThis()) + .Times(3); + EXPECT_CALL(mock, DoThat("Hi")) + .Times(AtLeast(1)); + ... use mock in test ... +``` + +With this, Google Mock will verify that your code made the right calls +(with the right arguments, in the right order, called the right number +of times, etc), and a real object will answer the calls (so the +behavior will be the same as in production). This gives you the best +of both worlds. + +## Delegating Calls to a Parent Class ## + +Ideally, you should code to interfaces, whose methods are all pure +virtual. In reality, sometimes you do need to mock a virtual method +that is not pure (i.e, it already has an implementation). For example: + +``` +class Foo { + public: + virtual ~Foo(); + + virtual void Pure(int n) = 0; + virtual int Concrete(const char* str) { ... } +}; + +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); +}; +``` + +Sometimes you may want to call `Foo::Concrete()` instead of +`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub +action, or perhaps your test doesn't need to mock `Concrete()` at all +(but it would be oh-so painful to have to define a new mock class +whenever you don't need to mock one of its methods). + +The trick is to leave a back door in your mock class for accessing the +real methods in the base class: + +``` +class MockFoo : public Foo { + public: + // Mocking a pure method. + MOCK_METHOD1(Pure, void(int n)); + // Mocking a concrete method. Foo::Concrete() is shadowed. + MOCK_METHOD1(Concrete, int(const char* str)); + + // Use this to call Concrete() defined in Foo. + int FooConcrete(const char* str) { return Foo::Concrete(str); } +}; +``` + +Now, you can call `Foo::Concrete()` inside an action by: + +``` +using ::testing::_; +using ::testing::Invoke; +... + EXPECT_CALL(foo, Concrete(_)) + .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +or tell the mock object that you don't want to mock `Concrete()`: + +``` +using ::testing::Invoke; +... + ON_CALL(foo, Concrete(_)) + .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); +``` + +(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do +that, `MockFoo::Concrete()` will be called (and cause an infinite +recursion) since `Foo::Concrete()` is virtual. That's just how C++ +works.) + +# Using Matchers # + +## Matching Argument Values Exactly ## + +You can specify exactly which arguments a mock method is expecting: + +``` +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(5)) + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", bar)); +``` + +## Using Simple Matchers ## + +You can use matchers to match arguments that have a certain property: + +``` +using ::testing::Ge; +using ::testing::NotNull; +using ::testing::Return; +... + EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. + .WillOnce(Return('a')); + EXPECT_CALL(foo, DoThat("Hello", NotNull())); + // The second argument must not be NULL. +``` + +A frequently used matcher is `_`, which matches anything: + +``` +using ::testing::_; +using ::testing::NotNull; +... + EXPECT_CALL(foo, DoThat(_, NotNull())); +``` + +## Combining Matchers ## + +You can build complex matchers from existing ones using `AllOf()`, +`AnyOf()`, and `Not()`: + +``` +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::HasSubstr; +using ::testing::Ne; +using ::testing::Not; +... + // The argument must be > 5 and != 10. + EXPECT_CALL(foo, DoThis(AllOf(Gt(5), + Ne(10)))); + + // The first argument must not contain sub-string "blah". + EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), + NULL)); +``` + +## Casting Matchers ## + +Google Mock matchers are statically typed, meaning that the compiler +can catch your mistake if you use a matcher of the wrong type (for +example, if you use `Eq(5)` to match a `string` argument). Good for +you! + +Sometimes, however, you know what you're doing and want the compiler +to give you some slack. One example is that you have a matcher for +`long` and the argument you want to match is `int`. While the two +types aren't exactly the same, there is nothing really wrong with +using a `Matcher` to match an `int` - after all, we can first +convert the `int` argument to a `long` before giving it to the +matcher. + +To support this need, Google Mock gives you the +`SafeMatcherCast(m)` function. It casts a matcher `m` to type +`Matcher`. To ensure safety, Google Mock checks that (let `U` be the +type `m` accepts): + + 1. Type `T` can be implicitly cast to type `U`; + 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and + 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). + +The code won't compile if any of these conditions isn't met. + +Here's one example: + +``` +using ::testing::SafeMatcherCast; + +// A base class and a child class. +class Base { ... }; +class Derived : public Base { ... }; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(DoThis, void(Derived* derived)); +}; +... + + MockFoo foo; + // m is a Matcher we got from somewhere. + EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); +``` + +If you find `SafeMatcherCast(m)` too limiting, you can use a similar +function `MatcherCast(m)`. The difference is that `MatcherCast` works +as long as you can `static_cast` type `T` to type `U`. + +`MatcherCast` essentially lets you bypass C++'s type system +(`static_cast` isn't always safe as it could throw away information, +for example), so be careful not to misuse/abuse it. + +## Selecting Between Overloaded Functions ## + +If you expect an overloaded function to be called, the compiler may +need some help on which overloaded version it is. + +To disambiguate functions overloaded on the const-ness of this object, +use the `Const()` argument wrapper. + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + ... + MOCK_METHOD0(GetBar, Bar&()); + MOCK_CONST_METHOD0(GetBar, const Bar&()); +}; +... + + MockFoo foo; + Bar bar1, bar2; + EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). + .WillOnce(ReturnRef(bar1)); + EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). + .WillOnce(ReturnRef(bar2)); +``` + +(`Const()` is defined by Google Mock and returns a `const` reference +to its argument.) + +To disambiguate overloaded functions with the same number of arguments +but different argument types, you may need to specify the exact type +of a matcher, either by wrapping your matcher in `Matcher()`, or +using a matcher whose type is fixed (`TypedEq`, `An()`, +etc): + +``` +using ::testing::An; +using ::testing::Lt; +using ::testing::Matcher; +using ::testing::TypedEq; + +class MockPrinter : public Printer { + public: + MOCK_METHOD1(Print, void(int n)); + MOCK_METHOD1(Print, void(char c)); +}; + +TEST(PrinterTest, Print) { + MockPrinter printer; + + EXPECT_CALL(printer, Print(An())); // void Print(int); + EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); + EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); + + printer.Print(3); + printer.Print(6); + printer.Print('a'); +} +``` + +## Performing Different Actions Based on the Arguments ## + +When a mock method is called, the _last_ matching expectation that's +still active will be selected (think "newer overrides older"). So, you +can make a method do different things depending on its argument values +like this: + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Return; +... + // The default case. + EXPECT_CALL(foo, DoThis(_)) + .WillRepeatedly(Return('b')); + + // The more specific case. + EXPECT_CALL(foo, DoThis(Lt(5))) + .WillRepeatedly(Return('a')); +``` + +Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will +be returned; otherwise `'b'` will be returned. + +## Matching Multiple Arguments as a Whole ## + +Sometimes it's not enough to match the arguments individually. For +example, we may want to say that the first argument must be less than +the second argument. The `With()` clause allows us to match +all arguments of a mock function as a whole. For example, + +``` +using ::testing::_; +using ::testing::Lt; +using ::testing::Ne; +... + EXPECT_CALL(foo, InRange(Ne(0), _)) + .With(Lt()); +``` + +says that the first argument of `InRange()` must not be 0, and must be +less than the second argument. + +The expression inside `With()` must be a matcher of type +`Matcher >`, where `A1`, ..., `An` are the +types of the function arguments. + +You can also write `AllArgs(m)` instead of `m` inside `.With()`. The +two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable +than `.With(Lt())`. + +You can use `Args(m)` to match the `n` selected arguments +(as a tuple) against `m`. For example, + +``` +using ::testing::_; +using ::testing::AllOf; +using ::testing::Args; +using ::testing::Lt; +... + EXPECT_CALL(foo, Blah(_, _, _)) + .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); +``` + +says that `Blah()` will be called with arguments `x`, `y`, and `z` where +`x < y < z`. + +As a convenience and example, Google Mock provides some matchers for +2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_7_CheatSheet.md) for +the complete list. + +Note that if you want to pass the arguments to a predicate of your own +(e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be +written to take a `tr1::tuple` as its argument; Google Mock will pass the `n` +selected arguments as _one_ single tuple to the predicate. + +## Using Matchers as Predicates ## + +Have you noticed that a matcher is just a fancy predicate that also +knows how to describe itself? Many existing algorithms take predicates +as arguments (e.g. those defined in STL's `` header), and +it would be a shame if Google Mock matchers are not allowed to +participate. + +Luckily, you can use a matcher where a unary predicate functor is +expected by wrapping it inside the `Matches()` function. For example, + +``` +#include +#include + +std::vector v; +... +// How many elements in v are >= 10? +const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); +``` + +Since you can build complex matchers from simpler ones easily using +Google Mock, this gives you a way to conveniently construct composite +predicates (doing the same using STL's `` header is just +painful). For example, here's a predicate that's satisfied by any +number that is >= 0, <= 100, and != 50: + +``` +Matches(AllOf(Ge(0), Le(100), Ne(50))) +``` + +## Using Matchers in Google Test Assertions ## + +Since matchers are basically predicates that also know how to describe +themselves, there is a way to take advantage of them in +[Google Test](http://code.google.com/p/googletest/) assertions. It's +called `ASSERT_THAT` and `EXPECT_THAT`: + +``` + ASSERT_THAT(value, matcher); // Asserts that value matches matcher. + EXPECT_THAT(value, matcher); // The non-fatal version. +``` + +For example, in a Google Test test you can write: + +``` +#include "gmock/gmock.h" + +using ::testing::AllOf; +using ::testing::Ge; +using ::testing::Le; +using ::testing::MatchesRegex; +using ::testing::StartsWith; +... + + EXPECT_THAT(Foo(), StartsWith("Hello")); + EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); + ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); +``` + +which (as you can probably guess) executes `Foo()`, `Bar()`, and +`Baz()`, and verifies that: + + * `Foo()` returns a string that starts with `"Hello"`. + * `Bar()` returns a string that matches regular expression `"Line \\d+"`. + * `Baz()` returns a number in the range [5, 10]. + +The nice thing about these macros is that _they read like +English_. They generate informative messages too. For example, if the +first `EXPECT_THAT()` above fails, the message will be something like: + +``` +Value of: Foo() + Actual: "Hi, world!" +Expected: starts with "Hello" +``` + +**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the +[Hamcrest](http://code.google.com/p/hamcrest/) project, which adds +`assertThat()` to JUnit. + +## Using Predicates as Matchers ## + +Google Mock provides a built-in set of matchers. In case you find them +lacking, you can use an arbitray unary predicate function or functor +as a matcher - as long as the predicate accepts a value of the type +you want. You do this by wrapping the predicate inside the `Truly()` +function, for example: + +``` +using ::testing::Truly; + +int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } +... + + // Bar() must be called with an even number. + EXPECT_CALL(foo, Bar(Truly(IsEven))); +``` + +Note that the predicate function / functor doesn't have to return +`bool`. It works as long as the return value can be used as the +condition in statement `if (condition) ...`. + +## Matching Arguments that Are Not Copyable ## + +When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves +away a copy of `bar`. When `Foo()` is called later, Google Mock +compares the argument to `Foo()` with the saved copy of `bar`. This +way, you don't need to worry about `bar` being modified or destroyed +after the `EXPECT_CALL()` is executed. The same is true when you use +matchers like `Eq(bar)`, `Le(bar)`, and so on. + +But what if `bar` cannot be copied (i.e. has no copy constructor)? You +could define your own matcher function and use it with `Truly()`, as +the previous couple of recipes have shown. Or, you may be able to get +away from it if you can guarantee that `bar` won't be changed after +the `EXPECT_CALL()` is executed. Just tell Google Mock that it should +save a reference to `bar`, instead of a copy of it. Here's how: + +``` +using ::testing::Eq; +using ::testing::ByRef; +using ::testing::Lt; +... + // Expects that Foo()'s argument == bar. + EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); + + // Expects that Foo()'s argument < bar. + EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); +``` + +Remember: if you do this, don't change `bar` after the +`EXPECT_CALL()`, or the result is undefined. + +## Validating a Member of an Object ## + +Often a mock function takes a reference to object as an argument. When +matching the argument, you may not want to compare the entire object +against a fixed object, as that may be over-specification. Instead, +you may need to validate a certain member variable or the result of a +certain getter method of the object. You can do this with `Field()` +and `Property()`. More specifically, + +``` +Field(&Foo::bar, m) +``` + +is a matcher that matches a `Foo` object whose `bar` member variable +satisfies matcher `m`. + +``` +Property(&Foo::baz, m) +``` + +is a matcher that matches a `Foo` object whose `baz()` method returns +a value that satisfies matcher `m`. + +For example: + +> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | +|:-----------------------------|:-----------------------------------| +> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | + +Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no +argument and be declared as `const`. + +BTW, `Field()` and `Property()` can also match plain pointers to +objects. For instance, + +``` +Field(&Foo::number, Ge(3)) +``` + +matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, +the match will always fail regardless of the inner matcher. + +What if you want to validate more than one members at the same time? +Remember that there is `AllOf()`. + +## Validating the Value Pointed to by a Pointer Argument ## + +C++ functions often take pointers as arguments. You can use matchers +like `IsNull()`, `NotNull()`, and other comparison matchers to match a +pointer, but what if you want to make sure the value _pointed to_ by +the pointer, instead of the pointer itself, has a certain property? +Well, you can use the `Pointee(m)` matcher. + +`Pointee(m)` matches a pointer iff `m` matches the value the pointer +points to. For example: + +``` +using ::testing::Ge; +using ::testing::Pointee; +... + EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); +``` + +expects `foo.Bar()` to be called with a pointer that points to a value +greater than or equal to 3. + +One nice thing about `Pointee()` is that it treats a `NULL` pointer as +a match failure, so you can write `Pointee(m)` instead of + +``` + AllOf(NotNull(), Pointee(m)) +``` + +without worrying that a `NULL` pointer will crash your test. + +Also, did we tell you that `Pointee()` works with both raw pointers +**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and +etc)? + +What if you have a pointer to pointer? You guessed it - you can use +nested `Pointee()` to probe deeper inside the value. For example, +`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer +that points to a number less than 3 (what a mouthful...). + +## Testing a Certain Property of an Object ## + +Sometimes you want to specify that an object argument has a certain +property, but there is no existing matcher that does this. If you want +good error messages, you should define a matcher. If you want to do it +quick and dirty, you could get away with writing an ordinary function. + +Let's say you have a mock function that takes an object of type `Foo`, +which has an `int bar()` method and an `int baz()` method, and you +want to constrain that the argument's `bar()` value plus its `baz()` +value is a given number. Here's how you can define a matcher to do it: + +``` +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class BarPlusBazEqMatcher : public MatcherInterface { + public: + explicit BarPlusBazEqMatcher(int expected_sum) + : expected_sum_(expected_sum) {} + + virtual bool MatchAndExplain(const Foo& foo, + MatchResultListener* listener) const { + return (foo.bar() + foo.baz()) == expected_sum_; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "bar() + baz() equals " << expected_sum_; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "bar() + baz() does not equal " << expected_sum_; + } + private: + const int expected_sum_; +}; + +inline Matcher BarPlusBazEq(int expected_sum) { + return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); +} + +... + + EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; +``` + +## Matching Containers ## + +Sometimes an STL container (e.g. list, vector, map, ...) is passed to +a mock function and you may want to validate it. Since most STL +containers support the `==` operator, you can write +`Eq(expected_container)` or simply `expected_container` to match a +container exactly. + +Sometimes, though, you may want to be more flexible (for example, the +first element must be an exact match, but the second element can be +any positive number, and so on). Also, containers used in tests often +have a small number of elements, and having to define the expected +container out-of-line is a bit of a hassle. + +You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in +such cases: + +``` +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Gt; +... + + MOCK_METHOD1(Foo, void(const vector& numbers)); +... + + EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); +``` + +The above matcher says that the container must have 4 elements, which +must be 1, greater than 0, anything, and 5 respectively. + +If you instead write: + +``` +using ::testing::_; +using ::testing::Gt; +using ::testing::UnorderedElementsAre; +... + + MOCK_METHOD1(Foo, void(const vector& numbers)); +... + + EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); +``` + +It means that the container must have 4 elements, which under some +permutation must be 1, greater than 0, anything, and 5 respectively. + +`ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0 +to 10 arguments. If more are needed, you can place them in a C-style +array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` +instead: + +``` +using ::testing::ElementsAreArray; +... + + // ElementsAreArray accepts an array of element values. + const int expected_vector1[] = { 1, 5, 2, 4, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); + + // Or, an array of element matchers. + Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); +``` + +In case the array needs to be dynamically created (and therefore the +array size cannot be inferred by the compiler), you can give +`ElementsAreArray()` an additional argument to specify the array size: + +``` +using ::testing::ElementsAreArray; +... + int* const expected_vector3 = new int[count]; + ... fill expected_vector3 with values ... + EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); +``` + +**Tips:** + + * `ElementsAre*()` can be used to match _any_ container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. + * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. + * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. + * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). + +## Sharing Matchers ## + +Under the hood, a Google Mock matcher object consists of a pointer to +a ref-counted implementation object. Copying matchers is allowed and +very efficient, as only the pointer is copied. When the last matcher +that references the implementation object dies, the implementation +object will be deleted. + +Therefore, if you have some complex matcher that you want to use again +and again, there is no need to build it everytime. Just assign it to a +matcher variable and use that variable repeatedly! For example, + +``` + Matcher in_range = AllOf(Gt(5), Le(10)); + ... use in_range as a matcher in multiple EXPECT_CALLs ... +``` + +# Setting Expectations # + +## Knowing When to Expect ## + +`ON_CALL` is likely the single most under-utilized construct in Google Mock. + +There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but _doesn't imply any expectation on the method being called._ `EXPECT_CALL` not only defines the behavior, but also sets an expectation that _the method will be called with the given arguments, for the given number of times_ (and _in the given order_ when you specify the order too). + +Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is _baaad_ - even worse than not having enough constraints. + +This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? + +The answer, lies in _what_ a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. + +Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. + +So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). + +## Ignoring Uninteresting Calls ## + +If you are not interested in how a mock method is called, just don't +say anything about it. In this case, if the method is ever called, +Google Mock will perform its default action to allow the test program +to continue. If you are not happy with the default action taken by +Google Mock, you can override it using `DefaultValue::Set()` +(described later in this document) or `ON_CALL()`. + +Please note that once you expressed interest in a particular mock +method (via `EXPECT_CALL()`), all invocations to it must match some +expectation. If this function is called but the arguments don't match +any `EXPECT_CALL()` statement, it will be an error. + +## Disallowing Unexpected Calls ## + +If a mock method shouldn't be called at all, explicitly say so: + +``` +using ::testing::_; +... + EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +If some calls to the method are allowed, but the rest are not, just +list all the expected calls: + +``` +using ::testing::AnyNumber; +using ::testing::Gt; +... + EXPECT_CALL(foo, Bar(5)); + EXPECT_CALL(foo, Bar(Gt(10))) + .Times(AnyNumber()); +``` + +A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` +statements will be an error. + +## Expecting Ordered Calls ## + +Although an `EXPECT_CALL()` statement defined earlier takes precedence +when Google Mock tries to match a function call with an expectation, +by default calls don't have to happen in the order `EXPECT_CALL()` +statements are written. For example, if the arguments match the +matchers in the third `EXPECT_CALL()`, but not those in the first two, +then the third expectation will be used. + +If you would rather have all calls occur in the order of the +expectations, put the `EXPECT_CALL()` statements in a block where you +define a variable of type `InSequence`: + +``` + using ::testing::_; + using ::testing::InSequence; + + { + InSequence s; + + EXPECT_CALL(foo, DoThis(5)); + EXPECT_CALL(bar, DoThat(_)) + .Times(2); + EXPECT_CALL(foo, DoThis(6)); + } +``` + +In this example, we expect a call to `foo.DoThis(5)`, followed by two +calls to `bar.DoThat()` where the argument can be anything, which are +in turn followed by a call to `foo.DoThis(6)`. If a call occurred +out-of-order, Google Mock will report an error. + +## Expecting Partially Ordered Calls ## + +Sometimes requiring everything to occur in a predetermined order can +lead to brittle tests. For example, we may care about `A` occurring +before both `B` and `C`, but aren't interested in the relative order +of `B` and `C`. In this case, the test should reflect our real intent, +instead of being overly constraining. + +Google Mock allows you to impose an arbitrary DAG (directed acyclic +graph) on the calls. One way to express the DAG is to use the +[After](http://code.google.com/p/googlemock/wiki/V1_7_CheatSheet#The_After_Clause) clause of `EXPECT_CALL`. + +Another way is via the `InSequence()` clause (not the same as the +`InSequence` class), which we borrowed from jMock 2. It's less +flexible than `After()`, but more convenient when you have long chains +of sequential calls, as it doesn't require you to come up with +different names for the expectations in the chains. Here's how it +works: + +If we view `EXPECT_CALL()` statements as nodes in a graph, and add an +edge from node A to node B wherever A must occur before B, we can get +a DAG. We use the term "sequence" to mean a directed path in this +DAG. Now, if we decompose the DAG into sequences, we just need to know +which sequences each `EXPECT_CALL()` belongs to in order to be able to +reconstruct the orginal DAG. + +So, to specify the partial order on the expectations we need to do two +things: first to define some `Sequence` objects, and then for each +`EXPECT_CALL()` say which `Sequence` objects it is part +of. Expectations in the same sequence must occur in the order they are +written. For example, + +``` + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(foo, A()) + .InSequence(s1, s2); + EXPECT_CALL(bar, B()) + .InSequence(s1); + EXPECT_CALL(bar, C()) + .InSequence(s2); + EXPECT_CALL(foo, D()) + .InSequence(s2); +``` + +specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> +C -> D`): + +``` + +---> B + | + A ---| + | + +---> C ---> D +``` + +This means that A must occur before B and C, and C must occur before +D. There's no restriction about the order other than these. + +## Controlling When an Expectation Retires ## + +When a mock method is called, Google Mock only consider expectations +that are still active. An expectation is active when created, and +becomes inactive (aka _retires_) when a call that has to occur later +has occurred. For example, in + +``` + using ::testing::_; + using ::testing::Sequence; + + Sequence s1, s2; + + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 + .Times(AnyNumber()) + .InSequence(s1, s2); + EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 + .InSequence(s1); + EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 + .InSequence(s2); +``` + +as soon as either #2 or #3 is matched, #1 will retire. If a warning +`"File too large."` is logged after this, it will be an error. + +Note that an expectation doesn't retire automatically when it's +saturated. For example, + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 +``` + +says that there will be exactly one warning with the message `"File +too large."`. If the second warning contains this message too, #2 will +match again and result in an upper-bound-violated error. + +If this is not what you want, you can ask an expectation to retire as +soon as it becomes saturated: + +``` +using ::testing::_; +... + EXPECT_CALL(log, Log(WARNING, _, _)); // #1 + EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 + .RetiresOnSaturation(); +``` + +Here #2 can be used only once, so if you have two warnings with the +message `"File too large."`, the first will match #2 and the second +will match #1 - there will be no error. + +# Using Actions # + +## Returning References from Mock Methods ## + +If a mock function's return type is a reference, you need to use +`ReturnRef()` instead of `Return()` to return a result: + +``` +using ::testing::ReturnRef; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetBar, Bar&()); +}; +... + + MockFoo foo; + Bar bar; + EXPECT_CALL(foo, GetBar()) + .WillOnce(ReturnRef(bar)); +``` + +## Returning Live Values from Mock Methods ## + +The `Return(x)` action saves a copy of `x` when the action is +_created_, and always returns the same value whenever it's +executed. Sometimes you may want to instead return the _live_ value of +`x` (i.e. its value at the time when the action is _executed_.). + +If the mock function's return type is a reference, you can do it using +`ReturnRef(x)`, as shown in the previous recipe ("Returning References +from Mock Methods"). However, Google Mock doesn't let you use +`ReturnRef()` in a mock function whose return type is not a reference, +as doing that usually indicates a user error. So, what shall you do? + +You may be tempted to try `ByRef()`: + +``` +using testing::ByRef; +using testing::Return; + +class MockFoo : public Foo { + public: + MOCK_METHOD0(GetValue, int()); +}; +... + int x = 0; + MockFoo foo; + EXPECT_CALL(foo, GetValue()) + .WillRepeatedly(Return(ByRef(x))); + x = 42; + EXPECT_EQ(42, foo.GetValue()); +``` + +Unfortunately, it doesn't work here. The above code will fail with error: + +``` +Value of: foo.GetValue() + Actual: 0 +Expected: 42 +``` + +The reason is that `Return(value)` converts `value` to the actual +return type of the mock function at the time when the action is +_created_, not when it is _executed_. (This behavior was chosen for +the action to be safe when `value` is a proxy object that references +some temporary objects.) As a result, `ByRef(x)` is converted to an +`int` value (instead of a `const int&`) when the expectation is set, +and `Return(ByRef(x))` will always return 0. + +`ReturnPointee(pointer)` was provided to solve this problem +specifically. It returns the value pointed to by `pointer` at the time +the action is _executed_: + +``` +using testing::ReturnPointee; +... + int x = 0; + MockFoo foo; + EXPECT_CALL(foo, GetValue()) + .WillRepeatedly(ReturnPointee(&x)); // Note the & here. + x = 42; + EXPECT_EQ(42, foo.GetValue()); // This will succeed now. +``` + +## Combining Actions ## + +Want to do more than one thing when a function is called? That's +fine. `DoAll()` allow you to do sequence of actions every time. Only +the return value of the last action in the sequence will be used. + +``` +using ::testing::DoAll; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Bar, bool(int n)); +}; +... + + EXPECT_CALL(foo, Bar(_)) + .WillOnce(DoAll(action_1, + action_2, + ... + action_n)); +``` + +## Mocking Side Effects ## + +Sometimes a method exhibits its effect not via returning a value but +via side effects. For example, it may change some global state or +modify an output argument. To mock side effects, in general you can +define your own action by implementing `::testing::ActionInterface`. + +If all you need to do is to change an output argument, the built-in +`SetArgPointee()` action is convenient: + +``` +using ::testing::SetArgPointee; + +class MockMutator : public Mutator { + public: + MOCK_METHOD2(Mutate, void(bool mutate, int* value)); + ... +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, Mutate(true, _)) + .WillOnce(SetArgPointee<1>(5)); +``` + +In this example, when `mutator.Mutate()` is called, we will assign 5 +to the `int` variable pointed to by argument #1 +(0-based). + +`SetArgPointee()` conveniently makes an internal copy of the +value you pass to it, removing the need to keep the value in scope and +alive. The implication however is that the value must have a copy +constructor and assignment operator. + +If the mock method also needs to return a value as well, you can chain +`SetArgPointee()` with `Return()` using `DoAll()`: + +``` +using ::testing::_; +using ::testing::Return; +using ::testing::SetArgPointee; + +class MockMutator : public Mutator { + public: + ... + MOCK_METHOD1(MutateInt, bool(int* value)); +}; +... + + MockMutator mutator; + EXPECT_CALL(mutator, MutateInt(_)) + .WillOnce(DoAll(SetArgPointee<0>(5), + Return(true))); +``` + +If the output argument is an array, use the +`SetArrayArgument(first, last)` action instead. It copies the +elements in source range `[first, last)` to the array pointed to by +the `N`-th (0-based) argument: + +``` +using ::testing::NotNull; +using ::testing::SetArrayArgument; + +class MockArrayMutator : public ArrayMutator { + public: + MOCK_METHOD2(Mutate, void(int* values, int num_values)); + ... +}; +... + + MockArrayMutator mutator; + int values[5] = { 1, 2, 3, 4, 5 }; + EXPECT_CALL(mutator, Mutate(NotNull(), 5)) + .WillOnce(SetArrayArgument<0>(values, values + 5)); +``` + +This also works when the argument is an output iterator: + +``` +using ::testing::_; +using ::testing::SeArrayArgument; + +class MockRolodex : public Rolodex { + public: + MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); + ... +}; +... + + MockRolodex rolodex; + vector names; + names.push_back("George"); + names.push_back("John"); + names.push_back("Thomas"); + EXPECT_CALL(rolodex, GetNames(_)) + .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); +``` + +## Changing a Mock Object's Behavior Based on the State ## + +If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: + +``` +using ::testing::InSequence; +using ::testing::Return; + +... + { + InSequence seq; + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(my_mock, Flush()); + EXPECT_CALL(my_mock, IsDirty()) + .WillRepeatedly(Return(false)); + } + my_mock.FlushIfDirty(); +``` + +This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. + +If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: + +``` +using ::testing::_; +using ::testing::SaveArg; +using ::testing::Return; + +ACTION_P(ReturnPointee, p) { return *p; } +... + int previous_value = 0; + EXPECT_CALL(my_mock, GetPrevValue()) + .WillRepeatedly(ReturnPointee(&previous_value)); + EXPECT_CALL(my_mock, UpdateValue(_)) + .WillRepeatedly(SaveArg<0>(&previous_value)); + my_mock.DoSomethingToUpdateValue(); +``` + +Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. + +## Setting the Default Value for a Return Type ## + +If a mock method's return type is a built-in C++ type or pointer, by +default it will return 0 when invoked. You only need to specify an +action if this default value doesn't work for you. + +Sometimes, you may want to change this default value, or you may want +to specify a default value for types Google Mock doesn't know +about. You can do this using the `::testing::DefaultValue` class +template: + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD0(CalculateBar, Bar()); +}; +... + + Bar default_bar; + // Sets the default return value for type Bar. + DefaultValue::Set(default_bar); + + MockFoo foo; + + // We don't need to specify an action here, as the default + // return value works for us. + EXPECT_CALL(foo, CalculateBar()); + + foo.CalculateBar(); // This should return default_bar. + + // Unsets the default return value. + DefaultValue::Clear(); +``` + +Please note that changing the default value for a type can make you +tests hard to understand. We recommend you to use this feature +judiciously. For example, you may want to make sure the `Set()` and +`Clear()` calls are right next to the code that uses your mock. + +## Setting the Default Actions for a Mock Method ## + +You've learned how to change the default value of a given +type. However, this may be too coarse for your purpose: perhaps you +have two mock methods with the same return type and you want them to +have different behaviors. The `ON_CALL()` macro allows you to +customize your mock's behavior at the method level: + +``` +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Gt; +using ::testing::Return; +... + ON_CALL(foo, Sign(_)) + .WillByDefault(Return(-1)); + ON_CALL(foo, Sign(0)) + .WillByDefault(Return(0)); + ON_CALL(foo, Sign(Gt(0))) + .WillByDefault(Return(1)); + + EXPECT_CALL(foo, Sign(_)) + .Times(AnyNumber()); + + foo.Sign(5); // This should return 1. + foo.Sign(-9); // This should return -1. + foo.Sign(0); // This should return 0. +``` + +As you may have guessed, when there are more than one `ON_CALL()` +statements, the news order take precedence over the older ones. In +other words, the **last** one that matches the function arguments will +be used. This matching order allows you to set up the common behavior +in a mock object's constructor or the test fixture's set-up phase and +specialize the mock's behavior later. + +## Using Functions/Methods/Functors as Actions ## + +If the built-in actions don't suit you, you can easily use an existing +function, method, or functor as an action: + +``` +using ::testing::_; +using ::testing::Invoke; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(Sum, int(int x, int y)); + MOCK_METHOD1(ComplexJob, bool(int x)); +}; + +int CalculateSum(int x, int y) { return x + y; } + +class Helper { + public: + bool ComplexJob(int x); +}; +... + + MockFoo foo; + Helper helper; + EXPECT_CALL(foo, Sum(_, _)) + .WillOnce(Invoke(CalculateSum)); + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(Invoke(&helper, &Helper::ComplexJob)); + + foo.Sum(5, 6); // Invokes CalculateSum(5, 6). + foo.ComplexJob(10); // Invokes helper.ComplexJob(10); +``` + +The only requirement is that the type of the function, etc must be +_compatible_ with the signature of the mock function, meaning that the +latter's arguments can be implicitly converted to the corresponding +arguments of the former, and the former's return type can be +implicitly converted to that of the latter. So, you can invoke +something whose type is _not_ exactly the same as the mock function, +as long as it's safe to do so - nice, huh? + +## Invoking a Function/Method/Functor Without Arguments ## + +`Invoke()` is very useful for doing actions that are more complex. It +passes the mock function's arguments to the function or functor being +invoked such that the callee has the full context of the call to work +with. If the invoked function is not interested in some or all of the +arguments, it can simply ignore them. + +Yet, a common pattern is that a test author wants to invoke a function +without the arguments of the mock function. `Invoke()` allows her to +do that using a wrapper function that throws away the arguments before +invoking an underlining nullary function. Needless to say, this can be +tedious and obscures the intent of the test. + +`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except +that it doesn't pass the mock function's arguments to the +callee. Here's an example: + +``` +using ::testing::_; +using ::testing::InvokeWithoutArgs; + +class MockFoo : public Foo { + public: + MOCK_METHOD1(ComplexJob, bool(int n)); +}; + +bool Job1() { ... } +... + + MockFoo foo; + EXPECT_CALL(foo, ComplexJob(_)) + .WillOnce(InvokeWithoutArgs(Job1)); + + foo.ComplexJob(10); // Invokes Job1(). +``` + +## Invoking an Argument of the Mock Function ## + +Sometimes a mock function will receive a function pointer or a functor +(in other words, a "callable") as an argument, e.g. + +``` +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); +}; +``` + +and you may want to invoke this callable argument: + +``` +using ::testing::_; +... + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(...); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +Arghh, you need to refer to a mock function argument but C++ has no +lambda (yet), so you have to define your own action. :-( Or do you +really? + +Well, Google Mock has an action to solve _exactly_ this problem: + +``` + InvokeArgument(arg_1, arg_2, ..., arg_m) +``` + +will invoke the `N`-th (0-based) argument the mock function receives, +with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is +a function pointer or a functor, Google Mock handles them both. + +With that, you could write: + +``` +using ::testing::_; +using ::testing::InvokeArgument; +... + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(InvokeArgument<1>(5)); + // Will execute (*fp)(5), where fp is the + // second argument DoThis() receives. +``` + +What if the callable takes an argument by reference? No problem - just +wrap it inside `ByRef()`: + +``` +... + MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); +... +using ::testing::_; +using ::testing::ByRef; +using ::testing::InvokeArgument; +... + + MockFoo foo; + Helper helper; + ... + EXPECT_CALL(foo, Bar(_)) + .WillOnce(InvokeArgument<0>(5, ByRef(helper))); + // ByRef(helper) guarantees that a reference to helper, not a copy of it, + // will be passed to the callable. +``` + +What if the callable takes an argument by reference and we do **not** +wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a +copy_ of the argument, and pass a _reference to the copy_, instead of +a reference to the original value, to the callable. This is especially +handy when the argument is a temporary value: + +``` +... + MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); +... +using ::testing::_; +using ::testing::InvokeArgument; +... + + MockFoo foo; + ... + EXPECT_CALL(foo, DoThat(_)) + .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); + // Will execute (*f)(5.0, string("Hi")), where f is the function pointer + // DoThat() receives. Note that the values 5.0 and string("Hi") are + // temporary and dead once the EXPECT_CALL() statement finishes. Yet + // it's fine to perform this action later, since a copy of the values + // are kept inside the InvokeArgument action. +``` + +## Ignoring an Action's Result ## + +Sometimes you have an action that returns _something_, but you need an +action that returns `void` (perhaps you want to use it in a mock +function that returns `void`, or perhaps it needs to be used in +`DoAll()` and it's not the last in the list). `IgnoreResult()` lets +you do that. For example: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; + +int Process(const MyData& data); +string DoSomething(); + +class MockFoo : public Foo { + public: + MOCK_METHOD1(Abc, void(const MyData& data)); + MOCK_METHOD0(Xyz, bool()); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, Abc(_)) + // .WillOnce(Invoke(Process)); + // The above line won't compile as Process() returns int but Abc() needs + // to return void. + .WillOnce(IgnoreResult(Invoke(Process))); + + EXPECT_CALL(foo, Xyz()) + .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), + // Ignores the string DoSomething() returns. + Return(true))); +``` + +Note that you **cannot** use `IgnoreResult()` on an action that already +returns `void`. Doing so will lead to ugly compiler errors. + +## Selecting an Action's Arguments ## + +Say you have a mock function `Foo()` that takes seven arguments, and +you have a custom action that you want to invoke when `Foo()` is +called. Trouble is, the custom action only wants three arguments: + +``` +using ::testing::_; +using ::testing::Invoke; +... + MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight)); +... + +bool IsVisibleInQuadrant1(bool visible, int x, int y) { + return visible && x >= 0 && y >= 0; +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( +``` + +To please the compiler God, you can to define an "adaptor" that has +the same signature as `Foo()` and calls the custom action with the +right arguments: + +``` +using ::testing::_; +using ::testing::Invoke; + +bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, + const map, double>& weight, + double min_weight, double max_wight) { + return IsVisibleInQuadrant1(visible, x, y); +} +... + + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. +``` + +But isn't this awkward? + +Google Mock provides a generic _action adaptor_, so you can spend your +time minding more important business than writing your own +adaptors. Here's the syntax: + +``` + WithArgs(action) +``` + +creates an action that passes the arguments of the mock function at +the given indices (0-based) to the inner `action` and performs +it. Using `WithArgs`, our original example can be written as: + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::WithArgs; +... + EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) + .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); + // No need to define your own adaptor. +``` + +For better readability, Google Mock also gives you: + + * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and + * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. + +As you may have realized, `InvokeWithoutArgs(...)` is just syntactic +sugar for `WithoutArgs(Inovke(...))`. + +Here are more tips: + + * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. + * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. + * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. + * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. + +## Ignoring Arguments in Action Functions ## + +The selecting-an-action's-arguments recipe showed us one way to make a +mock function and an action with incompatible argument lists fit +together. The downside is that wrapping the action in +`WithArgs<...>()` can get tedious for people writing the tests. + +If you are defining a function, method, or functor to be used with +`Invoke*()`, and you are not interested in some of its arguments, an +alternative to `WithArgs` is to declare the uninteresting arguments as +`Unused`. This makes the definition less cluttered and less fragile in +case the types of the uninteresting arguments change. It could also +increase the chance the action function can be reused. For example, +given + +``` + MOCK_METHOD3(Foo, double(const string& label, double x, double y)); + MOCK_METHOD3(Bar, double(int index, double x, double y)); +``` + +instead of + +``` +using ::testing::_; +using ::testing::Invoke; + +double DistanceToOriginWithLabel(const string& label, double x, double y) { + return sqrt(x*x + y*y); +} + +double DistanceToOriginWithIndex(int index, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOriginWithLabel)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOriginWithIndex)); +``` + +you could write + +``` +using ::testing::_; +using ::testing::Invoke; +using ::testing::Unused; + +double DistanceToOrigin(Unused, double x, double y) { + return sqrt(x*x + y*y); +} +... + + EXEPCT_CALL(mock, Foo("abc", _, _)) + .WillOnce(Invoke(DistanceToOrigin)); + EXEPCT_CALL(mock, Bar(5, _, _)) + .WillOnce(Invoke(DistanceToOrigin)); +``` + +## Sharing Actions ## + +Just like matchers, a Google Mock action object consists of a pointer +to a ref-counted implementation object. Therefore copying actions is +also allowed and very efficient. When the last action that references +the implementation object dies, the implementation object will be +deleted. + +If you have some complex action that you want to use again and again, +you may not have to build it from scratch everytime. If the action +doesn't have an internal state (i.e. if it always does the same thing +no matter how many times it has been called), you can assign it to an +action variable and use that variable repeatedly. For example: + +``` + Action set_flag = DoAll(SetArgPointee<0>(5), + Return(true)); + ... use set_flag in .WillOnce() and .WillRepeatedly() ... +``` + +However, if the action has its own state, you may be surprised if you +share the action object. Suppose you have an action factory +`IncrementCounter(init)` which creates an action that increments and +returns a counter whose initial value is `init`, using two actions +created from the same expression and using a shared action will +exihibit different behaviors. Example: + +``` + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(IncrementCounter(0)); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(IncrementCounter(0)); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 1 - Blah() uses a different + // counter than Bar()'s. +``` + +versus + +``` + Action increment = IncrementCounter(0); + + EXPECT_CALL(foo, DoThis()) + .WillRepeatedly(increment); + EXPECT_CALL(foo, DoThat()) + .WillRepeatedly(increment); + foo.DoThis(); // Returns 1. + foo.DoThis(); // Returns 2. + foo.DoThat(); // Returns 3 - the counter is shared. +``` + +# Misc Recipes on Using Google Mock # + +## Making the Compilation Faster ## + +Believe it or not, the _vast majority_ of the time spent on compiling +a mock class is in generating its constructor and destructor, as they +perform non-trivial tasks (e.g. verification of the +expectations). What's more, mock methods with different signatures +have different types and thus their constructors/destructors need to +be generated by the compiler separately. As a result, if you mock many +different types of methods, compiling your mock class can get really +slow. + +If you are experiencing slow compilation, you can move the definition +of your mock class' constructor and destructor out of the class body +and into a `.cpp` file. This way, even if you `#include` your mock +class in N files, the compiler only needs to generate its constructor +and destructor once, resulting in a much faster compilation. + +Let's illustrate the idea using an example. Here's the definition of a +mock class before applying this recipe: + +``` +// File mock_foo.h. +... +class MockFoo : public Foo { + public: + // Since we don't declare the constructor or the destructor, + // the compiler will generate them in every translation unit + // where this mock class is used. + + MOCK_METHOD0(DoThis, int()); + MOCK_METHOD1(DoThat, bool(const char* str)); + ... more mock methods ... +}; +``` + +After the change, it would look like: + +``` +// File mock_foo.h. +... +class MockFoo : public Foo { + public: + // The constructor and destructor are declared, but not defined, here. + MockFoo(); + virtual ~MockFoo(); + + MOCK_METHOD0(DoThis, int()); + MOCK_METHOD1(DoThat, bool(const char* str)); + ... more mock methods ... +}; +``` +and +``` +// File mock_foo.cpp. +#include "path/to/mock_foo.h" + +// The definitions may appear trivial, but the functions actually do a +// lot of things through the constructors/destructors of the member +// variables used to implement the mock methods. +MockFoo::MockFoo() {} +MockFoo::~MockFoo() {} +``` + +## Forcing a Verification ## + +When it's being destoyed, your friendly mock object will automatically +verify that all expectations on it have been satisfied, and will +generate [Google Test](http://code.google.com/p/googletest/) failures +if not. This is convenient as it leaves you with one less thing to +worry about. That is, unless you are not sure if your mock object will +be destoyed. + +How could it be that your mock object won't eventually be destroyed? +Well, it might be created on the heap and owned by the code you are +testing. Suppose there's a bug in that code and it doesn't delete the +mock object properly - you could end up with a passing test when +there's actually a bug. + +Using a heap checker is a good idea and can alleviate the concern, but +its implementation may not be 100% reliable. So, sometimes you do want +to _force_ Google Mock to verify a mock object before it is +(hopefully) destructed. You can do this with +`Mock::VerifyAndClearExpectations(&mock_object)`: + +``` +TEST(MyServerTest, ProcessesRequest) { + using ::testing::Mock; + + MockFoo* const foo = new MockFoo; + EXPECT_CALL(*foo, ...)...; + // ... other expectations ... + + // server now owns foo. + MyServer server(foo); + server.ProcessRequest(...); + + // In case that server's destructor will forget to delete foo, + // this will verify the expectations anyway. + Mock::VerifyAndClearExpectations(foo); +} // server is destroyed when it goes out of scope here. +``` + +**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a +`bool` to indicate whether the verification was successful (`true` for +yes), so you can wrap that function call inside a `ASSERT_TRUE()` if +there is no point going further when the verification has failed. + +## Using Check Points ## + +Sometimes you may want to "reset" a mock object at various check +points in your test: at each check point, you verify that all existing +expectations on the mock object have been satisfied, and then you set +some new expectations on it as if it's newly created. This allows you +to work with a mock object in "phases" whose sizes are each +manageable. + +One such scenario is that in your test's `SetUp()` function, you may +want to put the object you are testing into a certain state, with the +help from a mock object. Once in the desired state, you want to clear +all expectations on the mock, such that in the `TEST_F` body you can +set fresh expectations on it. + +As you may have figured out, the `Mock::VerifyAndClearExpectations()` +function we saw in the previous recipe can help you here. Or, if you +are using `ON_CALL()` to set default actions on the mock object and +want to clear the default actions as well, use +`Mock::VerifyAndClear(&mock_object)` instead. This function does what +`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the +same `bool`, **plus** it clears the `ON_CALL()` statements on +`mock_object` too. + +Another trick you can use to achieve the same effect is to put the +expectations in sequences and insert calls to a dummy "check-point" +function at specific places. Then you can verify that the mock +function calls do happen at the right time. For example, if you are +exercising code: + +``` +Foo(1); +Foo(2); +Foo(3); +``` + +and want to verify that `Foo(1)` and `Foo(3)` both invoke +`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: + +``` +using ::testing::MockFunction; + +TEST(FooTest, InvokesBarCorrectly) { + MyMock mock; + // Class MockFunction has exactly one mock method. It is named + // Call() and has type F. + MockFunction check; + { + InSequence s; + + EXPECT_CALL(mock, Bar("a")); + EXPECT_CALL(check, Call("1")); + EXPECT_CALL(check, Call("2")); + EXPECT_CALL(mock, Bar("a")); + } + Foo(1); + check.Call("1"); + Foo(2); + check.Call("2"); + Foo(3); +} +``` + +The expectation spec says that the first `Bar("a")` must happen before +check point "1", the second `Bar("a")` must happen after check point "2", +and nothing should happen between the two check points. The explicit +check points make it easy to tell which `Bar("a")` is called by which +call to `Foo()`. + +## Mocking Destructors ## + +Sometimes you want to make sure a mock object is destructed at the +right time, e.g. after `bar->A()` is called but before `bar->B()` is +called. We already know that you can specify constraints on the order +of mock function calls, so all we need to do is to mock the destructor +of the mock function. + +This sounds simple, except for one problem: a destructor is a special +function with special syntax and special semantics, and the +`MOCK_METHOD0` macro doesn't work for it: + +``` + MOCK_METHOD0(~MockFoo, void()); // Won't compile! +``` + +The good news is that you can use a simple pattern to achieve the same +effect. First, add a mock function `Die()` to your mock class and call +it in the destructor, like this: + +``` +class MockFoo : public Foo { + ... + // Add the following two lines to the mock class. + MOCK_METHOD0(Die, void()); + virtual ~MockFoo() { Die(); } +}; +``` + +(If the name `Die()` clashes with an existing symbol, choose another +name.) Now, we have translated the problem of testing when a `MockFoo` +object dies to testing when its `Die()` method is called: + +``` + MockFoo* foo = new MockFoo; + MockBar* bar = new MockBar; + ... + { + InSequence s; + + // Expects *foo to die after bar->A() and before bar->B(). + EXPECT_CALL(*bar, A()); + EXPECT_CALL(*foo, Die()); + EXPECT_CALL(*bar, B()); + } +``` + +And that's that. + +## Using Google Mock and Threads ## + +**IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on +platforms where Google Mock is thread-safe. Currently these are only +platforms that support the pthreads library (this includes Linux and Mac). +To make it thread-safe on other platforms we only need to implement +some synchronization operations in `"gtest/internal/gtest-port.h"`. + +In a **unit** test, it's best if you could isolate and test a piece of +code in a single-threaded context. That avoids race conditions and +dead locks, and makes debugging your test much easier. + +Yet many programs are multi-threaded, and sometimes to test something +we need to pound on it from more than one thread. Google Mock works +for this purpose too. + +Remember the steps for using a mock: + + 1. Create a mock object `foo`. + 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. + 1. The code under test calls methods of `foo`. + 1. Optionally, verify and reset the mock. + 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. + +If you follow the following simple rules, your mocks and threads can +live happily togeter: + + * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. + * Obviously, you can do step #1 without locking. + * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? + * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. + +If you violate the rules (for example, if you set expectations on a +mock while another thread is calling its methods), you get undefined +behavior. That's not fun, so don't do it. + +Google Mock guarantees that the action for a mock function is done in +the same thread that called the mock function. For example, in + +``` + EXPECT_CALL(mock, Foo(1)) + .WillOnce(action1); + EXPECT_CALL(mock, Foo(2)) + .WillOnce(action2); +``` + +if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, +Google Mock will execute `action1` in thread 1 and `action2` in thread +2. + +Google Mock does _not_ impose a sequence on actions performed in +different threads (doing so may create deadlocks as the actions may +need to cooperate). This means that the execution of `action1` and +`action2` in the above example _may_ interleave. If this is a problem, +you should add proper synchronization logic to `action1` and `action2` +to make the test thread-safe. + + +Also, remember that `DefaultValue` is a global resource that +potentially affects _all_ living mock objects in your +program. Naturally, you won't want to mess with it from multiple +threads or when there still are mocks in action. + +## Controlling How Much Information Google Mock Prints ## + +When Google Mock sees something that has the potential of being an +error (e.g. a mock function with no expectation is called, a.k.a. an +uninteresting call, which is allowed but perhaps you forgot to +explicitly ban the call), it prints some warning messages, including +the arguments of the function and the return value. Hopefully this +will remind you to take a look and see if there is indeed a problem. + +Sometimes you are confident that your tests are correct and may not +appreciate such friendly messages. Some other times, you are debugging +your tests or learning about the behavior of the code you are testing, +and wish you could observe every mock call that happens (including +argument values and the return value). Clearly, one size doesn't fit +all. + +You can control how much Google Mock tells you using the +`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string +with three possible values: + + * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. + * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. + * `error`: Google Mock will print errors only (least verbose). + +Alternatively, you can adjust the value of that flag from within your +tests like so: + +``` + ::testing::FLAGS_gmock_verbose = "error"; +``` + +Now, judiciously use the right flag to enable Google Mock serve you better! + +## Gaining Super Vision into Mock Calls ## + +You have a test using Google Mock. It fails: Google Mock tells you +that some expectations aren't satisfied. However, you aren't sure why: +Is there a typo somewhere in the matchers? Did you mess up the order +of the `EXPECT_CALL`s? Or is the code under test doing something +wrong? How can you find out the cause? + +Won't it be nice if you have X-ray vision and can actually see the +trace of all `EXPECT_CALL`s and mock method calls as they are made? +For each call, would you like to see its actual argument values and +which `EXPECT_CALL` Google Mock thinks it matches? + +You can unlock this power by running your test with the +`--gmock_verbose=info` flag. For example, given the test program: + +``` +using testing::_; +using testing::HasSubstr; +using testing::Return; + +class MockFoo { + public: + MOCK_METHOD2(F, void(const string& x, const string& y)); +}; + +TEST(Foo, Bar) { + MockFoo mock; + EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); + EXPECT_CALL(mock, F("a", "b")); + EXPECT_CALL(mock, F("c", HasSubstr("d"))); + + mock.F("a", "good"); + mock.F("a", "b"); +} +``` + +if you run it with `--gmock_verbose=info`, you will see this output: + +``` +[ RUN ] Foo.Bar + +foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked +foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked +foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked +foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... + Function call: F(@0x7fff7c8dad40"a", @0x7fff7c8dad10"good") +foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... + Function call: F(@0x7fff7c8dada0"a", @0x7fff7c8dad70"b") +foo_test.cc:16: Failure +Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] Foo.Bar +``` + +Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo +and should actually be `"a"`. With the above message, you should see +that the actual `F("a", "good")` call is matched by the first +`EXPECT_CALL`, not the third as you thought. From that it should be +obvious that the third `EXPECT_CALL` is written wrong. Case solved. + +## Running Tests in Emacs ## + +If you build and run your tests in Emacs, the source file locations of +Google Mock and [Google Test](http://code.google.com/p/googletest/) +errors will be highlighted. Just press `` on one of them and +you'll be taken to the offending line. Or, you can just type `C-x `` +to jump to the next error. + +To make it even easier, you can add the following lines to your +`~/.emacs` file: + +``` +(global-set-key "\M-m" 'compile) ; m is for make +(global-set-key [M-down] 'next-error) +(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) +``` + +Then you can type `M-m` to start a build, or `M-up`/`M-down` to move +back and forth between errors. + +## Fusing Google Mock Source Files ## + +Google Mock's implementation consists of dozens of files (excluding +its own tests). Sometimes you may want them to be packaged up in +fewer files instead, such that you can easily copy them to a new +machine and start hacking there. For this we provide an experimental +Python script `fuse_gmock_files.py` in the `scripts/` directory +(starting with release 1.2.0). Assuming you have Python 2.4 or above +installed on your machine, just go to that directory and run +``` +python fuse_gmock_files.py OUTPUT_DIR +``` + +and you should see an `OUTPUT_DIR` directory being created with files +`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. +These three files contain everything you need to use Google Mock (and +Google Test). Just copy them to anywhere you want and you are ready +to write tests and use mocks. You can use the +[scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests +against them. + +# Extending Google Mock # + +## Writing New Matchers Quickly ## + +The `MATCHER*` family of macros can be used to define custom matchers +easily. The syntax: + +``` +MATCHER(name, description_string_expression) { statements; } +``` + +will define a matcher with the given name that executes the +statements, which must return a `bool` to indicate if the match +succeeds. Inside the statements, you can refer to the value being +matched by `arg`, and refer to its type by `arg_type`. + +The description string is a `string`-typed expression that documents +what the matcher does, and is used to generate the failure message +when the match fails. It can (and should) reference the special +`bool` variable `negation`, and should evaluate to the description of +the matcher when `negation` is `false`, or that of the matcher's +negation when `negation` is `true`. + +For convenience, we allow the description string to be empty (`""`), +in which case Google Mock will use the sequence of words in the +matcher name as the description. + +For example: +``` +MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } +``` +allows you to write +``` + // Expects mock_foo.Bar(n) to be called where n is divisible by 7. + EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); +``` +or, +``` +using ::testing::Not; +... + EXPECT_THAT(some_expression, IsDivisibleBy7()); + EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); +``` +If the above assertions fail, they will print something like: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 +... + Value of: some_other_expression + Expected: not (is divisible by 7) + Actual: 21 +``` +where the descriptions `"is divisible by 7"` and `"not (is divisible +by 7)"` are automatically calculated from the matcher name +`IsDivisibleBy7`. + +As you may have noticed, the auto-generated descriptions (especially +those for the negation) may not be so great. You can always override +them with a string expression of your own: +``` +MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + + " divisible by 7") { + return (arg % 7) == 0; +} +``` + +Optionally, you can stream additional information to a hidden argument +named `result_listener` to explain the match result. For example, a +better definition of `IsDivisibleBy7` is: +``` +MATCHER(IsDivisibleBy7, "") { + if ((arg % 7) == 0) + return true; + + *result_listener << "the remainder is " << (arg % 7); + return false; +} +``` + +With this definition, the above assertion will give a better message: +``` + Value of: some_expression + Expected: is divisible by 7 + Actual: 27 (the remainder is 6) +``` + +You should let `MatchAndExplain()` print _any additional information_ +that can help a user understand the match result. Note that it should +explain why the match succeeds in case of a success (unless it's +obvious) - this is useful when the matcher is used inside +`Not()`. There is no need to print the argument value itself, as +Google Mock already prints it for you. + +**Notes:** + + 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. + 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. + +## Writing New Parameterized Matchers Quickly ## + +Sometimes you'll want to define a matcher that has parameters. For that you +can use the macro: +``` +MATCHER_P(name, param_name, description_string) { statements; } +``` +where the description string can be either `""` or a string expression +that references `negation` and `param_name`. + +For example: +``` +MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +``` +will allow you to write: +``` + EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +``` +which may lead to this message (assuming `n` is 10): +``` + Value of: Blah("a") + Expected: has absolute value 10 + Actual: -9 +``` + +Note that both the matcher description and its parameter are +printed, making the message human-friendly. + +In the matcher definition body, you can write `foo_type` to +reference the type of a parameter named `foo`. For example, in the +body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write +`value_type` to refer to the type of `value`. + +Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to +`MATCHER_P10` to support multi-parameter matchers: +``` +MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } +``` + +Please note that the custom description string is for a particular +**instance** of the matcher, where the parameters have been bound to +actual values. Therefore usually you'll want the parameter values to +be part of the description. Google Mock lets you do that by +referencing the matcher parameters in the description string +expression. + +For example, +``` + using ::testing::PrintToString; + MATCHER_P2(InClosedRange, low, hi, + std::string(negation ? "isn't" : "is") + " in range [" + + PrintToString(low) + ", " + PrintToString(hi) + "]") { + return low <= arg && arg <= hi; + } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the message: +``` + Expected: is in range [4, 6] +``` + +If you specify `""` as the description, the failure message will +contain the sequence of words in the matcher name followed by the +parameter values printed as a tuple. For example, +``` + MATCHER_P2(InClosedRange, low, hi, "") { ... } + ... + EXPECT_THAT(3, InClosedRange(4, 6)); +``` +would generate a failure that contains the text: +``` + Expected: in closed range (4, 6) +``` + +For the purpose of typing, you can view +``` +MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +``` +as shorthand for +``` +template +FooMatcherPk +Foo(p1_type p1, ..., pk_type pk) { ... } +``` + +When you write `Foo(v1, ..., vk)`, the compiler infers the types of +the parameters `v1`, ..., and `vk` for you. If you are not happy with +the result of the type inference, you can specify the types by +explicitly instantiating the template, as in `Foo(5, false)`. +As said earlier, you don't get to (or need to) specify +`arg_type` as that's determined by the context in which the matcher +is used. + +You can assign the result of expression `Foo(p1, ..., pk)` to a +variable of type `FooMatcherPk`. This can be +useful when composing matchers. Matchers that don't have a parameter +or have only one parameter have special types: you can assign `Foo()` +to a `FooMatcher`-typed variable, and assign `Foo(p)` to a +`FooMatcherP`-typed variable. + +While you can instantiate a matcher template with reference types, +passing the parameters by pointer usually makes your code more +readable. If, however, you still want to pass a parameter by +reference, be aware that in the failure message generated by the +matcher you will see the value of the referenced object but not its +address. + +You can overload matchers with different numbers of parameters: +``` +MATCHER_P(Blah, a, description_string_1) { ... } +MATCHER_P2(Blah, a, b, description_string_2) { ... } +``` + +While it's tempting to always use the `MATCHER*` macros when defining +a new matcher, you should also consider implementing +`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see +the recipes that follow), especially if you need to use the matcher a +lot. While these approaches require more work, they give you more +control on the types of the value being matched and the matcher +parameters, which in general leads to better compiler error messages +that pay off in the long run. They also allow overloading matchers +based on parameter types (as opposed to just based on the number of +parameters). + +## Writing New Monomorphic Matchers ## + +A matcher of argument type `T` implements +`::testing::MatcherInterface` and does two things: it tests whether a +value of type `T` matches the matcher, and can describe what kind of +values it matches. The latter ability is used for generating readable +error messages when expectations are violated. + +The interface looks like this: + +``` +class MatchResultListener { + public: + ... + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x); + + // Returns the underlying ostream. + ::std::ostream* stream(); +}; + +template +class MatcherInterface { + public: + virtual ~MatcherInterface(); + + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Describes this matcher to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. + virtual void DescribeNegationTo(::std::ostream* os) const; +}; +``` + +If you need a custom matcher but `Truly()` is not a good option (for +example, you may not be happy with the way `Truly(predicate)` +describes itself, or you may want your matcher to be polymorphic as +`Eq(value)` is), you can define a matcher to do whatever you want in +two steps: first implement the matcher interface, and then define a +factory function to create a matcher instance. The second step is not +strictly needed but it makes the syntax of using the matcher nicer. + +For example, you can define a matcher to test whether an `int` is +divisible by 7 and then use it like this: +``` +using ::testing::MakeMatcher; +using ::testing::Matcher; +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { + return (n % 7) == 0; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is divisible by 7"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "is not divisible by 7"; + } +}; + +inline Matcher DivisibleBy7() { + return MakeMatcher(new DivisibleBy7Matcher); +} +... + + EXPECT_CALL(foo, Bar(DivisibleBy7())); +``` + +You may improve the matcher message by streaming additional +information to the `listener` argument in `MatchAndExplain()`: + +``` +class DivisibleBy7Matcher : public MatcherInterface { + public: + virtual bool MatchAndExplain(int n, + MatchResultListener* listener) const { + const int remainder = n % 7; + if (remainder != 0) { + *listener << "the remainder is " << remainder; + } + return remainder == 0; + } + ... +}; +``` + +Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: +``` +Value of: x +Expected: is divisible by 7 + Actual: 23 (the remainder is 2) +``` + +## Writing New Polymorphic Matchers ## + +You've learned how to write your own matchers in the previous +recipe. Just one problem: a matcher created using `MakeMatcher()` only +works for one particular type of arguments. If you want a +_polymorphic_ matcher that works with arguments of several types (for +instance, `Eq(x)` can be used to match a `value` as long as `value` == +`x` compiles -- `value` and `x` don't have to share the same type), +you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit +involved. + +Fortunately, most of the time you can define a polymorphic matcher +easily with the help of `MakePolymorphicMatcher()`. Here's how you can +define `NotNull()` as an example: + +``` +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +using ::testing::NotNull; +using ::testing::PolymorphicMatcher; + +class NotNullMatcher { + public: + // To implement a polymorphic matcher, first define a COPYABLE class + // that has three members MatchAndExplain(), DescribeTo(), and + // DescribeNegationTo(), like the following. + + // In this example, we want to use NotNull() with any pointer, so + // MatchAndExplain() accepts a pointer of any type as its first argument. + // In general, you can define MatchAndExplain() as an ordinary method or + // a method template, or even overload it. + template + bool MatchAndExplain(T* p, + MatchResultListener* /* listener */) const { + return p != NULL; + } + + // Describes the property of a value matching this matcher. + void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } + + // Describes the property of a value NOT matching this matcher. + void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } +}; + +// To construct a polymorphic matcher, pass an instance of the class +// to MakePolymorphicMatcher(). Note the return type. +inline PolymorphicMatcher NotNull() { + return MakePolymorphicMatcher(NotNullMatcher()); +} +... + + EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. +``` + +**Note:** Your polymorphic matcher class does **not** need to inherit from +`MatcherInterface` or any other class, and its methods do **not** need +to be virtual. + +Like in a monomorphic matcher, you may explain the match result by +streaming additional information to the `listener` argument in +`MatchAndExplain()`. + +## Writing New Cardinalities ## + +A cardinality is used in `Times()` to tell Google Mock how many times +you expect a call to occur. It doesn't have to be exact. For example, +you can say `AtLeast(5)` or `Between(2, 4)`. + +If the built-in set of cardinalities doesn't suit you, you are free to +define your own by implementing the following interface (in namespace +`testing`): + +``` +class CardinalityInterface { + public: + virtual ~CardinalityInterface(); + + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; +``` + +For example, to specify that a call must occur even number of times, +you can write + +``` +using ::testing::Cardinality; +using ::testing::CardinalityInterface; +using ::testing::MakeCardinality; + +class EvenNumberCardinality : public CardinalityInterface { + public: + virtual bool IsSatisfiedByCallCount(int call_count) const { + return (call_count % 2) == 0; + } + + virtual bool IsSaturatedByCallCount(int call_count) const { + return false; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "called even number of times"; + } +}; + +Cardinality EvenNumber() { + return MakeCardinality(new EvenNumberCardinality); +} +... + + EXPECT_CALL(foo, Bar(3)) + .Times(EvenNumber()); +``` + +## Writing New Actions Quickly ## + +If the built-in actions don't work for you, and you find it +inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` +family to quickly define a new action that can be used in your code as +if it's a built-in action. + +By writing +``` +ACTION(name) { statements; } +``` +in a namespace scope (i.e. not inside a class or function), you will +define an action with the given name that executes the statements. +The value returned by `statements` will be used as the return value of +the action. Inside the statements, you can refer to the K-th +(0-based) argument of the mock function as `argK`. For example: +``` +ACTION(IncrementArg1) { return ++(*arg1); } +``` +allows you to write +``` +... WillOnce(IncrementArg1()); +``` + +Note that you don't need to specify the types of the mock function +arguments. Rest assured that your code is type-safe though: +you'll get a compiler error if `*arg1` doesn't support the `++` +operator, or if the type of `++(*arg1)` isn't compatible with the mock +function's return type. + +Another example: +``` +ACTION(Foo) { + (*arg2)(5); + Blah(); + *arg1 = 0; + return arg0; +} +``` +defines an action `Foo()` that invokes argument #2 (a function pointer) +with 5, calls function `Blah()`, sets the value pointed to by argument +#1 to 0, and returns argument #0. + +For more convenience and flexibility, you can also use the following +pre-defined symbols in the body of `ACTION`: + +| `argK_type` | The type of the K-th (0-based) argument of the mock function | +|:------------|:-------------------------------------------------------------| +| `args` | All arguments of the mock function as a tuple | +| `args_type` | The type of all arguments of the mock function as a tuple | +| `return_type` | The return type of the mock function | +| `function_type` | The type of the mock function | + +For example, when using an `ACTION` as a stub action for mock function: +``` +int DoSomething(bool flag, int* ptr); +``` +we have: +| **Pre-defined Symbol** | **Is Bound To** | +|:-----------------------|:----------------| +| `arg0` | the value of `flag` | +| `arg0_type` | the type `bool` | +| `arg1` | the value of `ptr` | +| `arg1_type` | the type `int*` | +| `args` | the tuple `(flag, ptr)` | +| `args_type` | the type `std::tr1::tuple` | +| `return_type` | the type `int` | +| `function_type` | the type `int(bool, int*)` | + +## Writing New Parameterized Actions Quickly ## + +Sometimes you'll want to parameterize an action you define. For that +we have another macro +``` +ACTION_P(name, param) { statements; } +``` + +For example, +``` +ACTION_P(Add, n) { return arg0 + n; } +``` +will allow you to write +``` +// Returns argument #0 + 5. +... WillOnce(Add(5)); +``` + +For convenience, we use the term _arguments_ for the values used to +invoke the mock function, and the term _parameters_ for the values +used to instantiate an action. + +Note that you don't need to provide the type of the parameter either. +Suppose the parameter is named `param`, you can also use the +Google-Mock-defined symbol `param_type` to refer to the type of the +parameter as inferred by the compiler. For example, in the body of +`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. + +Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support +multi-parameter actions. For example, +``` +ACTION_P2(ReturnDistanceTo, x, y) { + double dx = arg0 - x; + double dy = arg1 - y; + return sqrt(dx*dx + dy*dy); +} +``` +lets you write +``` +... WillOnce(ReturnDistanceTo(5.0, 26.5)); +``` + +You can view `ACTION` as a degenerated parameterized action where the +number of parameters is 0. + +You can also easily define actions overloaded on the number of parameters: +``` +ACTION_P(Plus, a) { ... } +ACTION_P2(Plus, a, b) { ... } +``` + +## Restricting the Type of an Argument or Parameter in an ACTION ## + +For maximum brevity and reusability, the `ACTION*` macros don't ask +you to provide the types of the mock function arguments and the action +parameters. Instead, we let the compiler infer the types for us. + +Sometimes, however, we may want to be more explicit about the types. +There are several tricks to do that. For example: +``` +ACTION(Foo) { + // Makes sure arg0 can be converted to int. + int n = arg0; + ... use n instead of arg0 here ... +} + +ACTION_P(Bar, param) { + // Makes sure the type of arg1 is const char*. + ::testing::StaticAssertTypeEq(); + + // Makes sure param can be converted to bool. + bool flag = param; +} +``` +where `StaticAssertTypeEq` is a compile-time assertion in Google Test +that verifies two types are the same. + +## Writing New Action Templates Quickly ## + +Sometimes you want to give an action explicit template parameters that +cannot be inferred from its value parameters. `ACTION_TEMPLATE()` +supports that and can be viewed as an extension to `ACTION()` and +`ACTION_P*()`. + +The syntax: +``` +ACTION_TEMPLATE(ActionName, + HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), + AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } +``` + +defines an action template that takes _m_ explicit template parameters +and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is +between 0 and 10. `name_i` is the name of the i-th template +parameter, and `kind_i` specifies whether it's a `typename`, an +integral constant, or a template. `p_i` is the name of the i-th value +parameter. + +Example: +``` +// DuplicateArg(output) converts the k-th argument of the mock +// function to type T and copies it to *output. +ACTION_TEMPLATE(DuplicateArg, + // Note the comma between int and k: + HAS_2_TEMPLATE_PARAMS(int, k, typename, T), + AND_1_VALUE_PARAMS(output)) { + *output = T(std::tr1::get(args)); +} +``` + +To create an instance of an action template, write: +``` + ActionName(v1, ..., v_n) +``` +where the `t`s are the template arguments and the +`v`s are the value arguments. The value argument +types are inferred by the compiler. For example: +``` +using ::testing::_; +... + int n; + EXPECT_CALL(mock, Foo(_, _)) + .WillOnce(DuplicateArg<1, unsigned char>(&n)); +``` + +If you want to explicitly specify the value argument types, you can +provide additional template arguments: +``` + ActionName(v1, ..., v_n) +``` +where `u_i` is the desired type of `v_i`. + +`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the +number of value parameters, but not on the number of template +parameters. Without the restriction, the meaning of the following is +unclear: + +``` + OverloadedAction(x); +``` + +Are we using a single-template-parameter action where `bool` refers to +the type of `x`, or a two-template-parameter action where the compiler +is asked to infer the type of `x`? + +## Using the ACTION Object's Type ## + +If you are writing a function that returns an `ACTION` object, you'll +need to know its type. The type depends on the macro used to define +the action and the parameter types. The rule is relatively simple: +| **Given Definition** | **Expression** | **Has Type** | +|:---------------------|:---------------|:-------------| +| `ACTION(Foo)` | `Foo()` | `FooAction` | +| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | +| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | +| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | +| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | +| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | +| ... | ... | ... | + +Note that we have to pick different suffixes (`Action`, `ActionP`, +`ActionP2`, and etc) for actions with different numbers of value +parameters, or the action definitions cannot be overloaded on the +number of them. + +## Writing New Monomorphic Actions ## + +While the `ACTION*` macros are very convenient, sometimes they are +inappropriate. For example, despite the tricks shown in the previous +recipes, they don't let you directly specify the types of the mock +function arguments and the action parameters, which in general leads +to unoptimized compiler error messages that can baffle unfamiliar +users. They also don't allow overloading actions based on parameter +types without jumping through some hoops. + +An alternative to the `ACTION*` macros is to implement +`::testing::ActionInterface`, where `F` is the type of the mock +function in which the action will be used. For example: + +``` +template class ActionInterface { + public: + virtual ~ActionInterface(); + + // Performs the action. Result is the return type of function type + // F, and ArgumentTuple is the tuple of arguments of F. + // + // For example, if F is int(bool, const string&), then Result would + // be int, and ArgumentTuple would be tr1::tuple. + virtual Result Perform(const ArgumentTuple& args) = 0; +}; + +using ::testing::_; +using ::testing::Action; +using ::testing::ActionInterface; +using ::testing::MakeAction; + +typedef int IncrementMethod(int*); + +class IncrementArgumentAction : public ActionInterface { + public: + virtual int Perform(const tr1::tuple& args) { + int* p = tr1::get<0>(args); // Grabs the first argument. + return *p++; + } +}; + +Action IncrementArgument() { + return MakeAction(new IncrementArgumentAction); +} +... + + EXPECT_CALL(foo, Baz(_)) + .WillOnce(IncrementArgument()); + + int n = 5; + foo.Baz(&n); // Should return 5 and change n to 6. +``` + +## Writing New Polymorphic Actions ## + +The previous recipe showed you how to define your own action. This is +all good, except that you need to know the type of the function in +which the action will be used. Sometimes that can be a problem. For +example, if you want to use the action in functions with _different_ +types (e.g. like `Return()` and `SetArgPointee()`). + +If an action can be used in several types of mock functions, we say +it's _polymorphic_. The `MakePolymorphicAction()` function template +makes it easy to define such an action: + +``` +namespace testing { + +template +PolymorphicAction MakePolymorphicAction(const Impl& impl); + +} // namespace testing +``` + +As an example, let's define an action that returns the second argument +in the mock function's argument list. The first step is to define an +implementation class: + +``` +class ReturnSecondArgumentAction { + public: + template + Result Perform(const ArgumentTuple& args) const { + // To get the i-th (0-based) argument, use tr1::get(args). + return tr1::get<1>(args); + } +}; +``` + +This implementation class does _not_ need to inherit from any +particular class. What matters is that it must have a `Perform()` +method template. This method template takes the mock function's +arguments as a tuple in a **single** argument, and returns the result of +the action. It can be either `const` or not, but must be invokable +with exactly one template argument, which is the result type. In other +words, you must be able to call `Perform(args)` where `R` is the +mock function's return type and `args` is its arguments in a tuple. + +Next, we use `MakePolymorphicAction()` to turn an instance of the +implementation class into the polymorphic action we need. It will be +convenient to have a wrapper for this: + +``` +using ::testing::MakePolymorphicAction; +using ::testing::PolymorphicAction; + +PolymorphicAction ReturnSecondArgument() { + return MakePolymorphicAction(ReturnSecondArgumentAction()); +} +``` + +Now, you can use this polymorphic action the same way you use the +built-in ones: + +``` +using ::testing::_; + +class MockFoo : public Foo { + public: + MOCK_METHOD2(DoThis, int(bool flag, int n)); + MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); +}; +... + + MockFoo foo; + EXPECT_CALL(foo, DoThis(_, _)) + .WillOnce(ReturnSecondArgument()); + EXPECT_CALL(foo, DoThat(_, _, _)) + .WillOnce(ReturnSecondArgument()); + ... + foo.DoThis(true, 5); // Will return 5. + foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". +``` + +## Teaching Google Mock How to Print Your Values ## + +When an uninteresting or unexpected call occurs, Google Mock prints the +argument values and the stack trace to help you debug. Assertion +macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in +question when the assertion fails. Google Mock and Google Test do this using +Google Test's user-extensible value printer. + +This printer knows how to print built-in C++ types, native arrays, STL +containers, and any type that supports the `<<` operator. For other +types, it prints the raw bytes in the value and hopes that you the +user can figure it out. +[Google Test's advanced guide](http://code.google.com/p/googletest/wiki/AdvancedGuide#Teaching_Google_Test_How_to_Print_Your_Values) +explains how to extend the printer to do a better job at +printing your particular type than to dump the bytes. \ No newline at end of file diff --git a/googlemock/docs/v1_7/Documentation.md b/googlemock/docs/v1_7/Documentation.md new file mode 100644 index 0000000..d9181f2 --- /dev/null +++ b/googlemock/docs/v1_7/Documentation.md @@ -0,0 +1,12 @@ +This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)** +- **if you use a released version of Google Mock, please read the documentation for that specific version instead.** + + * [ForDummies](V1_7_ForDummies.md) -- start here if you are new to Google Mock. + * [CheatSheet](V1_7_CheatSheet.md) -- a quick reference. + * [CookBook](V1_7_CookBook.md) -- recipes for doing various tasks using Google Mock. + * [FrequentlyAskedQuestions](V1_7_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. + +To contribute code to Google Mock, read: + + * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. + * [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files. \ No newline at end of file diff --git a/googlemock/docs/v1_7/ForDummies.md b/googlemock/docs/v1_7/ForDummies.md new file mode 100644 index 0000000..ee03c5b --- /dev/null +++ b/googlemock/docs/v1_7/ForDummies.md @@ -0,0 +1,439 @@ + + +(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_7_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).) + +# What Is Google C++ Mocking Framework? # +When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). + +**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: + + * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. + * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. + +If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. + +**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. + +Using Google Mock involves three basic steps: + + 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; + 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; + 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. + +# Why Google Mock? # +While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: + + * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. + * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. + * The knowledge you gained from using one mock doesn't transfer to the next. + +In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. + +Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: + + * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". + * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). + * Your tests are brittle as some resources they use are unreliable (e.g. the network). + * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. + * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. + * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. + +We encourage you to use Google Mock as: + + * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! + * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. + +# Getting Started # +Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. + +# A Case for Mock Turtles # +Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: + +``` +class Turtle { + ... + virtual ~Turtle() {} + virtual void PenUp() = 0; + virtual void PenDown() = 0; + virtual void Forward(int distance) = 0; + virtual void Turn(int degrees) = 0; + virtual void GoTo(int x, int y) = 0; + virtual int GetX() const = 0; + virtual int GetY() const = 0; +}; +``` + +(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) + +You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. + +Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. + +# Writing the Mock Class # +If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) + +## How to Define It ## +Using the `Turtle` interface as example, here are the simple steps you need to follow: + + 1. Derive a class `MockTurtle` from `Turtle`. + 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has. + 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. + 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). + 1. Repeat until all virtual functions you want to mock are done. + +After the process, you should have something like: + +``` +#include "gmock/gmock.h" // Brings in Google Mock. +class MockTurtle : public Turtle { + public: + ... + MOCK_METHOD0(PenUp, void()); + MOCK_METHOD0(PenDown, void()); + MOCK_METHOD1(Forward, void(int distance)); + MOCK_METHOD1(Turn, void(int degrees)); + MOCK_METHOD2(GoTo, void(int x, int y)); + MOCK_CONST_METHOD0(GetX, int()); + MOCK_CONST_METHOD0(GetY, int()); +}; +``` + +You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. + +**Tip:** If even this is too much work for you, you'll find the +`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line +tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, +and it will print the definition of the mock class for you. Due to the +complexity of the C++ language, this script may not always work, but +it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). + +## Where to Put It ## +When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) + +So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. + +Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. + +# Using Mocks in Tests # +Once you have a mock class, using it is easy. The typical work flow is: + + 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). + 1. Create some mock objects. + 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). + 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. + 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. + +Here's an example: + +``` +#include "path/to/mock-turtle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +using ::testing::AtLeast; // #1 + +TEST(PainterTest, CanDrawSomething) { + MockTurtle turtle; // #2 + EXPECT_CALL(turtle, PenDown()) // #3 + .Times(AtLeast(1)); + + Painter painter(&turtle); // #4 + + EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); +} // #5 + +int main(int argc, char** argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} +``` + +As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: + +``` +path/to/my_test.cc:119: Failure +Actual function call count doesn't match this expectation: +Actually: never called; +Expected: called at least once. +``` + +**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. + +**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. + +**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. + +This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. + +Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. + +## Using Google Mock with Any Testing Framework ## +If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or +[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: +``` +int main(int argc, char** argv) { + // The following line causes Google Mock to throw an exception on failure, + // which will be interpreted by your testing framework as a test failure. + ::testing::GTEST_FLAG(throw_on_failure) = true; + ::testing::InitGoogleMock(&argc, argv); + ... whatever your testing framework requires ... +} +``` + +This approach has a catch: it makes Google Mock throw an exception +from a mock object's destructor sometimes. With some compilers, this +sometimes causes the test program to crash. You'll still be able to +notice that the test has failed, but it's not a graceful failure. + +A better solution is to use Google Test's +[event listener API](http://code.google.com/p/googletest/wiki/AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) +to report a test failure to your testing framework properly. You'll need to +implement the `OnTestPartResult()` method of the event listener interface, but it +should be straightforward. + +If this turns out to be too much work, we suggest that you stick with +Google Test, which works with Google Mock seamlessly (in fact, it is +technically part of Google Mock.). If there is a reason that you +cannot use Google Test, please let us know. + +# Setting Expectations # +The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." + +## General Syntax ## +In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: + +``` +EXPECT_CALL(mock_object, method(matchers)) + .Times(cardinality) + .WillOnce(action) + .WillRepeatedly(action); +``` + +The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) + +The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. + +This syntax is designed to make an expectation read like English. For example, you can probably guess that + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .Times(5) + .WillOnce(Return(100)) + .WillOnce(Return(150)) + .WillRepeatedly(Return(200)); +``` + +says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). + +**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. + +## Matchers: What Arguments Do We Expect? ## +When a mock function takes arguments, we must specify what arguments we are expecting; for example: + +``` +// Expects the turtle to move forward by 100 units. +EXPECT_CALL(turtle, Forward(100)); +``` + +Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": + +``` +using ::testing::_; +... +// Expects the turtle to move forward. +EXPECT_CALL(turtle, Forward(_)); +``` + +`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. + +A list of built-in matchers can be found in the [CheatSheet](V1_7_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: + +``` +using ::testing::Ge;... +EXPECT_CALL(turtle, Forward(Ge(100))); +``` + +This checks that the turtle will be told to go forward by at least 100 units. + +## Cardinalities: How Many Times Will It Be Called? ## +The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. + +An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. + +We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_7_CheatSheet.md). + +The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: + + * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. + * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. + * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. + +**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? + +## Actions: What Should It Do? ## +Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. + +First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. + +Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillOnce(Return(300)); +``` + +This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) + .WillOnce(Return(100)) + .WillOnce(Return(200)) + .WillRepeatedly(Return(300)); +``` + +says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. + +Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). + +What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_7_CheatSheet#Actions). + +**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: + +``` +int n = 100; +EXPECT_CALL(turtle, GetX()) +.Times(4) +.WillRepeatedly(Return(n++)); +``` + +Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_7_CookBook.md). + +Time for another quiz! What do you think the following means? + +``` +using ::testing::Return;... +EXPECT_CALL(turtle, GetY()) +.Times(4) +.WillOnce(Return(100)); +``` + +Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. + +## Using Multiple Expectations ## +So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. + +By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: + +``` +using ::testing::_;... +EXPECT_CALL(turtle, Forward(_)); // #1 +EXPECT_CALL(turtle, Forward(10)) // #2 + .Times(2); +``` + +If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. + +**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. + +## Ordered vs Unordered Calls ## +By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. + +Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: + +``` +using ::testing::InSequence;... +TEST(FooTest, DrawsLineSegment) { + ... + { + InSequence dummy; + + EXPECT_CALL(turtle, PenDown()); + EXPECT_CALL(turtle, Forward(100)); + EXPECT_CALL(turtle, PenUp()); + } + Foo(); +} +``` + +By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. + +In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. + +(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_7_CookBook#Expecting_Partially_Ordered_Calls.md).) + +## All Expectations Are Sticky (Unless Said Otherwise) ## +Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? + +After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): + +``` +using ::testing::_;... +EXPECT_CALL(turtle, GoTo(_, _)) // #1 + .Times(AnyNumber()); +EXPECT_CALL(turtle, GoTo(0, 0)) // #2 + .Times(2); +``` + +Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. + +This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). + +Simple? Let's see if you've really understood it: what does the following code say? + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)); +} +``` + +If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! + +One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: + +``` +using ::testing::Return; +... +for (int i = n; i > 0; i--) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); +} +``` + +And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: + +``` +using ::testing::InSequence; +using ::testing::Return; +... +{ + InSequence s; + + for (int i = 1; i <= n; i++) { + EXPECT_CALL(turtle, GetX()) + .WillOnce(Return(10*i)) + .RetiresOnSaturation(); + } +} +``` + +By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). + +## Uninteresting Calls ## +A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. + +In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. + +# What Now? # +Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. + +Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_7_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. \ No newline at end of file diff --git a/googlemock/docs/v1_7/FrequentlyAskedQuestions.md b/googlemock/docs/v1_7/FrequentlyAskedQuestions.md new file mode 100644 index 0000000..fa21233 --- /dev/null +++ b/googlemock/docs/v1_7/FrequentlyAskedQuestions.md @@ -0,0 +1,628 @@ + + +Please send your questions to the +[googlemock](http://groups.google.com/group/googlemock) discussion +group. If you need help with compiler errors, make sure you have +tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. + +## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## + +In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods). + +## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## + +After version 1.4.0 of Google Mock was released, we had an idea on how +to make it easier to write matchers that can generate informative +messages efficiently. We experimented with this idea and liked what +we saw. Therefore we decided to implement it. + +Unfortunately, this means that if you have defined your own matchers +by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, +your definitions will no longer compile. Matchers defined using the +`MATCHER*` family of macros are not affected. + +Sorry for the hassle if your matchers are affected. We believe it's +in everyone's long-term interest to make this change sooner than +later. Fortunately, it's usually not hard to migrate an existing +matcher to the new API. Here's what you need to do: + +If you wrote your matcher like this: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` + +you'll need to change it to: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + ... +}; +``` +(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second +argument of type `MatchResultListener*`.) + +If you were also using `ExplainMatchResultTo()` to improve the matcher +message: +``` +// Old matcher definition that doesn't work with the lastest +// Google Mock. +using ::testing::MatcherInterface; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetFoo() > 5; + } + + virtual void ExplainMatchResultTo(MyType value, + ::std::ostream* os) const { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Foo property is " << value.GetFoo(); + } + ... +}; +``` + +you should move the logic of `ExplainMatchResultTo()` into +`MatchAndExplain()`, using the `MatchResultListener` argument where +the `::std::ostream` was used: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; +... +class MyWonderfulMatcher : public MatcherInterface { + public: + ... + virtual bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Foo property is " << value.GetFoo(); + return value.GetFoo() > 5; + } + ... +}; +``` + +If your matcher is defined using `MakePolymorphicMatcher()`: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you should rename the `Matches()` method to `MatchAndExplain()` and +add a `MatchResultListener*` argument (the same as what you need to do +for matchers defined by implementing `MatcherInterface`): +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +If your polymorphic matcher uses `ExplainMatchResultTo()` for better +failure messages: +``` +// Old matcher definition that doesn't work with the latest +// Google Mock. +using ::testing::MakePolymorphicMatcher; +... +class MyGreatMatcher { + public: + ... + bool Matches(MyType value) const { + // Returns true if value matches. + return value.GetBar() < 42; + } + ... +}; +void ExplainMatchResultTo(const MyGreatMatcher& matcher, + MyType value, + ::std::ostream* os) { + // Prints some helpful information to os to help + // a user understand why value matches (or doesn't match). + *os << "the Bar property is " << value.GetBar(); +} +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +you'll need to move the logic inside `ExplainMatchResultTo()` to +`MatchAndExplain()`: +``` +// New matcher definition that works with the latest Google Mock. +using ::testing::MakePolymorphicMatcher; +using ::testing::MatchResultListener; +... +class MyGreatMatcher { + public: + ... + bool MatchAndExplain(MyType value, + MatchResultListener* listener) const { + // Returns true if value matches. + *listener << "the Bar property is " << value.GetBar(); + return value.GetBar() < 42; + } + ... +}; +... MakePolymorphicMatcher(MyGreatMatcher()) ... +``` + +For more information, you can read these +[two](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Monomorphic_Matchers) +[recipes](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Matchers) +from the cookbook. As always, you +are welcome to post questions on `googlemock@googlegroups.com` if you +need any help. + +## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## + +Google Mock works out of the box with Google Test. However, it's easy +to configure it to work with any testing framework of your choice. +[Here](http://code.google.com/p/googlemock/wiki/V1_7_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how. + +## How am I supposed to make sense of these horrible template errors? ## + +If you are confused by the compiler errors gcc threw at you, +try consulting the _Google Mock Doctor_ tool first. What it does is to +scan stdin for gcc error messages, and spit out diagnoses on the +problems (we call them diseases) your code has. + +To "install", run command: +``` +alias gmd='/scripts/gmock_doctor.py' +``` + +To use it, do: +``` + 2>&1 | gmd +``` + +For example: +``` +make my_test 2>&1 | gmd +``` + +Or you can run `gmd` and copy-n-paste gcc's error messages to it. + +## Can I mock a variadic function? ## + +You cannot mock a variadic function (i.e. a function taking ellipsis +(`...`) arguments) directly in Google Mock. + +The problem is that in general, there is _no way_ for a mock object to +know how many arguments are passed to the variadic method, and what +the arguments' types are. Only the _author of the base class_ knows +the protocol, and we cannot look into his head. + +Therefore, to mock such a function, the _user_ must teach the mock +object how to figure out the number of arguments and their types. One +way to do it is to provide overloaded versions of the function. + +Ellipsis arguments are inherited from C and not really a C++ feature. +They are unsafe to use and don't work with arguments that have +constructors or destructors. Therefore we recommend to avoid them in +C++ as much as possible. + +## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## + +If you compile this using Microsoft Visual C++ 2005 SP1: +``` +class Foo { + ... + virtual void Bar(const int i) = 0; +}; + +class MockFoo : public Foo { + ... + MOCK_METHOD1(Bar, void(const int i)); +}; +``` +You may get the following warning: +``` +warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier +``` + +This is a MSVC bug. The same code compiles fine with gcc ,for +example. If you use Visual C++ 2008 SP1, you would get the warning: +``` +warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers +``` + +In C++, if you _declare_ a function with a `const` parameter, the +`const` modifier is _ignored_. Therefore, the `Foo` base class above +is equivalent to: +``` +class Foo { + ... + virtual void Bar(int i) = 0; // int or const int? Makes no difference. +}; +``` + +In fact, you can _declare_ Bar() with an `int` parameter, and _define_ +it with a `const int` parameter. The compiler will still match them +up. + +Since making a parameter `const` is meaningless in the method +_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. +That should workaround the VC bug. + +Note that we are talking about the _top-level_ `const` modifier here. +If the function parameter is passed by pointer or reference, declaring +the _pointee_ or _referee_ as `const` is still meaningful. For +example, the following two declarations are _not_ equivalent: +``` +void Bar(int* p); // Neither p nor *p is const. +void Bar(const int* p); // p is not const, but *p is. +``` + +## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## + +We've noticed that when the `/clr` compiler flag is used, Visual C++ +uses 5~6 times as much memory when compiling a mock class. We suggest +to avoid `/clr` when compiling native C++ mocks. + +## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## + +You might want to run your test with +`--gmock_verbose=info`. This flag lets Google Mock print a trace +of every mock function call it receives. By studying the trace, +you'll gain insights on why the expectations you set are not met. + +## How can I assert that a function is NEVER called? ## + +``` +EXPECT_CALL(foo, Bar(_)) + .Times(0); +``` + +## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## + +When Google Mock detects a failure, it prints relevant information +(the mock function arguments, the state of relevant expectations, and +etc) to help the user debug. If another failure is detected, Google +Mock will do the same, including printing the state of relevant +expectations. + +Sometimes an expectation's state didn't change between two failures, +and you'll see the same description of the state twice. They are +however _not_ redundant, as they refer to _different points in time_. +The fact they are the same _is_ interesting information. + +## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## + +Does the class (hopefully a pure interface) you are mocking have a +virtual destructor? + +Whenever you derive from a base class, make sure its destructor is +virtual. Otherwise Bad Things will happen. Consider the following +code: + +``` +class Base { + public: + // Not virtual, but should be. + ~Base() { ... } + ... +}; + +class Derived : public Base { + public: + ... + private: + std::string value_; +}; + +... + Base* p = new Derived; + ... + delete p; // Surprise! ~Base() will be called, but ~Derived() will not + // - value_ is leaked. +``` + +By changing `~Base()` to virtual, `~Derived()` will be correctly +called when `delete p` is executed, and the heap checker +will be happy. + +## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## + +When people complain about this, often they are referring to code like: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. However, I have to write the expectations in the +// reverse order. This sucks big time!!! +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); +``` + +The problem is that they didn't pick the **best** way to express the test's +intent. + +By default, expectations don't have to be matched in _any_ particular +order. If you want them to match in a certain order, you need to be +explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's +easy to accidentally over-specify your tests, and we want to make it +harder to do so. + +There are two better ways to write the test spec. You could either +put the expectations in sequence: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. Using a sequence, we can write the expectations +// in their natural order. +{ + InSequence s; + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .RetiresOnSaturation(); + EXPECT_CALL(foo, Bar()) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +} +``` + +or you can put the sequence of actions in the same expectation: + +``` +// foo.Bar() should be called twice, return 1 the first time, and return +// 2 the second time. +EXPECT_CALL(foo, Bar()) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .RetiresOnSaturation(); +``` + +Back to the original questions: why does Google Mock search the +expectations (and `ON_CALL`s) from back to front? Because this +allows a user to set up a mock's behavior for the common case early +(e.g. in the mock's constructor or the test fixture's set-up phase) +and customize it with more specific rules later. If Google Mock +searches from front to back, this very useful pattern won't be +possible. + +## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## + +When choosing between being neat and being safe, we lean toward the +latter. So the answer is that we think it's better to show the +warning. + +Often people write `ON_CALL`s in the mock object's +constructor or `SetUp()`, as the default behavior rarely changes from +test to test. Then in the test body they set the expectations, which +are often different for each test. Having an `ON_CALL` in the set-up +part of a test doesn't mean that the calls are expected. If there's +no `EXPECT_CALL` and the method is called, it's possibly an error. If +we quietly let the call go through without notifying the user, bugs +may creep in unnoticed. + +If, however, you are sure that the calls are OK, you can write + +``` +EXPECT_CALL(foo, Bar(_)) + .WillRepeatedly(...); +``` + +instead of + +``` +ON_CALL(foo, Bar(_)) + .WillByDefault(...); +``` + +This tells Google Mock that you do expect the calls and no warning should be +printed. + +Also, you can control the verbosity using the `--gmock_verbose` flag. +If you find the output too noisy when debugging, just choose a less +verbose level. + +## How can I delete the mock function's argument in an action? ## + +If you find yourself needing to perform some action that's not +supported by Google Mock directly, remember that you can define your own +actions using +[MakeAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Actions) or +[MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Actions), +or you can write a stub function and invoke it using +[Invoke()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Functions_Methods_Functors). + +## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## + +What?! I think it's beautiful. :-) + +While which syntax looks more natural is a subjective matter to some +extent, Google Mock's syntax was chosen for several practical advantages it +has. + +Try to mock a function that takes a map as an argument: +``` +virtual int GetSize(const map& m); +``` + +Using the proposed syntax, it would be: +``` +MOCK_METHOD1(GetSize, int, const map& m); +``` + +Guess what? You'll get a compiler error as the compiler thinks that +`const map& m` are **two**, not one, arguments. To work +around this you can use `typedef` to give the map type a name, but +that gets in the way of your work. Google Mock's syntax avoids this +problem as the function's argument types are protected inside a pair +of parentheses: +``` +// This compiles fine. +MOCK_METHOD1(GetSize, int(const map& m)); +``` + +You still need a `typedef` if the return type contains an unprotected +comma, but that's much rarer. + +Other advantages include: + 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. + 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. + 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! + +## My code calls a static/global function. Can I mock it? ## + +You can, but you need to make some changes. + +In general, if you find yourself needing to mock a static function, +it's a sign that your modules are too tightly coupled (and less +flexible, less reusable, less testable, etc). You are probably better +off defining a small interface and call the function through that +interface, which then can be easily mocked. It's a bit of work +initially, but usually pays for itself quickly. + +This Google Testing Blog +[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) +says it excellently. Check it out. + +## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## + +I know it's not a question, but you get an answer for free any way. :-) + +With Google Mock, you can create mocks in C++ easily. And people might be +tempted to use them everywhere. Sometimes they work great, and +sometimes you may find them, well, a pain to use. So, what's wrong in +the latter case? + +When you write a test without using mocks, you exercise the code and +assert that it returns the correct value or that the system is in an +expected state. This is sometimes called "state-based testing". + +Mocks are great for what some call "interaction-based" testing: +instead of checking the system state at the very end, mock objects +verify that they are invoked the right way and report an error as soon +as it arises, giving you a handle on the precise context in which the +error was triggered. This is often more effective and economical to +do than state-based testing. + +If you are doing state-based testing and using a test double just to +simulate the real object, you are probably better off using a fake. +Using a mock in this case causes pain, as it's not a strong point for +mocks to perform complex actions. If you experience this and think +that mocks suck, you are just not using the right tool for your +problem. Or, you might be trying to solve the wrong problem. :-) + +## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## + +By all means, NO! It's just an FYI. + +What it means is that you have a mock function, you haven't set any +expectations on it (by Google Mock's rule this means that you are not +interested in calls to this function and therefore it can be called +any number of times), and it is called. That's OK - you didn't say +it's not OK to call the function! + +What if you actually meant to disallow this function to be called, but +forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While +one can argue that it's the user's fault, Google Mock tries to be nice and +prints you a note. + +So, when you see the message and believe that there shouldn't be any +uninteresting calls, you should investigate what's going on. To make +your life easier, Google Mock prints the function name and arguments +when an uninteresting call is encountered. + +## I want to define a custom action. Should I use Invoke() or implement the action interface? ## + +Either way is fine - you want to choose the one that's more convenient +for your circumstance. + +Usually, if your action is for a particular function type, defining it +using `Invoke()` should be easier; if your action can be used in +functions of different types (e.g. if you are defining +`Return(value)`), `MakePolymorphicAction()` is +easiest. Sometimes you want precise control on what types of +functions the action can be used in, and implementing +`ActionInterface` is the way to go here. See the implementation of +`Return()` in `include/gmock/gmock-actions.h` for an example. + +## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## + +You got this error as Google Mock has no idea what value it should return +when the mock method is called. `SetArgPointee()` says what the +side effect is, but doesn't say what the return value should be. You +need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. + +See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Side_Effects) for more details and an example. + + +## My question is not in your FAQ! ## + +If you cannot find the answer to your question in this FAQ, there are +some other resources you can use: + + 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), + 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), + 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). + +Please note that creating an issue in the +[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ +a good way to get your answer, as it is monitored infrequently by a +very small number of people. + +When asking a question, it's helpful to provide as much of the +following information as possible (people cannot help you if there's +not enough information in your question): + + * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), + * your operating system, + * the name and version of your compiler, + * the complete command line flags you give to your compiler, + * the complete compiler error messages (if the question is about compilation), + * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. \ No newline at end of file diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h new file mode 100644 index 0000000..b3f654a --- /dev/null +++ b/googlemock/include/gmock/gmock-actions.h @@ -0,0 +1,1205 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ + +#ifndef _WIN32_WCE +# include +#endif + +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" + +#if GTEST_HAS_STD_TYPE_TRAITS_ // Defined by gtest-port.h via gmock-port.h. +#include +#endif + +namespace testing { + +// To implement an action Foo, define: +// 1. a class FooAction that implements the ActionInterface interface, and +// 2. a factory function that creates an Action object from a +// const FooAction*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Action objects can now be copied like plain values. + +namespace internal { + +template +class ActionAdaptor; + +// BuiltInDefaultValueGetter::Get() returns a +// default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. +// +// This primary template is used when kDefaultConstructible is true. +template +struct BuiltInDefaultValueGetter { + static T Get() { return T(); } +}; +template +struct BuiltInDefaultValueGetter { + static T Get() { + Assert(false, __FILE__, __LINE__, + "Default action undefined for the function return type."); + return internal::Invalid(); + // The above statement will never be reached, but is required in + // order for this function to compile. + } +}; + +// BuiltInDefaultValue::Get() returns the "built-in" default value +// for type T, which is NULL when T is a raw pointer type, 0 when T is +// a numeric type, false when T is bool, or "" when T is string or +// std::string. In addition, in C++11 and above, it turns a +// default-constructed T value if T is default constructible. For any +// other type T, the built-in default T value is undefined, and the +// function will abort the process. +template +class BuiltInDefaultValue { + public: +#if GTEST_HAS_STD_TYPE_TRAITS_ + // This function returns true iff type T has a built-in default value. + static bool Exists() { + return ::std::is_default_constructible::value; + } + + static T Get() { + return BuiltInDefaultValueGetter< + T, ::std::is_default_constructible::value>::Get(); + } + +#else // GTEST_HAS_STD_TYPE_TRAITS_ + // This function returns true iff type T has a built-in default value. + static bool Exists() { + return false; + } + + static T Get() { + return BuiltInDefaultValueGetter::Get(); + } + +#endif // GTEST_HAS_STD_TYPE_TRAITS_ +}; + +// This partial specialization says that we use the same built-in +// default value for T and const T. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return BuiltInDefaultValue::Exists(); } + static T Get() { return BuiltInDefaultValue::Get(); } +}; + +// This partial specialization defines the default values for pointer +// types. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return true; } + static T* Get() { return NULL; } +}; + +// The following specializations define the default values for +// specific types we care about. +#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ + template <> \ + class BuiltInDefaultValue { \ + public: \ + static bool Exists() { return true; } \ + static type Get() { return value; } \ + } + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT +#if GTEST_HAS_GLOBAL_STRING +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, ""); +#endif // GTEST_HAS_GLOBAL_STRING +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); + +// There's no need for a default action for signed wchar_t, as that +// type is the same as wchar_t for gcc, and invalid for MSVC. +// +// There's also no need for a default action for unsigned wchar_t, as +// that type is the same as unsigned int for gcc, and invalid for +// MSVC. +#if GMOCK_WCHAR_T_IS_NATIVE_ +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT +#endif + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(UInt64, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(Int64, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); + +#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ + +} // namespace internal + +// When an unexpected function call is encountered, Google Mock will +// let it return a default value if the user has specified one for its +// return type, or if the return type has a built-in default value; +// otherwise Google Mock won't know what value to return and will have +// to abort the process. +// +// The DefaultValue class allows a user to specify the +// default value for a type T that is both copyable and publicly +// destructible (i.e. anything that can be used as a function return +// type). The usage is: +// +// // Sets the default value for type T to be foo. +// DefaultValue::Set(foo); +template +class DefaultValue { + public: + // Sets the default value for type T; requires T to be + // copy-constructable and have a public destructor. + static void Set(T x) { + delete producer_; + producer_ = new FixedValueProducer(x); + } + + // Provides a factory function to be called to generate the default value. + // This method can be used even if T is only move-constructible, but it is not + // limited to that case. + typedef T (*FactoryFunction)(); + static void SetFactory(FactoryFunction factory) { + delete producer_; + producer_ = new FactoryValueProducer(factory); + } + + // Unsets the default value for type T. + static void Clear() { + delete producer_; + producer_ = NULL; + } + + // Returns true iff the user has set the default value for type T. + static bool IsSet() { return producer_ != NULL; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T if the user has set one; + // otherwise returns the built-in default value. Requires that Exists() + // is true, which ensures that the return value is well-defined. + static T Get() { + return producer_ == NULL ? + internal::BuiltInDefaultValue::Get() : producer_->Produce(); + } + + private: + class ValueProducer { + public: + virtual ~ValueProducer() {} + virtual T Produce() = 0; + }; + + class FixedValueProducer : public ValueProducer { + public: + explicit FixedValueProducer(T value) : value_(value) {} + virtual T Produce() { return value_; } + + private: + const T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(FixedValueProducer); + }; + + class FactoryValueProducer : public ValueProducer { + public: + explicit FactoryValueProducer(FactoryFunction factory) + : factory_(factory) {} + virtual T Produce() { return factory_(); } + + private: + const FactoryFunction factory_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(FactoryValueProducer); + }; + + static ValueProducer* producer_; +}; + +// This partial specialization allows a user to set default values for +// reference types. +template +class DefaultValue { + public: + // Sets the default value for type T&. + static void Set(T& x) { // NOLINT + address_ = &x; + } + + // Unsets the default value for type T&. + static void Clear() { + address_ = NULL; + } + + // Returns true iff the user has set the default value for type T&. + static bool IsSet() { return address_ != NULL; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T& if the user has set one; + // otherwise returns the built-in default value if there is one; + // otherwise aborts the process. + static T& Get() { + return address_ == NULL ? + internal::BuiltInDefaultValue::Get() : *address_; + } + + private: + static T* address_; +}; + +// This specialization allows DefaultValue::Get() to +// compile. +template <> +class DefaultValue { + public: + static bool Exists() { return true; } + static void Get() {} +}; + +// Points to the user-set default value for type T. +template +typename DefaultValue::ValueProducer* DefaultValue::producer_ = NULL; + +// Points to the user-set default value for type T&. +template +T* DefaultValue::address_ = NULL; + +// Implement this interface to define an action for function type F. +template +class ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + ActionInterface() {} + virtual ~ActionInterface() {} + + // Performs the action. This method is not const, as in general an + // action can have side effects and be stateful. For example, a + // get-the-next-element-from-the-collection action will need to + // remember the current element. + virtual Result Perform(const ArgumentTuple& args) = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); +}; + +// An Action is a copyable and IMMUTABLE (except by assignment) +// object that represents an action to be taken when a mock function +// of type F is called. The implementation of Action is just a +// linked_ptr to const ActionInterface, so copying is fairly cheap. +// Don't inherit from Action! +// +// You can view an object implementing ActionInterface as a +// concrete action (including its current state), and an Action +// object as a handle to it. +template +class Action { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + // Constructs a null Action. Needed for storing Action objects in + // STL containers. + Action() : impl_(NULL) {} + + // Constructs an Action from its implementation. A NULL impl is + // used to represent the "do-default" action. + explicit Action(ActionInterface* impl) : impl_(impl) {} + + // Copy constructor. + Action(const Action& action) : impl_(action.impl_) {} + + // This constructor allows us to turn an Action object into an + // Action, as long as F's arguments can be implicitly converted + // to Func's and Func's return type can be implicitly converted to + // F's. + template + explicit Action(const Action& action); + + // Returns true iff this is the DoDefault() action. + bool IsDoDefault() const { return impl_.get() == NULL; } + + // Performs the action. Note that this method is const even though + // the corresponding method in ActionInterface is not. The reason + // is that a const Action means that it cannot be re-bound to + // another concrete action, not that the concrete action it binds to + // cannot change state. (Think of the difference between a const + // pointer and a pointer to const.) + Result Perform(const ArgumentTuple& args) const { + internal::Assert( + !IsDoDefault(), __FILE__, __LINE__, + "You are using DoDefault() inside a composite action like " + "DoAll() or WithArgs(). This is not supported for technical " + "reasons. Please instead spell out the default action, or " + "assign the default action to an Action variable and use " + "the variable in various places."); + return impl_->Perform(args); + } + + private: + template + friend class internal::ActionAdaptor; + + internal::linked_ptr > impl_; +}; + +// The PolymorphicAction class template makes it easy to implement a +// polymorphic action (i.e. an action that can be used in mock +// functions of than one type, e.g. Return()). +// +// To define a polymorphic action, a user first provides a COPYABLE +// implementation class that has a Perform() method template: +// +// class FooAction { +// public: +// template +// Result Perform(const ArgumentTuple& args) const { +// // Processes the arguments and returns a result, using +// // tr1::get(args) to get the N-th (0-based) argument in the tuple. +// } +// ... +// }; +// +// Then the user creates the polymorphic action using +// MakePolymorphicAction(object) where object has type FooAction. See +// the definition of Return(void) and SetArgumentPointee(value) for +// complete examples. +template +class PolymorphicAction { + public: + explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} + + template + operator Action() const { + return Action(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual Result Perform(const ArgumentTuple& args) { + return impl_.template Perform(args); + } + + private: + Impl impl_; + + GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); + }; + + Impl impl_; + + GTEST_DISALLOW_ASSIGN_(PolymorphicAction); +}; + +// Creates an Action from its implementation and returns it. The +// created Action object owns the implementation. +template +Action MakeAction(ActionInterface* impl) { + return Action(impl); +} + +// Creates a polymorphic action from its implementation. This is +// easier to use than the PolymorphicAction constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicAction(foo); +// vs +// PolymorphicAction(foo); +template +inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { + return PolymorphicAction(impl); +} + +namespace internal { + +// Allows an Action object to pose as an Action, as long as F2 +// and F1 are compatible. +template +class ActionAdaptor : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit ActionAdaptor(const Action& from) : impl_(from.impl_) {} + + virtual Result Perform(const ArgumentTuple& args) { + return impl_->Perform(args); + } + + private: + const internal::linked_ptr > impl_; + + GTEST_DISALLOW_ASSIGN_(ActionAdaptor); +}; + +// Helper struct to specialize ReturnAction to execute a move instead of a copy +// on return. Useful for move-only types, but could be used on any type. +template +struct ByMoveWrapper { + explicit ByMoveWrapper(T value) : payload(internal::move(value)) {} + T payload; +}; + +// Implements the polymorphic Return(x) action, which can be used in +// any function that returns the type of x, regardless of the argument +// types. +// +// Note: The value passed into Return must be converted into +// Function::Result when this action is cast to Action rather than +// when that action is performed. This is important in scenarios like +// +// MOCK_METHOD1(Method, T(U)); +// ... +// { +// Foo foo; +// X x(&foo); +// EXPECT_CALL(mock, Method(_)).WillOnce(Return(x)); +// } +// +// In the example above the variable x holds reference to foo which leaves +// scope and gets destroyed. If copying X just copies a reference to foo, +// that copy will be left with a hanging reference. If conversion to T +// makes a copy of foo, the above code is safe. To support that scenario, we +// need to make sure that the type conversion happens inside the EXPECT_CALL +// statement, and conversion of the result of Return to Action is a +// good place for that. +// +template +class ReturnAction { + public: + // Constructs a ReturnAction object from the value to be returned. + // 'value' is passed by value instead of by const reference in order + // to allow Return("string literal") to compile. + explicit ReturnAction(R value) : value_(new R(internal::move(value))) {} + + // This template type conversion operator allows Return(x) to be + // used in ANY function that returns x's type. + template + operator Action() const { + // Assert statement belongs here because this is the best place to verify + // conditions on F. It produces the clearest error messages + // in most compilers. + // Impl really belongs in this scope as a local class but can't + // because MSVC produces duplicate symbols in different translation units + // in this case. Until MS fixes that bug we put Impl into the class scope + // and put the typedef both here (for use in assert statement) and + // in the Impl class. But both definitions must be the same. + typedef typename Function::Result Result; + GTEST_COMPILE_ASSERT_( + !is_reference::value, + use_ReturnRef_instead_of_Return_to_return_a_reference); + return Action(new Impl(value_)); + } + + private: + // Implements the Return(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + // The implicit cast is necessary when Result has more than one + // single-argument constructor (e.g. Result is std::vector) and R + // has a type conversion operator template. In that case, value_(value) + // won't compile as the compiler doesn't known which constructor of + // Result to call. ImplicitCast_ forces the compiler to convert R to + // Result without considering explicit constructors, thus resolving the + // ambiguity. value_ is then initialized using its copy constructor. + explicit Impl(const linked_ptr& value) + : value_before_cast_(*value), + value_(ImplicitCast_(value_before_cast_)) {} + + virtual Result Perform(const ArgumentTuple&) { return value_; } + + private: + GTEST_COMPILE_ASSERT_(!is_reference::value, + Result_cannot_be_a_reference_type); + // We save the value before casting just in case it is being cast to a + // wrapper type. + R value_before_cast_; + Result value_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl); + }; + + // Partially specialize for ByMoveWrapper. This version of ReturnAction will + // move its contents instead. + template + class Impl, F> : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const linked_ptr& wrapper) + : performed_(false), wrapper_(wrapper) {} + + virtual Result Perform(const ArgumentTuple&) { + GTEST_CHECK_(!performed_) + << "A ByMove() action should only be performed once."; + performed_ = true; + return internal::move(wrapper_->payload); + } + + private: + bool performed_; + const linked_ptr wrapper_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const linked_ptr value_; + + GTEST_DISALLOW_ASSIGN_(ReturnAction); +}; + +// Implements the ReturnNull() action. +class ReturnNullAction { + public: + // Allows ReturnNull() to be used in any pointer-returning function. In C++11 + // this is enforced by returning nullptr, and in non-C++11 by asserting a + // pointer type on compile time. + template + static Result Perform(const ArgumentTuple&) { +#if GTEST_LANG_CXX11 + return nullptr; +#else + GTEST_COMPILE_ASSERT_(internal::is_pointer::value, + ReturnNull_can_be_used_to_return_a_pointer_only); + return NULL; +#endif // GTEST_LANG_CXX11 + } +}; + +// Implements the Return() action. +class ReturnVoidAction { + public: + // Allows Return() to be used in any void-returning function. + template + static void Perform(const ArgumentTuple&) { + CompileAssertTypesEqual(); + } +}; + +// Implements the polymorphic ReturnRef(x) action, which can be used +// in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefAction { + public: + // Constructs a ReturnRefAction object from the reference to be returned. + explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT + + // This template type conversion operator allows ReturnRef(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRef(x) when Return(x) + // should be used, and generates some helpful error message. + GTEST_COMPILE_ASSERT_(internal::is_reference::value, + use_Return_instead_of_ReturnRef_to_return_a_value); + return Action(new Impl(ref_)); + } + + private: + // Implements the ReturnRef(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(T& ref) : ref_(ref) {} // NOLINT + + virtual Result Perform(const ArgumentTuple&) { + return ref_; + } + + private: + T& ref_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + T& ref_; + + GTEST_DISALLOW_ASSIGN_(ReturnRefAction); +}; + +// Implements the polymorphic ReturnRefOfCopy(x) action, which can be +// used in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefOfCopyAction { + public: + // Constructs a ReturnRefOfCopyAction object from the reference to + // be returned. + explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT + + // This template type conversion operator allows ReturnRefOfCopy(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRefOfCopy(x) when Return(x) + // should be used, and generates some helpful error message. + GTEST_COMPILE_ASSERT_( + internal::is_reference::value, + use_Return_instead_of_ReturnRefOfCopy_to_return_a_value); + return Action(new Impl(value_)); + } + + private: + // Implements the ReturnRefOfCopy(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const T& value) : value_(value) {} // NOLINT + + virtual Result Perform(const ArgumentTuple&) { + return value_; + } + + private: + T value_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const T value_; + + GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction); +}; + +// Implements the polymorphic DoDefault() action. +class DoDefaultAction { + public: + // This template type conversion operator allows DoDefault() to be + // used in any function. + template + operator Action() const { return Action(NULL); } +}; + +// Implements the Assign action to set a given pointer referent to a +// particular value. +template +class AssignAction { + public: + AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} + + template + void Perform(const ArgumentTuple& /* args */) const { + *ptr_ = value_; + } + + private: + T1* const ptr_; + const T2 value_; + + GTEST_DISALLOW_ASSIGN_(AssignAction); +}; + +#if !GTEST_OS_WINDOWS_MOBILE + +// Implements the SetErrnoAndReturn action to simulate return from +// various system calls and libc functions. +template +class SetErrnoAndReturnAction { + public: + SetErrnoAndReturnAction(int errno_value, T result) + : errno_(errno_value), + result_(result) {} + template + Result Perform(const ArgumentTuple& /* args */) const { + errno = errno_; + return result_; + } + + private: + const int errno_; + const T result_; + + GTEST_DISALLOW_ASSIGN_(SetErrnoAndReturnAction); +}; + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Implements the SetArgumentPointee(x) action for any function +// whose N-th argument (0-based) is a pointer to x's type. The +// template parameter kIsProto is true iff type A is ProtocolMessage, +// proto2::Message, or a sub-class of those. +template +class SetArgumentPointeeAction { + public: + // Constructs an action that sets the variable pointed to by the + // N-th function argument to 'value'. + explicit SetArgumentPointeeAction(const A& value) : value_(value) {} + + template + void Perform(const ArgumentTuple& args) const { + CompileAssertTypesEqual(); + *::testing::get(args) = value_; + } + + private: + const A value_; + + GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); +}; + +template +class SetArgumentPointeeAction { + public: + // Constructs an action that sets the variable pointed to by the + // N-th function argument to 'proto'. Both ProtocolMessage and + // proto2::Message have the CopyFrom() method, so the same + // implementation works for both. + explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) { + proto_->CopyFrom(proto); + } + + template + void Perform(const ArgumentTuple& args) const { + CompileAssertTypesEqual(); + ::testing::get(args)->CopyFrom(*proto_); + } + + private: + const internal::linked_ptr proto_; + + GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); +}; + +// Implements the InvokeWithoutArgs(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. InvokeWithoutArgs(f) can be used as an +// Action as long as f's type is compatible with F (i.e. f can be +// assigned to a tr1::function). +template +class InvokeWithoutArgsAction { + public: + // The c'tor makes a copy of function_impl (either a function + // pointer or a functor). + explicit InvokeWithoutArgsAction(FunctionImpl function_impl) + : function_impl_(function_impl) {} + + // Allows InvokeWithoutArgs(f) to be used as any action whose type is + // compatible with f. + template + Result Perform(const ArgumentTuple&) { return function_impl_(); } + + private: + FunctionImpl function_impl_; + + GTEST_DISALLOW_ASSIGN_(InvokeWithoutArgsAction); +}; + +// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. +template +class InvokeMethodWithoutArgsAction { + public: + InvokeMethodWithoutArgsAction(Class* obj_ptr, MethodPtr method_ptr) + : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} + + template + Result Perform(const ArgumentTuple&) const { + return (obj_ptr_->*method_ptr_)(); + } + + private: + Class* const obj_ptr_; + const MethodPtr method_ptr_; + + GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction); +}; + +// Implements the IgnoreResult(action) action. +template +class IgnoreResultAction { + public: + explicit IgnoreResultAction(const A& action) : action_(action) {} + + template + operator Action() const { + // Assert statement belongs here because this is the best place to verify + // conditions on F. It produces the clearest error messages + // in most compilers. + // Impl really belongs in this scope as a local class but can't + // because MSVC produces duplicate symbols in different translation units + // in this case. Until MS fixes that bug we put Impl into the class scope + // and put the typedef both here (for use in assert statement) and + // in the Impl class. But both definitions must be the same. + typedef typename internal::Function::Result Result; + + // Asserts at compile time that F returns void. + CompileAssertTypesEqual(); + + return Action(new Impl(action_)); + } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const A& action) : action_(action) {} + + virtual void Perform(const ArgumentTuple& args) { + // Performs the action and ignores its result. + action_.Perform(args); + } + + private: + // Type OriginalFunction is the same as F except that its return + // type is IgnoredValue. + typedef typename internal::Function::MakeResultIgnoredValue + OriginalFunction; + + const Action action_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const A action_; + + GTEST_DISALLOW_ASSIGN_(IgnoreResultAction); +}; + +// A ReferenceWrapper object represents a reference to type T, +// which can be either const or not. It can be explicitly converted +// from, and implicitly converted to, a T&. Unlike a reference, +// ReferenceWrapper can be copied and can survive template type +// inference. This is used to support by-reference arguments in the +// InvokeArgument(...) action. The idea was from "reference +// wrappers" in tr1, which we don't have in our source tree yet. +template +class ReferenceWrapper { + public: + // Constructs a ReferenceWrapper object from a T&. + explicit ReferenceWrapper(T& l_value) : pointer_(&l_value) {} // NOLINT + + // Allows a ReferenceWrapper object to be implicitly converted to + // a T&. + operator T&() const { return *pointer_; } + private: + T* pointer_; +}; + +// Allows the expression ByRef(x) to be printed as a reference to x. +template +void PrintTo(const ReferenceWrapper& ref, ::std::ostream* os) { + T& value = ref; + UniversalPrinter::Print(value, os); +} + +// Does two actions sequentially. Used for implementing the DoAll(a1, +// a2, ...) action. +template +class DoBothAction { + public: + DoBothAction(Action1 action1, Action2 action2) + : action1_(action1), action2_(action2) {} + + // This template type conversion operator allows DoAll(a1, ..., a_n) + // to be used in ANY function of compatible type. + template + operator Action() const { + return Action(new Impl(action1_, action2_)); + } + + private: + // Implements the DoAll(...) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::MakeResultVoid VoidResult; + + Impl(const Action& action1, const Action& action2) + : action1_(action1), action2_(action2) {} + + virtual Result Perform(const ArgumentTuple& args) { + action1_.Perform(args); + return action2_.Perform(args); + } + + private: + const Action action1_; + const Action action2_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + Action1 action1_; + Action2 action2_; + + GTEST_DISALLOW_ASSIGN_(DoBothAction); +}; + +} // namespace internal + +// An Unused object can be implicitly constructed from ANY value. +// This is handy when defining actions that ignore some or all of the +// mock function arguments. For example, given +// +// MOCK_METHOD3(Foo, double(const string& label, double x, double y)); +// MOCK_METHOD3(Bar, double(int index, double x, double y)); +// +// instead of +// +// double DistanceToOriginWithLabel(const string& label, double x, double y) { +// return sqrt(x*x + y*y); +// } +// double DistanceToOriginWithIndex(int index, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXEPCT_CALL(mock, Foo("abc", _, _)) +// .WillOnce(Invoke(DistanceToOriginWithLabel)); +// EXEPCT_CALL(mock, Bar(5, _, _)) +// .WillOnce(Invoke(DistanceToOriginWithIndex)); +// +// you could write +// +// // We can declare any uninteresting argument as Unused. +// double DistanceToOrigin(Unused, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXEPCT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); +// EXEPCT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); +typedef internal::IgnoredValue Unused; + +// This constructor allows us to turn an Action object into an +// Action, as long as To's arguments can be implicitly converted +// to From's and From's return type cann be implicitly converted to +// To's. +template +template +Action::Action(const Action& from) + : impl_(new internal::ActionAdaptor(from)) {} + +// Creates an action that returns 'value'. 'value' is passed by value +// instead of const reference - otherwise Return("string literal") +// will trigger a compiler error about using array as initializer. +template +internal::ReturnAction Return(R value) { + return internal::ReturnAction(internal::move(value)); +} + +// Creates an action that returns NULL. +inline PolymorphicAction ReturnNull() { + return MakePolymorphicAction(internal::ReturnNullAction()); +} + +// Creates an action that returns from a void function. +inline PolymorphicAction Return() { + return MakePolymorphicAction(internal::ReturnVoidAction()); +} + +// Creates an action that returns the reference to a variable. +template +inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT + return internal::ReturnRefAction(x); +} + +// Creates an action that returns the reference to a copy of the +// argument. The copy is created when the action is constructed and +// lives as long as the action. +template +inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { + return internal::ReturnRefOfCopyAction(x); +} + +// Modifies the parent action (a Return() action) to perform a move of the +// argument instead of a copy. +// Return(ByMove()) actions can only be executed once and will assert this +// invariant. +template +internal::ByMoveWrapper ByMove(R x) { + return internal::ByMoveWrapper(internal::move(x)); +} + +// Creates an action that does the default action for the give mock function. +inline internal::DoDefaultAction DoDefault() { + return internal::DoDefaultAction(); +} + +// Creates an action that sets the variable pointed by the N-th +// (0-based) function argument to 'value'. +template +PolymorphicAction< + internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value> > +SetArgPointee(const T& x) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value>(x)); +} + +#if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN) +// This overload allows SetArgPointee() to accept a string literal. +// GCC prior to the version 4.0 and Symbian C++ compiler cannot distinguish +// this overload from the templated version and emit a compile error. +template +PolymorphicAction< + internal::SetArgumentPointeeAction > +SetArgPointee(const char* p) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, const char*, false>(p)); +} + +template +PolymorphicAction< + internal::SetArgumentPointeeAction > +SetArgPointee(const wchar_t* p) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, const wchar_t*, false>(p)); +} +#endif + +// The following version is DEPRECATED. +template +PolymorphicAction< + internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value> > +SetArgumentPointee(const T& x) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value>(x)); +} + +// Creates an action that sets a pointer referent to a given value. +template +PolymorphicAction > Assign(T1* ptr, T2 val) { + return MakePolymorphicAction(internal::AssignAction(ptr, val)); +} + +#if !GTEST_OS_WINDOWS_MOBILE + +// Creates an action that sets errno and returns the appropriate error. +template +PolymorphicAction > +SetErrnoAndReturn(int errval, T result) { + return MakePolymorphicAction( + internal::SetErrnoAndReturnAction(errval, result)); +} + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Various overloads for InvokeWithoutArgs(). + +// Creates an action that invokes 'function_impl' with no argument. +template +PolymorphicAction > +InvokeWithoutArgs(FunctionImpl function_impl) { + return MakePolymorphicAction( + internal::InvokeWithoutArgsAction(function_impl)); +} + +// Creates an action that invokes the given method on the given object +// with no argument. +template +PolymorphicAction > +InvokeWithoutArgs(Class* obj_ptr, MethodPtr method_ptr) { + return MakePolymorphicAction( + internal::InvokeMethodWithoutArgsAction( + obj_ptr, method_ptr)); +} + +// Creates an action that performs an_action and throws away its +// result. In other words, it changes the return type of an_action to +// void. an_action MUST NOT return void, or the code won't compile. +template +inline internal::IgnoreResultAction
IgnoreResult(const A& an_action) { + return internal::IgnoreResultAction(an_action); +} + +// Creates a reference wrapper for the given L-value. If necessary, +// you can explicitly specify the type of the reference. For example, +// suppose 'derived' is an object of type Derived, ByRef(derived) +// would wrap a Derived&. If you want to wrap a const Base& instead, +// where Base is a base class of Derived, just write: +// +// ByRef(derived) +template +inline internal::ReferenceWrapper ByRef(T& l_value) { // NOLINT + return internal::ReferenceWrapper(l_value); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/googlemock/include/gmock/gmock-cardinalities.h b/googlemock/include/gmock/gmock-cardinalities.h new file mode 100644 index 0000000..fc315f9 --- /dev/null +++ b/googlemock/include/gmock/gmock-cardinalities.h @@ -0,0 +1,147 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used cardinalities. More +// cardinalities can be defined by the user implementing the +// CardinalityInterface interface if necessary. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ + +#include +#include // NOLINT +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" + +namespace testing { + +// To implement a cardinality Foo, define: +// 1. a class FooCardinality that implements the +// CardinalityInterface interface, and +// 2. a factory function that creates a Cardinality object from a +// const FooCardinality*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Cardinality objects can now be copied like plain values. + +// The implementation of a cardinality. +class CardinalityInterface { + public: + virtual ~CardinalityInterface() {} + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + virtual int ConservativeLowerBound() const { return 0; } + virtual int ConservativeUpperBound() const { return INT_MAX; } + + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; + +// A Cardinality is a copyable and IMMUTABLE (except by assignment) +// object that specifies how many times a mock function is expected to +// be called. The implementation of Cardinality is just a linked_ptr +// to const CardinalityInterface, so copying is fairly cheap. +// Don't inherit from Cardinality! +class GTEST_API_ Cardinality { + public: + // Constructs a null cardinality. Needed for storing Cardinality + // objects in STL containers. + Cardinality() {} + + // Constructs a Cardinality from its implementation. + explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } + int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } + + // Returns true iff call_count calls will satisfy this cardinality. + bool IsSatisfiedByCallCount(int call_count) const { + return impl_->IsSatisfiedByCallCount(call_count); + } + + // Returns true iff call_count calls will saturate this cardinality. + bool IsSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count); + } + + // Returns true iff call_count calls will over-saturate this + // cardinality, i.e. exceed the maximum number of allowed calls. + bool IsOverSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count) && + !impl_->IsSatisfiedByCallCount(call_count); + } + + // Describes self to an ostream + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the given actual call count to an ostream. + static void DescribeActualCallCountTo(int actual_call_count, + ::std::ostream* os); + + private: + internal::linked_ptr impl_; +}; + +// Creates a cardinality that allows at least n calls. +GTEST_API_ Cardinality AtLeast(int n); + +// Creates a cardinality that allows at most n calls. +GTEST_API_ Cardinality AtMost(int n); + +// Creates a cardinality that allows any number of calls. +GTEST_API_ Cardinality AnyNumber(); + +// Creates a cardinality that allows between min and max calls. +GTEST_API_ Cardinality Between(int min, int max); + +// Creates a cardinality that allows exactly n calls. +GTEST_API_ Cardinality Exactly(int n); + +// Creates a cardinality from its implementation. +inline Cardinality MakeCardinality(const CardinalityInterface* c) { + return Cardinality(c); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ diff --git a/googlemock/include/gmock/gmock-generated-actions.h b/googlemock/include/gmock/gmock-generated-actions.h new file mode 100644 index 0000000..b5a889c --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-actions.h @@ -0,0 +1,2377 @@ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used variadic actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ + +#include "gmock/gmock-actions.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { +namespace internal { + +// InvokeHelper knows how to unpack an N-tuple and invoke an N-ary +// function or method with the unpacked values, where F is a function +// type that takes N arguments. +template +class InvokeHelper; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple<>&) { + return function(); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple<>&) { + return (obj_ptr->*method_ptr)(); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args), get<4>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args), get<4>(args), get<5>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args), get<4>(args), get<5>(args), + get<6>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args), + get<7>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args), get<4>(args), get<5>(args), + get<6>(args), get<7>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args), + get<7>(args), get<8>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args), get<4>(args), get<5>(args), + get<6>(args), get<7>(args), get<8>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple& args) { + return function(get<0>(args), get<1>(args), get<2>(args), + get<3>(args), get<4>(args), get<5>(args), get<6>(args), + get<7>(args), get<8>(args), get<9>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple& args) { + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), + get<2>(args), get<3>(args), get<4>(args), get<5>(args), + get<6>(args), get<7>(args), get<8>(args), get<9>(args)); + } +}; + +// An INTERNAL macro for extracting the type of a tuple field. It's +// subject to change without notice - DO NOT USE IN USER CODE! +#define GMOCK_FIELD_(Tuple, N) \ + typename ::testing::tuple_element::type + +// SelectArgs::type is the +// type of an n-ary function whose i-th (1-based) argument type is the +// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple +// type, and whose return type is Result. For example, +// SelectArgs, 0, 3>::type +// is int(bool, long). +// +// SelectArgs::Select(args) +// returns the selected fields (k1, k2, ..., k_n) of args as a tuple. +// For example, +// SelectArgs, 2, 0>::Select( +// ::testing::make_tuple(true, 'a', 2.5)) +// returns tuple (2.5, true). +// +// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be +// in the range [0, 10]. Duplicates are allowed and they don't have +// to be in an ascending or descending order. + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), + GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9), + GMOCK_FIELD_(ArgumentTuple, k10)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args), + get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& /* args */) { + return SelectedArgs(); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), + GMOCK_FIELD_(ArgumentTuple, k8)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args), + get(args)); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), + GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), + GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), + GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs(get(args), get(args), get(args), + get(args), get(args), get(args), get(args), + get(args), get(args)); + } +}; + +#undef GMOCK_FIELD_ + +// Implements the WithArgs action. +template +class WithArgsAction { + public: + explicit WithArgsAction(const InnerAction& action) : action_(action) {} + + template + operator Action() const { return MakeAction(new Impl(action_)); } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const InnerAction& action) : action_(action) {} + + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + + private: + typedef typename SelectArgs::type InnerFunctionType; + + Action action_; + }; + + const InnerAction action_; + + GTEST_DISALLOW_ASSIGN_(WithArgsAction); +}; + +// A macro from the ACTION* family (defined later in this file) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// A helper class needed for implementing the ACTION* macros. +template +class ActionHelper { + public: + static Result Perform(Impl* impl, const ::testing::tuple<>& args) { + return impl->template gmock_PerformImpl<>(args, ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), get<2>(args), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), get<2>(args), get<3>(args), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, + get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, + get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), + get<5>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, + get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), + get<5>(args), get<6>(args), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), ExcessiveArg(), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), + ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::testing::tuple& args) { + return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), + get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), + get<9>(args)); + } +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. C++ doesn't support default arguments for +// function templates, so we have to overload it. +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +template +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. +template +inline internal::DoBothAction +DoAll(Action1 a1, Action2 a2) { + return internal::DoBothAction(a1, a2); +} + +template +inline internal::DoBothAction > +DoAll(Action1 a1, Action2 a2, Action3 a3) { + return DoAll(a1, DoAll(a2, a3)); +} + +template +inline internal::DoBothAction > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4) { + return DoAll(a1, DoAll(a2, a3, a4)); +} + +template +inline internal::DoBothAction > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5) { + return DoAll(a1, DoAll(a2, a3, a4, a5)); +} + +template +inline internal::DoBothAction > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6)); +} + +template +inline internal::DoBothAction > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7)); +} + +template +inline internal::DoBothAction > > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7, Action8 a8) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8)); +} + +template +inline internal::DoBothAction > > > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7, Action8 a8, Action9 a9) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template +inline internal::DoBothAction > > > > > > > > +DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, + Action7 a7, Action8 a8, Action9 a9, Action10 a10) { + return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9, a10)); +} + +} // namespace testing + +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using ACTION*() inside +// a function. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +// An internal macro needed for implementing ACTION*(). +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ + const args_type& args GTEST_ATTRIBUTE_UNUSED_, \ + arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \ + arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \ + arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \ + arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \ + arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \ + arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \ + arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \ + arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \ + arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \ + arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_ + +// Sometimes you want to give an action explicit template parameters +// that cannot be inferred from its value parameters. ACTION() and +// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that +// and can be viewed as an extension to ACTION() and ACTION_P*(). +// +// The syntax: +// +// ACTION_TEMPLATE(ActionName, +// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), +// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } +// +// defines an action template that takes m explicit template +// parameters and n value parameters. name_i is the name of the i-th +// template parameter, and kind_i specifies whether it's a typename, +// an integral constant, or a template. p_i is the name of the i-th +// value parameter. +// +// Example: +// +// // DuplicateArg(output) converts the k-th argument of the mock +// // function to type T and copies it to *output. +// ACTION_TEMPLATE(DuplicateArg, +// HAS_2_TEMPLATE_PARAMS(int, k, typename, T), +// AND_1_VALUE_PARAMS(output)) { +// *output = T(::testing::get(args)); +// } +// ... +// int n; +// EXPECT_CALL(mock, Foo(_, _)) +// .WillOnce(DuplicateArg<1, unsigned char>(&n)); +// +// To create an instance of an action template, write: +// +// ActionName(v1, ..., v_n) +// +// where the ts are the template arguments and the vs are the value +// arguments. The value argument types are inferred by the compiler. +// If you want to explicitly specify the value argument types, you can +// provide additional template arguments: +// +// ActionName(v1, ..., v_n) +// +// where u_i is the desired type of v_i. +// +// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the +// number of value parameters, but not on the number of template +// parameters. Without the restriction, the meaning of the following +// is unclear: +// +// OverloadedAction(x); +// +// Are we using a single-template-parameter action where 'bool' refers +// to the type of x, or are we using a two-template-parameter action +// where the compiler is asked to infer the type of x? +// +// Implementation notes: +// +// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and +// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for +// implementing ACTION_TEMPLATE. The main trick we use is to create +// new macro invocations when expanding a macro. For example, we have +// +// #define ACTION_TEMPLATE(name, template_params, value_params) +// ... GMOCK_INTERNAL_DECL_##template_params ... +// +// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...) +// to expand to +// +// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ... +// +// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the +// preprocessor will continue to expand it to +// +// ... typename T ... +// +// This technique conforms to the C++ standard and is portable. It +// allows us to implement action templates using O(N) code, where N is +// the maximum number of template/value parameters supported. Without +// using it, we'd have to devote O(N^2) amount of code to implement all +// combinations of m and n. + +// Declares the template parameters. +#define GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(kind0, name0) kind0 name0 +#define GMOCK_INTERNAL_DECL_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1) kind0 name0, kind1 name1 +#define GMOCK_INTERNAL_DECL_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2) kind0 name0, kind1 name1, kind2 name2 +#define GMOCK_INTERNAL_DECL_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3) kind0 name0, kind1 name1, kind2 name2, \ + kind3 name3 +#define GMOCK_INTERNAL_DECL_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4) kind0 name0, kind1 name1, \ + kind2 name2, kind3 name3, kind4 name4 +#define GMOCK_INTERNAL_DECL_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5) kind0 name0, \ + kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5 +#define GMOCK_INTERNAL_DECL_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6) kind0 name0, kind1 name1, kind2 name2, kind3 name3, kind4 name4, \ + kind5 name5, kind6 name6 +#define GMOCK_INTERNAL_DECL_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7) kind0 name0, kind1 name1, kind2 name2, kind3 name3, \ + kind4 name4, kind5 name5, kind6 name6, kind7 name7 +#define GMOCK_INTERNAL_DECL_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7, kind8, name8) kind0 name0, kind1 name1, kind2 name2, \ + kind3 name3, kind4 name4, kind5 name5, kind6 name6, kind7 name7, \ + kind8 name8 +#define GMOCK_INTERNAL_DECL_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6, kind7, name7, kind8, name8, kind9, name9) kind0 name0, \ + kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5, \ + kind6 name6, kind7 name7, kind8 name8, kind9 name9 + +// Lists the template parameters. +#define GMOCK_INTERNAL_LIST_HAS_1_TEMPLATE_PARAMS(kind0, name0) name0 +#define GMOCK_INTERNAL_LIST_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1) name0, name1 +#define GMOCK_INTERNAL_LIST_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2) name0, name1, name2 +#define GMOCK_INTERNAL_LIST_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3) name0, name1, name2, name3 +#define GMOCK_INTERNAL_LIST_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4) name0, name1, name2, name3, \ + name4 +#define GMOCK_INTERNAL_LIST_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5) name0, name1, \ + name2, name3, name4, name5 +#define GMOCK_INTERNAL_LIST_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6) name0, name1, name2, name3, name4, name5, name6 +#define GMOCK_INTERNAL_LIST_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7) name0, name1, name2, name3, name4, name5, name6, name7 +#define GMOCK_INTERNAL_LIST_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ + kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ + kind7, name7, kind8, name8) name0, name1, name2, name3, name4, name5, \ + name6, name7, name8 +#define GMOCK_INTERNAL_LIST_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ + name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ + name6, kind7, name7, kind8, name8, kind9, name9) name0, name1, name2, \ + name3, name4, name5, name6, name7, name8, name9 + +// Declares the types of value parameters. +#define GMOCK_INTERNAL_DECL_TYPE_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_DECL_TYPE_AND_1_VALUE_PARAMS(p0) , typename p0##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_2_VALUE_PARAMS(p0, p1) , \ + typename p0##_type, typename p1##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , \ + typename p0##_type, typename p1##_type, typename p2##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ + typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ + typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ + typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) , typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type, \ + typename p6##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7) , typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type, \ + typename p6##_type, typename p7##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8) , typename p0##_type, typename p1##_type, typename p2##_type, \ + typename p3##_type, typename p4##_type, typename p5##_type, \ + typename p6##_type, typename p7##_type, typename p8##_type +#define GMOCK_INTERNAL_DECL_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9) , typename p0##_type, typename p1##_type, \ + typename p2##_type, typename p3##_type, typename p4##_type, \ + typename p5##_type, typename p6##_type, typename p7##_type, \ + typename p8##_type, typename p9##_type + +// Initializes the value parameters. +#define GMOCK_INTERNAL_INIT_AND_0_VALUE_PARAMS()\ + () +#define GMOCK_INTERNAL_INIT_AND_1_VALUE_PARAMS(p0)\ + (p0##_type gmock_p0) : p0(gmock_p0) +#define GMOCK_INTERNAL_INIT_AND_2_VALUE_PARAMS(p0, p1)\ + (p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), p1(gmock_p1) +#define GMOCK_INTERNAL_INIT_AND_3_VALUE_PARAMS(p0, p1, p2)\ + (p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) +#define GMOCK_INTERNAL_INIT_AND_4_VALUE_PARAMS(p0, p1, p2, p3)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3) +#define GMOCK_INTERNAL_INIT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) +#define GMOCK_INTERNAL_INIT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) +#define GMOCK_INTERNAL_INIT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) +#define GMOCK_INTERNAL_INIT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) +#define GMOCK_INTERNAL_INIT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) +#define GMOCK_INTERNAL_INIT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9)\ + (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8), p9(gmock_p9) + +// Declares the fields for storing the value parameters. +#define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0; +#define GMOCK_INTERNAL_DEFN_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0; \ + p1##_type p1; +#define GMOCK_INTERNAL_DEFN_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0; \ + p1##_type p1; p2##_type p2; +#define GMOCK_INTERNAL_DEFN_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0; \ + p1##_type p1; p2##_type p2; p3##_type p3; +#define GMOCK_INTERNAL_DEFN_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ + p4) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; +#define GMOCK_INTERNAL_DEFN_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ + p5) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ + p5##_type p5; +#define GMOCK_INTERNAL_DEFN_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ + p5##_type p5; p6##_type p6; +#define GMOCK_INTERNAL_DEFN_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ + p5##_type p5; p6##_type p6; p7##_type p7; +#define GMOCK_INTERNAL_DEFN_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ + p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; +#define GMOCK_INTERNAL_DEFN_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ + p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; \ + p9##_type p9; + +// Lists the value parameters. +#define GMOCK_INTERNAL_LIST_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_LIST_AND_1_VALUE_PARAMS(p0) p0 +#define GMOCK_INTERNAL_LIST_AND_2_VALUE_PARAMS(p0, p1) p0, p1 +#define GMOCK_INTERNAL_LIST_AND_3_VALUE_PARAMS(p0, p1, p2) p0, p1, p2 +#define GMOCK_INTERNAL_LIST_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0, p1, p2, p3 +#define GMOCK_INTERNAL_LIST_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) p0, p1, \ + p2, p3, p4 +#define GMOCK_INTERNAL_LIST_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) p0, \ + p1, p2, p3, p4, p5 +#define GMOCK_INTERNAL_LIST_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) p0, p1, p2, p3, p4, p5, p6 +#define GMOCK_INTERNAL_LIST_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) p0, p1, p2, p3, p4, p5, p6, p7 +#define GMOCK_INTERNAL_LIST_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) p0, p1, p2, p3, p4, p5, p6, p7, p8 +#define GMOCK_INTERNAL_LIST_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 + +// Lists the value parameter types. +#define GMOCK_INTERNAL_LIST_TYPE_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_LIST_TYPE_AND_1_VALUE_PARAMS(p0) , p0##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_2_VALUE_PARAMS(p0, p1) , p0##_type, \ + p1##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , p0##_type, \ + p1##_type, p2##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ + p0##_type, p1##_type, p2##_type, p3##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ + p0##_type, p1##_type, p2##_type, p3##_type, p4##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ + p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, \ + p6##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ + p5##_type, p6##_type, p7##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ + p5##_type, p6##_type, p7##_type, p8##_type +#define GMOCK_INTERNAL_LIST_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ + p5##_type, p6##_type, p7##_type, p8##_type, p9##_type + +// Declares the value parameters. +#define GMOCK_INTERNAL_DECL_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_DECL_AND_1_VALUE_PARAMS(p0) p0##_type p0 +#define GMOCK_INTERNAL_DECL_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0, \ + p1##_type p1 +#define GMOCK_INTERNAL_DECL_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0, \ + p1##_type p1, p2##_type p2 +#define GMOCK_INTERNAL_DECL_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3 +#define GMOCK_INTERNAL_DECL_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ + p4) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4 +#define GMOCK_INTERNAL_DECL_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ + p5) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ + p5##_type p5 +#define GMOCK_INTERNAL_DECL_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ + p6) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ + p5##_type p5, p6##_type p6 +#define GMOCK_INTERNAL_DECL_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ + p5##_type p5, p6##_type p6, p7##_type p7 +#define GMOCK_INTERNAL_DECL_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8 +#define GMOCK_INTERNAL_DECL_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9 + +// The suffix of the class template implementing the action template. +#define GMOCK_INTERNAL_COUNT_AND_0_VALUE_PARAMS() +#define GMOCK_INTERNAL_COUNT_AND_1_VALUE_PARAMS(p0) P +#define GMOCK_INTERNAL_COUNT_AND_2_VALUE_PARAMS(p0, p1) P2 +#define GMOCK_INTERNAL_COUNT_AND_3_VALUE_PARAMS(p0, p1, p2) P3 +#define GMOCK_INTERNAL_COUNT_AND_4_VALUE_PARAMS(p0, p1, p2, p3) P4 +#define GMOCK_INTERNAL_COUNT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) P5 +#define GMOCK_INTERNAL_COUNT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) P6 +#define GMOCK_INTERNAL_COUNT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6) P7 +#define GMOCK_INTERNAL_COUNT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7) P8 +#define GMOCK_INTERNAL_COUNT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8) P9 +#define GMOCK_INTERNAL_COUNT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ + p7, p8, p9) P10 + +// The name of the class template implementing the action template. +#define GMOCK_ACTION_CLASS_(name, value_params)\ + GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) + +#define ACTION_TEMPLATE(name, template_params, value_params)\ + template \ + class GMOCK_ACTION_CLASS_(name, value_params) {\ + public:\ + explicit GMOCK_ACTION_CLASS_(name, value_params)\ + GMOCK_INTERNAL_INIT_##value_params {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(\ + new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ + }\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ + };\ + template \ + inline GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ + GMOCK_INTERNAL_DECL_##value_params) {\ + return GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params>(\ + GMOCK_INTERNAL_LIST_##value_params);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::\ + gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION(name)\ + class name##Action {\ + public:\ + name##Action() {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl() {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl());\ + }\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##Action);\ + };\ + inline name##Action name() {\ + return name##Action();\ + }\ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##Action::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P(name, p0)\ + template \ + class name##ActionP {\ + public:\ + explicit name##ActionP(p0##_type gmock_p0) : p0(gmock_p0) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0));\ + }\ + p0##_type p0;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP);\ + };\ + template \ + inline name##ActionP name(p0##_type p0) {\ + return name##ActionP(p0);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P2(name, p0, p1)\ + template \ + class name##ActionP2 {\ + public:\ + name##ActionP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP2);\ + };\ + template \ + inline name##ActionP2 name(p0##_type p0, \ + p1##_type p1) {\ + return name##ActionP2(p0, p1);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP2::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P3(name, p0, p1, p2)\ + template \ + class name##ActionP3 {\ + public:\ + name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP3);\ + };\ + template \ + inline name##ActionP3 name(p0##_type p0, \ + p1##_type p1, p2##_type p2) {\ + return name##ActionP3(p0, p1, p2);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP3::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P4(name, p0, p1, p2, p3)\ + template \ + class name##ActionP4 {\ + public:\ + name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP4);\ + };\ + template \ + inline name##ActionP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3) {\ + return name##ActionP4(p0, p1, \ + p2, p3);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP4::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P5(name, p0, p1, p2, p3, p4)\ + template \ + class name##ActionP5 {\ + public:\ + name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, \ + p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \ + p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP5);\ + };\ + template \ + inline name##ActionP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4) {\ + return name##ActionP5(p0, p1, p2, p3, p4);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP5::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P6(name, p0, p1, p2, p3, p4, p5)\ + template \ + class name##ActionP6 {\ + public:\ + name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP6);\ + };\ + template \ + inline name##ActionP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3, p4##_type p4, p5##_type p5) {\ + return name##ActionP6(p0, p1, p2, p3, p4, p5);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP6::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\ + template \ + class name##ActionP7 {\ + public:\ + name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ + p6(gmock_p6) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP7);\ + };\ + template \ + inline name##ActionP7 name(p0##_type p0, p1##_type p1, \ + p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6) {\ + return name##ActionP7(p0, p1, p2, p3, p4, p5, p6);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP7::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P8(name, p0, p1, p2, p3, p4, p5, p6, p7)\ + template \ + class name##ActionP8 {\ + public:\ + name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, \ + p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \ + p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \ + p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP8);\ + };\ + template \ + inline name##ActionP8 name(p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6, p7##_type p7) {\ + return name##ActionP8(p0, p1, p2, p3, p4, p5, \ + p6, p7);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP8::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8)\ + template \ + class name##ActionP9 {\ + public:\ + name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP9);\ + };\ + template \ + inline name##ActionP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ + p8##_type p8) {\ + return name##ActionP9(p0, p1, p2, \ + p3, p4, p5, p6, p7, p8);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP9::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)\ + template \ + class name##ActionP10 {\ + public:\ + name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template \ + return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ + arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ + arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ + arg9_type arg9) const;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9));\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP10);\ + };\ + template \ + inline name##ActionP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9) {\ + return name##ActionP10(p0, \ + p1, p2, p3, p4, p5, p6, p7, p8, p9);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##ActionP10::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +namespace testing { + + +// The ACTION*() macros trigger warning C4100 (unreferenced formal +// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in +// the macro definition, as the warnings are generated when the macro +// is expanded and macro expansion cannot contain #pragma. Therefore +// we suppress them here. +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4100) +#endif + +// Various overloads for InvokeArgument(). +// +// The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th +// (0-based) argument, which must be a k-ary callable, of the mock +// function, with arguments a1, a2, ..., a_k. +// +// Notes: +// +// 1. The arguments are passed by value by default. If you need to +// pass an argument by reference, wrap it inside ByRef(). For +// example, +// +// InvokeArgument<1>(5, string("Hello"), ByRef(foo)) +// +// passes 5 and string("Hello") by value, and passes foo by +// reference. +// +// 2. If the callable takes an argument by reference but ByRef() is +// not used, it will receive the reference to a copy of the value, +// instead of the original value. For example, when the 0-th +// argument of the mock function takes a const string&, the action +// +// InvokeArgument<0>(string("Hello")) +// +// makes a copy of the temporary string("Hello") object and passes a +// reference of the copy, instead of the original temporary object, +// to the callable. This makes it easy for a user to define an +// InvokeArgument action from temporary values and have it performed +// later. + +namespace internal { +namespace invoke_argument { + +// Appears in InvokeArgumentAdl's argument list to help avoid +// accidental calls to user functions of the same name. +struct AdlTag {}; + +// InvokeArgumentAdl - a helper for InvokeArgument. +// The basic overloads are provided here for generic functors. +// Overloads for other custom-callables are provided in the +// internal/custom/callback-actions.h header. + +template +R InvokeArgumentAdl(AdlTag, F f) { + return f(); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1) { + return f(a1); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2) { + return f(a1, a2); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3) { + return f(a1, a2, a3); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4) { + return f(a1, a2, a3, a4); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return f(a1, a2, a3, a4, a5); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return f(a1, a2, a3, a4, a5, a6); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7) { + return f(a1, a2, a3, a4, a5, a6, a7); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8) { + return f(a1, a2, a3, a4, a5, a6, a7, a8); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8, A9 a9) { + return f(a1, a2, a3, a4, a5, a6, a7, a8, a9); +} +template +R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8, A9 a9, A10 a10) { + return f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); +} +} // namespace invoke_argument +} // namespace internal + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args)); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(p0)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_2_VALUE_PARAMS(p0, p1)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_3_VALUE_PARAMS(p0, p1, p2)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3, p4); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3, p4, p5); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3, p4, p5, p6); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8); +} + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); +} + +// Various overloads for ReturnNew(). +// +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_0_VALUE_PARAMS()) { + return new T(); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_1_VALUE_PARAMS(p0)) { + return new T(p0); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_2_VALUE_PARAMS(p0, p1)) { + return new T(p0, p1); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_3_VALUE_PARAMS(p0, p1, p2)) { + return new T(p0, p1, p2); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { + return new T(p0, p1, p2, p3); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { + return new T(p0, p1, p2, p3, p4); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { + return new T(p0, p1, p2, p3, p4, p5); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { + return new T(p0, p1, p2, p3, p4, p5, p6); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { + return new T(p0, p1, p2, p3, p4, p5, p6, p7); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { + return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8); +} + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { + return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +} // namespace testing + +// Include any custom actions added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gmock/internal/custom/gmock-generated-actions.h" + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/googlemock/include/gmock/gmock-generated-actions.h.pump b/googlemock/include/gmock/gmock-generated-actions.h.pump new file mode 100644 index 0000000..66d9f9d --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-actions.h.pump @@ -0,0 +1,794 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-actions.h. +$$ +$var n = 10 $$ The maximum arity we support. +$$}} This meta comment fixes auto-indentation in editors. +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used variadic actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ + +#include "gmock/gmock-actions.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { +namespace internal { + +// InvokeHelper knows how to unpack an N-tuple and invoke an N-ary +// function or method with the unpacked values, where F is a function +// type that takes N arguments. +template +class InvokeHelper; + + +$range i 0..n +$for i [[ +$range j 1..i +$var types = [[$for j [[, typename A$j]]]] +$var as = [[$for j, [[A$j]]]] +$var args = [[$if i==0 [[]] $else [[ args]]]] +$var gets = [[$for j, [[get<$(j - 1)>(args)]]]] +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::testing::tuple<$as>&$args) { + return function($gets); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::testing::tuple<$as>&$args) { + return (obj_ptr->*method_ptr)($gets); + } +}; + + +]] +// An INTERNAL macro for extracting the type of a tuple field. It's +// subject to change without notice - DO NOT USE IN USER CODE! +#define GMOCK_FIELD_(Tuple, N) \ + typename ::testing::tuple_element::type + +$range i 1..n + +// SelectArgs::type is the +// type of an n-ary function whose i-th (1-based) argument type is the +// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple +// type, and whose return type is Result. For example, +// SelectArgs, 0, 3>::type +// is int(bool, long). +// +// SelectArgs::Select(args) +// returns the selected fields (k1, k2, ..., k_n) of args as a tuple. +// For example, +// SelectArgs, 2, 0>::Select( +// ::testing::make_tuple(true, 'a', 2.5)) +// returns tuple (2.5, true). +// +// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be +// in the range [0, $n]. Duplicates are allowed and they don't have +// to be in an ascending or descending order. + +template +class SelectArgs { + public: + typedef Result type($for i, [[GMOCK_FIELD_(ArgumentTuple, k$i)]]); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + return SelectedArgs($for i, [[get(args)]]); + } +}; + + +$for i [[ +$range j 1..n +$range j1 1..i-1 +template +class SelectArgs { + public: + typedef Result type($for j1, [[GMOCK_FIELD_(ArgumentTuple, k$j1)]]); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& [[]] +$if i == 1 [[/* args */]] $else [[args]]) { + return SelectedArgs($for j1, [[get(args)]]); + } +}; + + +]] +#undef GMOCK_FIELD_ + +$var ks = [[$for i, [[k$i]]]] + +// Implements the WithArgs action. +template +class WithArgsAction { + public: + explicit WithArgsAction(const InnerAction& action) : action_(action) {} + + template + operator Action() const { return MakeAction(new Impl(action_)); } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const InnerAction& action) : action_(action) {} + + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + + private: + typedef typename SelectArgs::type InnerFunctionType; + + Action action_; + }; + + const InnerAction action_; + + GTEST_DISALLOW_ASSIGN_(WithArgsAction); +}; + +// A macro from the ACTION* family (defined later in this file) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// A helper class needed for implementing the ACTION* macros. +template +class ActionHelper { + public: +$range i 0..n +$for i + +[[ +$var template = [[$if i==0 [[]] $else [[ +$range j 0..i-1 + template <$for j, [[typename A$j]]> +]]]] +$range j 0..i-1 +$var As = [[$for j, [[A$j]]]] +$var as = [[$for j, [[get<$j>(args)]]]] +$range k 1..n-i +$var eas = [[$for k, [[ExcessiveArg()]]]] +$var arg_list = [[$if (i==0) | (i==n) [[$as$eas]] $else [[$as, $eas]]]] +$template + static Result Perform(Impl* impl, const ::testing::tuple<$As>& args) { + return impl->template gmock_PerformImpl<$As>(args, $arg_list); + } + +]] +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. C++ doesn't support default arguments for +// function templates, so we have to overload it. + +$range i 1..n +$for i [[ +$range j 1..i +template <$for j [[int k$j, ]]typename InnerAction> +inline internal::WithArgsAction +WithArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + + +]] +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. +$range i 2..n +$for i [[ +$range j 2..i +$var types = [[$for j, [[typename Action$j]]]] +$var Aas = [[$for j [[, Action$j a$j]]]] + +template +$range k 1..i-1 + +inline $for k [[internal::DoBothAction]] + +DoAll(Action1 a1$Aas) { +$if i==2 [[ + + return internal::DoBothAction(a1, a2); +]] $else [[ +$range j2 2..i + + return DoAll(a1, DoAll($for j2, [[a$j2]])); +]] + +} + +]] + +} // namespace testing + +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P$n to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using ACTION*() inside +// a function. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +$range i 0..n +$range k 0..n-1 + +// An internal macro needed for implementing ACTION*(). +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ + const args_type& args GTEST_ATTRIBUTE_UNUSED_ +$for k [[, \ + arg$k[[]]_type arg$k GTEST_ATTRIBUTE_UNUSED_]] + + +// Sometimes you want to give an action explicit template parameters +// that cannot be inferred from its value parameters. ACTION() and +// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that +// and can be viewed as an extension to ACTION() and ACTION_P*(). +// +// The syntax: +// +// ACTION_TEMPLATE(ActionName, +// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), +// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } +// +// defines an action template that takes m explicit template +// parameters and n value parameters. name_i is the name of the i-th +// template parameter, and kind_i specifies whether it's a typename, +// an integral constant, or a template. p_i is the name of the i-th +// value parameter. +// +// Example: +// +// // DuplicateArg(output) converts the k-th argument of the mock +// // function to type T and copies it to *output. +// ACTION_TEMPLATE(DuplicateArg, +// HAS_2_TEMPLATE_PARAMS(int, k, typename, T), +// AND_1_VALUE_PARAMS(output)) { +// *output = T(::testing::get(args)); +// } +// ... +// int n; +// EXPECT_CALL(mock, Foo(_, _)) +// .WillOnce(DuplicateArg<1, unsigned char>(&n)); +// +// To create an instance of an action template, write: +// +// ActionName(v1, ..., v_n) +// +// where the ts are the template arguments and the vs are the value +// arguments. The value argument types are inferred by the compiler. +// If you want to explicitly specify the value argument types, you can +// provide additional template arguments: +// +// ActionName(v1, ..., v_n) +// +// where u_i is the desired type of v_i. +// +// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the +// number of value parameters, but not on the number of template +// parameters. Without the restriction, the meaning of the following +// is unclear: +// +// OverloadedAction(x); +// +// Are we using a single-template-parameter action where 'bool' refers +// to the type of x, or are we using a two-template-parameter action +// where the compiler is asked to infer the type of x? +// +// Implementation notes: +// +// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and +// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for +// implementing ACTION_TEMPLATE. The main trick we use is to create +// new macro invocations when expanding a macro. For example, we have +// +// #define ACTION_TEMPLATE(name, template_params, value_params) +// ... GMOCK_INTERNAL_DECL_##template_params ... +// +// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...) +// to expand to +// +// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ... +// +// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the +// preprocessor will continue to expand it to +// +// ... typename T ... +// +// This technique conforms to the C++ standard and is portable. It +// allows us to implement action templates using O(N) code, where N is +// the maximum number of template/value parameters supported. Without +// using it, we'd have to devote O(N^2) amount of code to implement all +// combinations of m and n. + +// Declares the template parameters. + +$range j 1..n +$for j [[ +$range m 0..j-1 +#define GMOCK_INTERNAL_DECL_HAS_$j[[]] +_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[kind$m name$m]] + + +]] + +// Lists the template parameters. + +$for j [[ +$range m 0..j-1 +#define GMOCK_INTERNAL_LIST_HAS_$j[[]] +_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[name$m]] + + +]] + +// Declares the types of value parameters. + +$for i [[ +$range j 0..i-1 +#define GMOCK_INTERNAL_DECL_TYPE_AND_$i[[]] +_VALUE_PARAMS($for j, [[p$j]]) $for j [[, typename p$j##_type]] + + +]] + +// Initializes the value parameters. + +$for i [[ +$range j 0..i-1 +#define GMOCK_INTERNAL_INIT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])\ + ($for j, [[p$j##_type gmock_p$j]])$if i>0 [[ : ]]$for j, [[p$j(gmock_p$j)]] + + +]] + +// Declares the fields for storing the value parameters. + +$for i [[ +$range j 0..i-1 +#define GMOCK_INTERNAL_DEFN_AND_$i[[]] +_VALUE_PARAMS($for j, [[p$j]]) $for j [[p$j##_type p$j; ]] + + +]] + +// Lists the value parameters. + +$for i [[ +$range j 0..i-1 +#define GMOCK_INTERNAL_LIST_AND_$i[[]] +_VALUE_PARAMS($for j, [[p$j]]) $for j, [[p$j]] + + +]] + +// Lists the value parameter types. + +$for i [[ +$range j 0..i-1 +#define GMOCK_INTERNAL_LIST_TYPE_AND_$i[[]] +_VALUE_PARAMS($for j, [[p$j]]) $for j [[, p$j##_type]] + + +]] + +// Declares the value parameters. + +$for i [[ +$range j 0..i-1 +#define GMOCK_INTERNAL_DECL_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]] +$for j, [[p$j##_type p$j]] + + +]] + +// The suffix of the class template implementing the action template. +$for i [[ + + +$range j 0..i-1 +#define GMOCK_INTERNAL_COUNT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]] +$if i==1 [[P]] $elif i>=2 [[P$i]] +]] + + +// The name of the class template implementing the action template. +#define GMOCK_ACTION_CLASS_(name, value_params)\ + GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) + +$range k 0..n-1 + +#define ACTION_TEMPLATE(name, template_params, value_params)\ + template \ + class GMOCK_ACTION_CLASS_(name, value_params) {\ + public:\ + explicit GMOCK_ACTION_CLASS_(name, value_params)\ + GMOCK_INTERNAL_INIT_##value_params {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template <$for k, [[typename arg$k[[]]_type]]>\ + return_type gmock_PerformImpl(const args_type& args[[]] +$for k [[, arg$k[[]]_type arg$k]]) const;\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(\ + new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ + }\ + GMOCK_INTERNAL_DEFN_##value_params\ + private:\ + GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ + };\ + template \ + inline GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ + GMOCK_INTERNAL_DECL_##value_params) {\ + return GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params>(\ + GMOCK_INTERNAL_LIST_##value_params);\ + }\ + template \ + template \ + template \ + typename ::testing::internal::Function::Result\ + GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::\ + gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +$for i + +[[ +$var template = [[$if i==0 [[]] $else [[ +$range j 0..i-1 + + template <$for j, [[typename p$j##_type]]>\ +]]]] +$var class_name = [[name##Action[[$if i==0 [[]] $elif i==1 [[P]] + $else [[P$i]]]]]] +$range j 0..i-1 +$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] +$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var param_field_decls = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var param_field_decls2 = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var params = [[$for j, [[p$j]]]] +$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] +$var typename_arg_types = [[$for k, [[typename arg$k[[]]_type]]]] +$var arg_types_and_names = [[$for k, [[arg$k[[]]_type arg$k]]]] +$var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]] + $else [[ACTION_P$i]]]] + +#define $macro_name(name$for j [[, p$j]])\$template + class $class_name {\ + public:\ + [[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {}\ + template \ + class gmock_Impl : public ::testing::ActionInterface {\ + public:\ + typedef F function_type;\ + typedef typename ::testing::internal::Function::Result return_type;\ + typedef typename ::testing::internal::Function::ArgumentTuple\ + args_type;\ + [[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\ + virtual return_type Perform(const args_type& args) {\ + return ::testing::internal::ActionHelper::\ + Perform(this, args);\ + }\ + template <$typename_arg_types>\ + return_type gmock_PerformImpl(const args_type& args, [[]] +$arg_types_and_names) const;\$param_field_decls + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl($params));\ + }\$param_field_decls2 + private:\ + GTEST_DISALLOW_ASSIGN_($class_name);\ + };\$template + inline $class_name$param_types name($param_types_and_names) {\ + return $class_name$param_types($params);\ + }\$template + template \ + template <$typename_arg_types>\ + typename ::testing::internal::Function::Result\ + $class_name$param_types::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const +]] +$$ } // This meta comment fixes auto-indentation in Emacs. It won't +$$ // show up in the generated code. + + +namespace testing { + + +// The ACTION*() macros trigger warning C4100 (unreferenced formal +// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in +// the macro definition, as the warnings are generated when the macro +// is expanded and macro expansion cannot contain #pragma. Therefore +// we suppress them here. +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4100) +#endif + +// Various overloads for InvokeArgument(). +// +// The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th +// (0-based) argument, which must be a k-ary callable, of the mock +// function, with arguments a1, a2, ..., a_k. +// +// Notes: +// +// 1. The arguments are passed by value by default. If you need to +// pass an argument by reference, wrap it inside ByRef(). For +// example, +// +// InvokeArgument<1>(5, string("Hello"), ByRef(foo)) +// +// passes 5 and string("Hello") by value, and passes foo by +// reference. +// +// 2. If the callable takes an argument by reference but ByRef() is +// not used, it will receive the reference to a copy of the value, +// instead of the original value. For example, when the 0-th +// argument of the mock function takes a const string&, the action +// +// InvokeArgument<0>(string("Hello")) +// +// makes a copy of the temporary string("Hello") object and passes a +// reference of the copy, instead of the original temporary object, +// to the callable. This makes it easy for a user to define an +// InvokeArgument action from temporary values and have it performed +// later. + +namespace internal { +namespace invoke_argument { + +// Appears in InvokeArgumentAdl's argument list to help avoid +// accidental calls to user functions of the same name. +struct AdlTag {}; + +// InvokeArgumentAdl - a helper for InvokeArgument. +// The basic overloads are provided here for generic functors. +// Overloads for other custom-callables are provided in the +// internal/custom/callback-actions.h header. + +$range i 0..n +$for i +[[ +$range j 1..i + +template +R InvokeArgumentAdl(AdlTag, F f[[$for j [[, A$j a$j]]]]) { + return f([[$for j, [[a$j]]]]); +} +]] + +} // namespace invoke_argument +} // namespace internal + +$range i 0..n +$for i [[ +$range j 0..i-1 + +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) { + using internal::invoke_argument::InvokeArgumentAdl; + return InvokeArgumentAdl( + internal::invoke_argument::AdlTag(), + ::testing::get(args)$for j [[, p$j]]); +} + +]] + +// Various overloads for ReturnNew(). +// +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +$range i 0..n +$for i [[ +$range j 0..i-1 +$var ps = [[$for j, [[p$j]]]] + +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_$i[[]]_VALUE_PARAMS($ps)) { + return new T($ps); +} + +]] + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +} // namespace testing + +// Include any custom callback actions added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gmock/internal/custom/gmock-generated-actions.h" + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/googlemock/include/gmock/gmock-generated-function-mockers.h b/googlemock/include/gmock/gmock-generated-function-mockers.h new file mode 100644 index 0000000..4fa5ca9 --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-function-mockers.h @@ -0,0 +1,1095 @@ +// This file was GENERATED by command: +// pump.py gmock-generated-function-mockers.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements function mockers of various arities. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" + +#if GTEST_HAS_STD_FUNCTION_ +# include +#endif + +namespace testing { +namespace internal { + +template +class FunctionMockerBase; + +// Note: class FunctionMocker really belongs to the ::testing +// namespace. However if we define it in ::testing, MSVC will +// complain when classes in ::testing::internal declare it as a +// friend class template. To workaround this compiler bug, we define +// FunctionMocker in ::testing::internal and import it into ::testing. +template +class FunctionMocker; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With() { + return this->current_spec(); + } + + R Invoke() { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple()); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1) { + this->current_spec().SetMatchers(::testing::make_tuple(m1)); + return this->current_spec(); + } + + R Invoke(A1 a1) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, + m6)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, + m6, m7)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7, A8); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7, const Matcher& m8) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, + m6, m7, m8)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7, const Matcher& m8, + const Matcher& m9) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, + m6, m7, m8, m9)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9)); + } +}; + +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With(const Matcher& m1, const Matcher& m2, + const Matcher& m3, const Matcher& m4, const Matcher& m5, + const Matcher& m6, const Matcher& m7, const Matcher& m8, + const Matcher& m9, const Matcher& m10) { + this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, + m6, m7, m8, m9, m10)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, + A10 a10) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10)); + } +}; + +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; + +// GMOCK_RESULT_(tn, F) expands to the result type of function type F. +// We define this as a variadic macro in case F contains unprotected +// commas (the same reason that we use variadic macros in other places +// in this file). +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_RESULT_(tn, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Result + +// The type of argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_ARG_(tn, N, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Argument##N + +// The matcher type for argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MATCHER_(tn, N, ...) \ + const ::testing::Matcher& + +// The variable for mocking the given method. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + ) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 0), \ + this_method_does_not_take_0_arguments); \ + GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(0, constness, Method).Invoke(); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method() constness { \ + GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(0, constness, Method).With(); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 1), \ + this_method_does_not_take_1_argument); \ + GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ + GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 2), \ + this_method_does_not_take_2_arguments); \ + GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ + GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 3), \ + this_method_does_not_take_3_arguments); \ + GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ + GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 4), \ + this_method_does_not_take_4_arguments); \ + GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(4, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ + GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 5), \ + this_method_does_not_take_5_arguments); \ + GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(5, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ + GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 6), \ + this_method_does_not_take_6_arguments); \ + GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(6, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ + GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 7), \ + this_method_does_not_take_7_arguments); \ + GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(7, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ + GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 8), \ + this_method_does_not_take_8_arguments); \ + GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(8, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ + GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 9), \ + this_method_does_not_take_9_arguments); \ + GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(9, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ + gmock_a9); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ + GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ + gmock_a9); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \ + Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \ + GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ + == 10), \ + this_method_does_not_take_10_arguments); \ + GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(10, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + gmock_a10); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ + GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ + GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ + GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ + GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ + GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ + GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ + GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ + GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \ + GMOCK_MATCHER_(tn, 10, \ + __VA_ARGS__) gmock_a10) constness { \ + GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + gmock_a10); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \ + Method) + +#define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__) +#define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__) +#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__) +#define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__) +#define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__) +#define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__) +#define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__) +#define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__) +#define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__) +#define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__) +#define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__) + +#define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__) +#define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T(m, ...) \ + GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T(m, ...) \ + GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T(m, ...) \ + GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T(m, ...) \ + GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T(m, ...) \ + GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T(m, ...) \ + GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T(m, ...) \ + GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T(m, ...) \ + GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T(m, ...) \ + GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T(m, ...) \ + GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T(m, ...) \ + GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(, , ct, m, __VA_ARGS__) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(, , ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__) + +#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__) +#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__) + +// A MockFunction class has one mock method whose type is F. It is +// useful when you just want your test code to emit some messages and +// have Google Mock verify the right messages are sent (and perhaps at +// the right times). For example, if you are exercising code: +// +// Foo(1); +// Foo(2); +// Foo(3); +// +// and want to verify that Foo(1) and Foo(3) both invoke +// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: +// +// TEST(FooTest, InvokesBarCorrectly) { +// MyMock mock; +// MockFunction check; +// { +// InSequence s; +// +// EXPECT_CALL(mock, Bar("a")); +// EXPECT_CALL(check, Call("1")); +// EXPECT_CALL(check, Call("2")); +// EXPECT_CALL(mock, Bar("a")); +// } +// Foo(1); +// check.Call("1"); +// Foo(2); +// check.Call("2"); +// Foo(3); +// } +// +// The expectation spec says that the first Bar("a") must happen +// before check point "1", the second Bar("a") must happen after check +// point "2", and nothing should happen between the two check +// points. The explicit check points make it easy to tell which +// Bar("a") is called by which call to Foo(). +// +// MockFunction can also be used to exercise code that accepts +// std::function callbacks. To do so, use AsStdFunction() method +// to create std::function proxy forwarding to original object's Call. +// Example: +// +// TEST(FooTest, RunsCallbackWithBarArgument) { +// MockFunction callback; +// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); +// Foo(callback.AsStdFunction()); +// } +template +class MockFunction; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD0_T(Call, R()); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this]() -> R { + return this->Call(); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD1_T(Call, R(A0)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0) -> R { + return this->Call(a0); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD2_T(Call, R(A0, A1)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1) -> R { + return this->Call(a0, a1); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD3_T(Call, R(A0, A1, A2)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2) -> R { + return this->Call(a0, a1, a2); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD4_T(Call, R(A0, A1, A2, A3)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3) -> R { + return this->Call(a0, a1, a2, a3); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) -> R { + return this->Call(a0, a1, a2, a3, a4); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> R { + return this->Call(a0, a1, a2, a3, a4, a5); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) -> R { + return this->Call(a0, a1, a2, a3, a4, a5, a6); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) -> R { + return this->Call(a0, a1, a2, a3, a4, a5, a6, a7); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, + A8 a8) -> R { + return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, + A8 a8, A9 a9) -> R { + return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/googlemock/include/gmock/gmock-generated-function-mockers.h.pump b/googlemock/include/gmock/gmock-generated-function-mockers.h.pump new file mode 100644 index 0000000..811502d --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-function-mockers.h.pump @@ -0,0 +1,291 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-function-mockers.h. +$$ +$var n = 10 $$ The maximum arity we support. +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements function mockers of various arities. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" + +#if GTEST_HAS_STD_FUNCTION_ +# include +#endif + +namespace testing { +namespace internal { + +template +class FunctionMockerBase; + +// Note: class FunctionMocker really belongs to the ::testing +// namespace. However if we define it in ::testing, MSVC will +// complain when classes in ::testing::internal declare it as a +// friend class template. To workaround this compiler bug, we define +// FunctionMocker in ::testing::internal and import it into ::testing. +template +class FunctionMocker; + + +$range i 0..n +$for i [[ +$range j 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var As = [[$for j, [[A$j]]]] +$var as = [[$for j, [[a$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var ms = [[$for j, [[m$j]]]] +$var matchers = [[$for j, [[const Matcher& m$j]]]] +template +class FunctionMocker : public + internal::FunctionMockerBase { + public: + typedef R F($As); + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + MockSpec& With($matchers) { + +$if i >= 1 [[ + this->current_spec().SetMatchers(::testing::make_tuple($ms)); + +]] + return this->current_spec(); + } + + R Invoke($Aas) { + // Even though gcc and MSVC don't enforce it, 'this->' is required + // by the C++ standard [14.6.4] here, as the base class type is + // dependent on the template argument (and thus shouldn't be + // looked into when resolving InvokeWith). + return this->InvokeWith(ArgumentTuple($as)); + } +}; + + +]] +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; + +// GMOCK_RESULT_(tn, F) expands to the result type of function type F. +// We define this as a variadic macro in case F contains unprotected +// commas (the same reason that we use variadic macros in other places +// in this file). +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_RESULT_(tn, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Result + +// The type of argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_ARG_(tn, N, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Argument##N + +// The matcher type for argument N of the given function type. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MATCHER_(tn, N, ...) \ + const ::testing::Matcher& + +// The variable for mocking the given method. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + + +$for i [[ +$range j 1..i +$var arg_as = [[$for j, \ + [[GMOCK_ARG_(tn, $j, __VA_ARGS__) gmock_a$j]]]] +$var as = [[$for j, [[gmock_a$j]]]] +$var matcher_as = [[$for j, \ + [[GMOCK_MATCHER_(tn, $j, __VA_ARGS__) gmock_a$j]]]] +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + $arg_as) constness { \ + GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ + tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value == $i), \ + this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ + GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_($i, constness, Method).Invoke($as); \ + } \ + ::testing::MockSpec<__VA_ARGS__>& \ + gmock_##Method($matcher_as) constness { \ + GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_($i, constness, Method).With($as); \ + } \ + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_($i, constness, Method) + + +]] +$for i [[ +#define MOCK_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, , , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, const, , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_T(m, ...) GMOCK_METHOD$i[[]]_(typename, , , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_T(m, ...) \ + GMOCK_METHOD$i[[]]_(typename, const, , m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(, , ct, m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(, const, ct, m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(typename, , ct, m, __VA_ARGS__) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(typename, const, ct, m, __VA_ARGS__) + +]] + +// A MockFunction class has one mock method whose type is F. It is +// useful when you just want your test code to emit some messages and +// have Google Mock verify the right messages are sent (and perhaps at +// the right times). For example, if you are exercising code: +// +// Foo(1); +// Foo(2); +// Foo(3); +// +// and want to verify that Foo(1) and Foo(3) both invoke +// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: +// +// TEST(FooTest, InvokesBarCorrectly) { +// MyMock mock; +// MockFunction check; +// { +// InSequence s; +// +// EXPECT_CALL(mock, Bar("a")); +// EXPECT_CALL(check, Call("1")); +// EXPECT_CALL(check, Call("2")); +// EXPECT_CALL(mock, Bar("a")); +// } +// Foo(1); +// check.Call("1"); +// Foo(2); +// check.Call("2"); +// Foo(3); +// } +// +// The expectation spec says that the first Bar("a") must happen +// before check point "1", the second Bar("a") must happen after check +// point "2", and nothing should happen between the two check +// points. The explicit check points make it easy to tell which +// Bar("a") is called by which call to Foo(). +// +// MockFunction can also be used to exercise code that accepts +// std::function callbacks. To do so, use AsStdFunction() method +// to create std::function proxy forwarding to original object's Call. +// Example: +// +// TEST(FooTest, RunsCallbackWithBarArgument) { +// MockFunction callback; +// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); +// Foo(callback.AsStdFunction()); +// } +template +class MockFunction; + + +$for i [[ +$range j 0..i-1 +$var ArgTypes = [[$for j, [[A$j]]]] +$var ArgNames = [[$for j, [[a$j]]]] +$var ArgDecls = [[$for j, [[A$j a$j]]]] +template +class MockFunction { + public: + MockFunction() {} + + MOCK_METHOD$i[[]]_T(Call, R($ArgTypes)); + +#if GTEST_HAS_STD_FUNCTION_ + std::function AsStdFunction() { + return [this]($ArgDecls) -> R { + return this->Call($ArgNames); + }; + } +#endif // GTEST_HAS_STD_FUNCTION_ + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); +}; + + +]] +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/googlemock/include/gmock/gmock-generated-matchers.h b/googlemock/include/gmock/gmock-generated-matchers.h new file mode 100644 index 0000000..57056fd --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-matchers.h @@ -0,0 +1,2179 @@ +// This file was GENERATED by command: +// pump.py gmock-generated-matchers.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used variadic matchers. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ + +#include +#include +#include +#include +#include "gmock/gmock-matchers.h" + +namespace testing { +namespace internal { + +// The type of the i-th (0-based) field of Tuple. +#define GMOCK_FIELD_TYPE_(Tuple, i) \ + typename ::testing::tuple_element::type + +// TupleFields is for selecting fields from a +// tuple of type Tuple. It has two members: +// +// type: a tuple type whose i-th field is the ki-th field of Tuple. +// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. +// +// For example, in class TupleFields, 2, 0>, we have: +// +// type is tuple, and +// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). + +template +class TupleFields; + +// This generic version is used when there are 10 selectors. +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t), get(t), get(t)); + } +}; + +// The following specialization is used for 0 ~ 9 selectors. + +template +class TupleFields { + public: + typedef ::testing::tuple<> type; + static type GetSelectedFields(const Tuple& /* t */) { + return type(); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t), get(t), + get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::testing::tuple type; + static type GetSelectedFields(const Tuple& t) { + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t), get(t)); + } +}; + +#undef GMOCK_FIELD_TYPE_ + +// Implements the Args() matcher. +template +class ArgsMatcherImpl : public MatcherInterface { + public: + // ArgsTuple may have top-level const or reference modifiers. + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; + typedef typename internal::TupleFields::type SelectedArgs; + typedef Matcher MonomorphicInnerMatcher; + + template + explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) + : inner_matcher_(SafeMatcherCast(inner_matcher)) {} + + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + const SelectedArgs& selected_args = GetSelectedArgs(args); + if (!listener->IsInterested()) + return inner_matcher_.Matches(selected_args); + + PrintIndices(listener->stream()); + *listener << "are " << PrintToString(selected_args); + + StringMatchResultListener inner_listener; + const bool match = inner_matcher_.MatchAndExplain(selected_args, + &inner_listener); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return match; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeNegationTo(os); + } + + private: + static SelectedArgs GetSelectedArgs(ArgsTuple args) { + return TupleFields::GetSelectedFields(args); + } + + // Prints the indices of the selected fields. + static void PrintIndices(::std::ostream* os) { + *os << "whose fields ("; + const int indices[10] = { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 }; + for (int i = 0; i < 10; i++) { + if (indices[i] < 0) + break; + + if (i >= 1) + *os << ", "; + + *os << "#" << indices[i]; + } + *os << ") "; + } + + const MonomorphicInnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); +}; + +template +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); + } + + private: + const InnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcher); +}; + +// A set of metafunctions for computing the result type of AllOf. +// AllOf(m1, ..., mN) returns +// AllOfResultN::type. + +// Although AllOf isn't defined for one argument, AllOfResult1 is defined +// to simplify the implementation. +template +struct AllOfResult1 { + typedef M1 type; +}; + +template +struct AllOfResult2 { + typedef BothOfMatcher< + typename AllOfResult1::type, + typename AllOfResult1::type + > type; +}; + +template +struct AllOfResult3 { + typedef BothOfMatcher< + typename AllOfResult1::type, + typename AllOfResult2::type + > type; +}; + +template +struct AllOfResult4 { + typedef BothOfMatcher< + typename AllOfResult2::type, + typename AllOfResult2::type + > type; +}; + +template +struct AllOfResult5 { + typedef BothOfMatcher< + typename AllOfResult2::type, + typename AllOfResult3::type + > type; +}; + +template +struct AllOfResult6 { + typedef BothOfMatcher< + typename AllOfResult3::type, + typename AllOfResult3::type + > type; +}; + +template +struct AllOfResult7 { + typedef BothOfMatcher< + typename AllOfResult3::type, + typename AllOfResult4::type + > type; +}; + +template +struct AllOfResult8 { + typedef BothOfMatcher< + typename AllOfResult4::type, + typename AllOfResult4::type + > type; +}; + +template +struct AllOfResult9 { + typedef BothOfMatcher< + typename AllOfResult4::type, + typename AllOfResult5::type + > type; +}; + +template +struct AllOfResult10 { + typedef BothOfMatcher< + typename AllOfResult5::type, + typename AllOfResult5::type + > type; +}; + +// A set of metafunctions for computing the result type of AnyOf. +// AnyOf(m1, ..., mN) returns +// AnyOfResultN::type. + +// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined +// to simplify the implementation. +template +struct AnyOfResult1 { + typedef M1 type; +}; + +template +struct AnyOfResult2 { + typedef EitherOfMatcher< + typename AnyOfResult1::type, + typename AnyOfResult1::type + > type; +}; + +template +struct AnyOfResult3 { + typedef EitherOfMatcher< + typename AnyOfResult1::type, + typename AnyOfResult2::type + > type; +}; + +template +struct AnyOfResult4 { + typedef EitherOfMatcher< + typename AnyOfResult2::type, + typename AnyOfResult2::type + > type; +}; + +template +struct AnyOfResult5 { + typedef EitherOfMatcher< + typename AnyOfResult2::type, + typename AnyOfResult3::type + > type; +}; + +template +struct AnyOfResult6 { + typedef EitherOfMatcher< + typename AnyOfResult3::type, + typename AnyOfResult3::type + > type; +}; + +template +struct AnyOfResult7 { + typedef EitherOfMatcher< + typename AnyOfResult3::type, + typename AnyOfResult4::type + > type; +}; + +template +struct AnyOfResult8 { + typedef EitherOfMatcher< + typename AnyOfResult4::type, + typename AnyOfResult4::type + > type; +}; + +template +struct AnyOfResult9 { + typedef EitherOfMatcher< + typename AnyOfResult4::type, + typename AnyOfResult5::type + > type; +}; + +template +struct AnyOfResult10 { + typedef EitherOfMatcher< + typename AnyOfResult5::type, + typename AnyOfResult5::type + > type; +}; + +} // namespace internal + +// Args(a_matcher) matches a tuple if the selected +// fields of it matches a_matcher. C++ doesn't support default +// arguments for function templates, so we have to overload it. +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +template +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + +// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with +// n elements, where the i-th element in the container must +// match the i-th argument in the list. Each argument of +// ElementsAre() can be either a value or a matcher. We support up to +// 10 arguments. +// +// The use of DecayArray in the implementation allows ElementsAre() +// to accept string literals, whose type is const char[N], but we +// want to treat them as const char*. +// +// NOTE: Since ElementsAre() cares about the order of the elements, it +// must not be used with containers whose elements's order is +// undefined (e.g. hash_map). + +inline internal::ElementsAreMatcher< + ::testing::tuple<> > +ElementsAre() { + typedef ::testing::tuple<> Args; + return internal::ElementsAreMatcher(Args()); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type> > +ElementsAre(const T1& e1) { + typedef ::testing::tuple< + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8, e9)); +} + +template +inline internal::ElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, + const T10& e10) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8, e9, e10)); +} + +// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension +// that matches n elements in any order. We support up to n=10 arguments. + +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple<> > +UnorderedElementsAre() { + typedef ::testing::tuple<> Args; + return internal::UnorderedElementsAreMatcher(Args()); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1) { + typedef ::testing::tuple< + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8, e9)); +} + +template +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, + const T10& e10) { + typedef ::testing::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10)); +} + +// AllOf(m1, m2, ..., mk) matches any value that matches all of the given +// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. + +template +inline typename internal::AllOfResult2::type +AllOf(M1 m1, M2 m2) { + return typename internal::AllOfResult2::type( + m1, + m2); +} + +template +inline typename internal::AllOfResult3::type +AllOf(M1 m1, M2 m2, M3 m3) { + return typename internal::AllOfResult3::type( + m1, + ::testing::AllOf(m2, m3)); +} + +template +inline typename internal::AllOfResult4::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4) { + return typename internal::AllOfResult4::type( + ::testing::AllOf(m1, m2), + ::testing::AllOf(m3, m4)); +} + +template +inline typename internal::AllOfResult5::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { + return typename internal::AllOfResult5::type( + ::testing::AllOf(m1, m2), + ::testing::AllOf(m3, m4, m5)); +} + +template +inline typename internal::AllOfResult6::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { + return typename internal::AllOfResult6::type( + ::testing::AllOf(m1, m2, m3), + ::testing::AllOf(m4, m5, m6)); +} + +template +inline typename internal::AllOfResult7::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { + return typename internal::AllOfResult7::type( + ::testing::AllOf(m1, m2, m3), + ::testing::AllOf(m4, m5, m6, m7)); +} + +template +inline typename internal::AllOfResult8::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { + return typename internal::AllOfResult8::type( + ::testing::AllOf(m1, m2, m3, m4), + ::testing::AllOf(m5, m6, m7, m8)); +} + +template +inline typename internal::AllOfResult9::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { + return typename internal::AllOfResult9::type( + ::testing::AllOf(m1, m2, m3, m4), + ::testing::AllOf(m5, m6, m7, m8, m9)); +} + +template +inline typename internal::AllOfResult10::type +AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { + return typename internal::AllOfResult10::type( + ::testing::AllOf(m1, m2, m3, m4, m5), + ::testing::AllOf(m6, m7, m8, m9, m10)); +} + +// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given +// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. + +template +inline typename internal::AnyOfResult2::type +AnyOf(M1 m1, M2 m2) { + return typename internal::AnyOfResult2::type( + m1, + m2); +} + +template +inline typename internal::AnyOfResult3::type +AnyOf(M1 m1, M2 m2, M3 m3) { + return typename internal::AnyOfResult3::type( + m1, + ::testing::AnyOf(m2, m3)); +} + +template +inline typename internal::AnyOfResult4::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4) { + return typename internal::AnyOfResult4::type( + ::testing::AnyOf(m1, m2), + ::testing::AnyOf(m3, m4)); +} + +template +inline typename internal::AnyOfResult5::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { + return typename internal::AnyOfResult5::type( + ::testing::AnyOf(m1, m2), + ::testing::AnyOf(m3, m4, m5)); +} + +template +inline typename internal::AnyOfResult6::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { + return typename internal::AnyOfResult6::type( + ::testing::AnyOf(m1, m2, m3), + ::testing::AnyOf(m4, m5, m6)); +} + +template +inline typename internal::AnyOfResult7::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { + return typename internal::AnyOfResult7::type( + ::testing::AnyOf(m1, m2, m3), + ::testing::AnyOf(m4, m5, m6, m7)); +} + +template +inline typename internal::AnyOfResult8::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { + return typename internal::AnyOfResult8::type( + ::testing::AnyOf(m1, m2, m3, m4), + ::testing::AnyOf(m5, m6, m7, m8)); +} + +template +inline typename internal::AnyOfResult9::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { + return typename internal::AnyOfResult9::type( + ::testing::AnyOf(m1, m2, m3, m4), + ::testing::AnyOf(m5, m6, m7, m8, m9)); +} + +template +inline typename internal::AnyOfResult10::type +AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { + return typename internal::AnyOfResult10::type( + ::testing::AnyOf(m1, m2, m3, m4, m5), + ::testing::AnyOf(m6, m7, m8, m9, m10)); +} + +} // namespace testing + + +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using MATCHER*() inside +// a function. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +#define MATCHER(name, description)\ + class name##Matcher {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl()\ + {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple<>()));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl());\ + }\ + name##Matcher() {\ + }\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##Matcher);\ + };\ + inline name##Matcher name() {\ + return name##Matcher();\ + }\ + template \ + bool name##Matcher::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P(name, p0, description)\ + template \ + class name##MatcherP {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + explicit gmock_Impl(p0##_type gmock_p0)\ + : p0(gmock_p0) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0));\ + }\ + explicit name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ + }\ + p0##_type p0;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP);\ + };\ + template \ + inline name##MatcherP name(p0##_type p0) {\ + return name##MatcherP(p0);\ + }\ + template \ + template \ + bool name##MatcherP::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P2(name, p0, p1, description)\ + template \ + class name##MatcherP2 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\ + : p0(gmock_p0), p1(gmock_p1) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1));\ + }\ + name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\ + };\ + template \ + inline name##MatcherP2 name(p0##_type p0, \ + p1##_type p1) {\ + return name##MatcherP2(p0, p1);\ + }\ + template \ + template \ + bool name##MatcherP2::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P3(name, p0, p1, p2, description)\ + template \ + class name##MatcherP3 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, \ + p2)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2));\ + }\ + name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\ + };\ + template \ + inline name##MatcherP3 name(p0##_type p0, \ + p1##_type p1, p2##_type p2) {\ + return name##MatcherP3(p0, p1, p2);\ + }\ + template \ + template \ + bool name##MatcherP3::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P4(name, p0, p1, p2, p3, description)\ + template \ + class name##MatcherP4 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, p3)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3));\ + }\ + name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\ + };\ + template \ + inline name##MatcherP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3) {\ + return name##MatcherP4(p0, \ + p1, p2, p3);\ + }\ + template \ + template \ + bool name##MatcherP4::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\ + template \ + class name##MatcherP5 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, p3, p4)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4));\ + }\ + name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, \ + p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\ + };\ + template \ + inline name##MatcherP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4) {\ + return name##MatcherP5(p0, p1, p2, p3, p4);\ + }\ + template \ + template \ + bool name##MatcherP5::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\ + template \ + class name##MatcherP6 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, p3, p4, p5)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5));\ + }\ + name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\ + };\ + template \ + inline name##MatcherP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3, p4##_type p4, p5##_type p5) {\ + return name##MatcherP6(p0, p1, p2, p3, p4, p5);\ + }\ + template \ + template \ + bool name##MatcherP6::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\ + template \ + class name##MatcherP7 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, p3, p4, p5, \ + p6)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6));\ + }\ + name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ + p6(gmock_p6) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\ + };\ + template \ + inline name##MatcherP7 name(p0##_type p0, p1##_type p1, \ + p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6) {\ + return name##MatcherP7(p0, p1, p2, p3, p4, p5, p6);\ + }\ + template \ + template \ + bool name##MatcherP7::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\ + template \ + class name##MatcherP8 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, \ + p3, p4, p5, p6, p7)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7));\ + }\ + name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, \ + p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\ + };\ + template \ + inline name##MatcherP8 name(p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6, p7##_type p7) {\ + return name##MatcherP8(p0, p1, p2, p3, p4, p5, \ + p6, p7);\ + }\ + template \ + template \ + bool name##MatcherP8::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\ + template \ + class name##MatcherP9 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8));\ + }\ + name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\ + };\ + template \ + inline name##MatcherP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ + p8##_type p8) {\ + return name##MatcherP9(p0, p1, p2, \ + p3, p4, p5, p6, p7, p8);\ + }\ + template \ + template \ + bool name##MatcherP9::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\ + template \ + class name##MatcherP10 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8), p9(gmock_p9) {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\ + }\ + name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\ + };\ + template \ + inline name##MatcherP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9) {\ + return name##MatcherP10(p0, \ + p1, p2, p3, p4, p5, p6, p7, p8, p9);\ + }\ + template \ + template \ + bool name##MatcherP10::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/googlemock/include/gmock/gmock-generated-matchers.h.pump b/googlemock/include/gmock/gmock-generated-matchers.h.pump new file mode 100644 index 0000000..de30c2c --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-matchers.h.pump @@ -0,0 +1,672 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-actions.h. +$$ +$var n = 10 $$ The maximum arity we support. +$$ }} This line fixes auto-indentation of the following code in Emacs. +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used variadic matchers. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ + +#include +#include +#include +#include +#include "gmock/gmock-matchers.h" + +namespace testing { +namespace internal { + +$range i 0..n-1 + +// The type of the i-th (0-based) field of Tuple. +#define GMOCK_FIELD_TYPE_(Tuple, i) \ + typename ::testing::tuple_element::type + +// TupleFields is for selecting fields from a +// tuple of type Tuple. It has two members: +// +// type: a tuple type whose i-th field is the ki-th field of Tuple. +// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. +// +// For example, in class TupleFields, 2, 0>, we have: +// +// type is tuple, and +// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). + +template +class TupleFields; + +// This generic version is used when there are $n selectors. +template +class TupleFields { + public: + typedef ::testing::tuple<$for i, [[GMOCK_FIELD_TYPE_(Tuple, k$i)]]> type; + static type GetSelectedFields(const Tuple& t) { + return type($for i, [[get(t)]]); + } +}; + +// The following specialization is used for 0 ~ $(n-1) selectors. + +$for i [[ +$$ }}} +$range j 0..i-1 +$range k 0..n-1 + +template +class TupleFields { + public: + typedef ::testing::tuple<$for j, [[GMOCK_FIELD_TYPE_(Tuple, k$j)]]> type; + static type GetSelectedFields(const Tuple& $if i==0 [[/* t */]] $else [[t]]) { + return type($for j, [[get(t)]]); + } +}; + +]] + +#undef GMOCK_FIELD_TYPE_ + +// Implements the Args() matcher. + +$var ks = [[$for i, [[k$i]]]] +template +class ArgsMatcherImpl : public MatcherInterface { + public: + // ArgsTuple may have top-level const or reference modifiers. + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; + typedef typename internal::TupleFields::type SelectedArgs; + typedef Matcher MonomorphicInnerMatcher; + + template + explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) + : inner_matcher_(SafeMatcherCast(inner_matcher)) {} + + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + const SelectedArgs& selected_args = GetSelectedArgs(args); + if (!listener->IsInterested()) + return inner_matcher_.Matches(selected_args); + + PrintIndices(listener->stream()); + *listener << "are " << PrintToString(selected_args); + + StringMatchResultListener inner_listener; + const bool match = inner_matcher_.MatchAndExplain(selected_args, + &inner_listener); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return match; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "are a tuple "; + PrintIndices(os); + inner_matcher_.DescribeNegationTo(os); + } + + private: + static SelectedArgs GetSelectedArgs(ArgsTuple args) { + return TupleFields::GetSelectedFields(args); + } + + // Prints the indices of the selected fields. + static void PrintIndices(::std::ostream* os) { + *os << "whose fields ("; + const int indices[$n] = { $ks }; + for (int i = 0; i < $n; i++) { + if (indices[i] < 0) + break; + + if (i >= 1) + *os << ", "; + + *os << "#" << indices[i]; + } + *os << ") "; + } + + const MonomorphicInnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); +}; + +template +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); + } + + private: + const InnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcher); +}; + +// A set of metafunctions for computing the result type of AllOf. +// AllOf(m1, ..., mN) returns +// AllOfResultN::type. + +// Although AllOf isn't defined for one argument, AllOfResult1 is defined +// to simplify the implementation. +template +struct AllOfResult1 { + typedef M1 type; +}; + +$range i 1..n + +$range i 2..n +$for i [[ +$range j 2..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template +struct AllOfResult$i { + typedef BothOfMatcher< + typename AllOfResult$m<$for k, [[M$k]]>::type, + typename AllOfResult$(i-m)<$for t, [[M$t]]>::type + > type; +}; + +]] + +// A set of metafunctions for computing the result type of AnyOf. +// AnyOf(m1, ..., mN) returns +// AnyOfResultN::type. + +// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined +// to simplify the implementation. +template +struct AnyOfResult1 { + typedef M1 type; +}; + +$range i 1..n + +$range i 2..n +$for i [[ +$range j 2..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template +struct AnyOfResult$i { + typedef EitherOfMatcher< + typename AnyOfResult$m<$for k, [[M$k]]>::type, + typename AnyOfResult$(i-m)<$for t, [[M$t]]>::type + > type; +}; + +]] + +} // namespace internal + +// Args(a_matcher) matches a tuple if the selected +// fields of it matches a_matcher. C++ doesn't support default +// arguments for function templates, so we have to overload it. + +$range i 0..n +$for i [[ +$range j 1..i +template <$for j [[int k$j, ]]typename InnerMatcher> +inline internal::ArgsMatcher +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher(matcher); +} + + +]] +// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with +// n elements, where the i-th element in the container must +// match the i-th argument in the list. Each argument of +// ElementsAre() can be either a value or a matcher. We support up to +// $n arguments. +// +// The use of DecayArray in the implementation allows ElementsAre() +// to accept string literals, whose type is const char[N], but we +// want to treat them as const char*. +// +// NOTE: Since ElementsAre() cares about the order of the elements, it +// must not be used with containers whose elements's order is +// undefined (e.g. hash_map). + +$range i 0..n +$for i [[ + +$range j 1..i + +$if i>0 [[ + +template <$for j, [[typename T$j]]> +]] + +inline internal::ElementsAreMatcher< + ::testing::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> > +ElementsAre($for j, [[const T$j& e$j]]) { + typedef ::testing::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> Args; + return internal::ElementsAreMatcher(Args($for j, [[e$j]])); +} + +]] + +// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension +// that matches n elements in any order. We support up to n=$n arguments. + +$range i 0..n +$for i [[ + +$range j 1..i + +$if i>0 [[ + +template <$for j, [[typename T$j]]> +]] + +inline internal::UnorderedElementsAreMatcher< + ::testing::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> > +UnorderedElementsAre($for j, [[const T$j& e$j]]) { + typedef ::testing::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> Args; + return internal::UnorderedElementsAreMatcher(Args($for j, [[e$j]])); +} + +]] + +// AllOf(m1, m2, ..., mk) matches any value that matches all of the given +// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. + +$range i 2..n +$for i [[ +$range j 1..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template <$for j, [[typename M$j]]> +inline typename internal::AllOfResult$i<$for j, [[M$j]]>::type +AllOf($for j, [[M$j m$j]]) { + return typename internal::AllOfResult$i<$for j, [[M$j]]>::type( + $if m == 1 [[m1]] $else [[::testing::AllOf($for k, [[m$k]])]], + $if m+1 == i [[m$i]] $else [[::testing::AllOf($for t, [[m$t]])]]); +} + +]] + +// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given +// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. + +$range i 2..n +$for i [[ +$range j 1..i +$var m = i/2 +$range k 1..m +$range t m+1..i + +template <$for j, [[typename M$j]]> +inline typename internal::AnyOfResult$i<$for j, [[M$j]]>::type +AnyOf($for j, [[M$j m$j]]) { + return typename internal::AnyOfResult$i<$for j, [[M$j]]>::type( + $if m == 1 [[m1]] $else [[::testing::AnyOf($for k, [[m$k]])]], + $if m+1 == i [[m$i]] $else [[::testing::AnyOf($for t, [[m$t]])]]); +} + +]] + +} // namespace testing +$$ } // This Pump meta comment fixes auto-indentation in Emacs. It will not +$$ // show up in the generated code. + + +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using MATCHER*() inside +// a function. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +$range i 0..n +$for i + +[[ +$var macro_name = [[$if i==0 [[MATCHER]] $elif i==1 [[MATCHER_P]] + $else [[MATCHER_P$i]]]] +$var class_name = [[name##Matcher[[$if i==0 [[]] $elif i==1 [[P]] + $else [[P$i]]]]]] +$range j 0..i-1 +$var template = [[$if i==0 [[]] $else [[ + + template <$for j, [[typename p$j##_type]]>\ +]]]] +$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var impl_ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var impl_inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var params = [[$for j, [[p$j]]]] +$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] +$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] +$var param_field_decls = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var param_field_decls2 = [[$for j +[[ + + p$j##_type p$j;\ +]]]] + +#define $macro_name(name$for j [[, p$j]], description)\$template + class $class_name {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ + $impl_inits {}\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ + }\$param_field_decls + private:\ + ::testing::internal::string FormatDescription(bool negation) const {\ + const ::testing::internal::string gmock_description = (description);\ + if (!gmock_description.empty())\ + return gmock_description;\ + return ::testing::internal::FormatMatcherDescription(\ + negation, #name, \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::testing::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]])));\ + }\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(\ + new gmock_Impl($params));\ + }\ + [[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {\ + }\$param_field_decls2 + private:\ + GTEST_DISALLOW_ASSIGN_($class_name);\ + };\$template + inline $class_name$param_types name($param_types_and_names) {\ + return $class_name$param_types($params);\ + }\$template + template \ + bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ + arg_type arg, \ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const +]] + + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/googlemock/include/gmock/gmock-generated-nice-strict.h b/googlemock/include/gmock/gmock-generated-nice-strict.h new file mode 100644 index 0000000..4095f4d --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-nice-strict.h @@ -0,0 +1,397 @@ +// This file was GENERATED by command: +// pump.py gmock-generated-nice-strict.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements class templates NiceMock, NaggyMock, and StrictMock. +// +// Given a mock class MockFoo that is created using Google Mock, +// NiceMock is a subclass of MockFoo that allows +// uninteresting calls (i.e. calls to mock methods that have no +// EXPECT_CALL specs), NaggyMock is a subclass of MockFoo +// that prints a warning when an uninteresting call occurs, and +// StrictMock is a subclass of MockFoo that treats all +// uninteresting calls as errors. +// +// Currently a mock is naggy by default, so MockFoo and +// NaggyMock behave like the same. However, we will soon +// switch the default behavior of mocks to be nice, as that in general +// leads to more maintainable tests. When that happens, MockFoo will +// stop behaving like NaggyMock and start behaving like +// NiceMock. +// +// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of +// their respective base class, with up-to 10 arguments. Therefore +// you can write NiceMock(5, "a") to construct a nice mock +// where MockFoo has a constructor that accepts (int, const char*), +// for example. +// +// A known limitation is that NiceMock, NaggyMock, +// and StrictMock only works for mock methods defined using +// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. +// If a mock method is defined in a base class of MockFoo, the "nice" +// or "strict" modifier may not affect it, depending on the compiler. +// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT +// supported. +// +// Another known limitation is that the constructors of the base mock +// cannot have arguments passed by non-const reference, which are +// banned by the Google C++ style guide anyway. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { + +template +class NiceMock : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + NiceMock() { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit NiceMock(const A1& a1) : MockClass(a1) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + template + NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, + a6, a7) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, + a2, a3, a4, a5, a6, a7, a8) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, + const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, + const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { + ::testing::Mock::AllowUninterestingCalls( + internal::ImplicitCast_(this)); + } + + virtual ~NiceMock() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); +}; + +template +class NaggyMock : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + NaggyMock() { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit NaggyMock(const A1& a1) : MockClass(a1) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + template + NaggyMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, + a6, a7) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, + a2, a3, a4, a5, a6, a7, a8) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, + const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, + const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { + ::testing::Mock::WarnUninterestingCalls( + internal::ImplicitCast_(this)); + } + + virtual ~NaggyMock() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock); +}; + +template +class StrictMock : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + StrictMock() { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit StrictMock(const A1& a1) : MockClass(a1) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + template + StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, + a6, a7) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, + a2, a3, a4, a5, a6, a7, a8) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, + const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, + const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { + ::testing::Mock::FailUninterestingCalls( + internal::ImplicitCast_(this)); + } + + virtual ~StrictMock() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock); +}; + +// The following specializations catch some (relatively more common) +// user errors of nesting nice and strict mocks. They do NOT catch +// all possible errors. + +// These specializations are declared but not defined, as NiceMock, +// NaggyMock, and StrictMock cannot be nested. + +template +class NiceMock >; +template +class NiceMock >; +template +class NiceMock >; + +template +class NaggyMock >; +template +class NaggyMock >; +template +class NaggyMock >; + +template +class StrictMock >; +template +class StrictMock >; +template +class StrictMock >; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/googlemock/include/gmock/gmock-generated-nice-strict.h.pump b/googlemock/include/gmock/gmock-generated-nice-strict.h.pump new file mode 100644 index 0000000..3ee1ce7 --- /dev/null +++ b/googlemock/include/gmock/gmock-generated-nice-strict.h.pump @@ -0,0 +1,161 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-nice-strict.h. +$$ +$var n = 10 $$ The maximum arity we support. +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements class templates NiceMock, NaggyMock, and StrictMock. +// +// Given a mock class MockFoo that is created using Google Mock, +// NiceMock is a subclass of MockFoo that allows +// uninteresting calls (i.e. calls to mock methods that have no +// EXPECT_CALL specs), NaggyMock is a subclass of MockFoo +// that prints a warning when an uninteresting call occurs, and +// StrictMock is a subclass of MockFoo that treats all +// uninteresting calls as errors. +// +// Currently a mock is naggy by default, so MockFoo and +// NaggyMock behave like the same. However, we will soon +// switch the default behavior of mocks to be nice, as that in general +// leads to more maintainable tests. When that happens, MockFoo will +// stop behaving like NaggyMock and start behaving like +// NiceMock. +// +// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of +// their respective base class, with up-to $n arguments. Therefore +// you can write NiceMock(5, "a") to construct a nice mock +// where MockFoo has a constructor that accepts (int, const char*), +// for example. +// +// A known limitation is that NiceMock, NaggyMock, +// and StrictMock only works for mock methods defined using +// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. +// If a mock method is defined in a base class of MockFoo, the "nice" +// or "strict" modifier may not affect it, depending on the compiler. +// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT +// supported. +// +// Another known limitation is that the constructors of the base mock +// cannot have arguments passed by non-const reference, which are +// banned by the Google C++ style guide anyway. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-port.h" + +namespace testing { + +$range kind 0..2 +$for kind [[ + +$var clazz=[[$if kind==0 [[NiceMock]] + $elif kind==1 [[NaggyMock]] + $else [[StrictMock]]]] + +$var method=[[$if kind==0 [[AllowUninterestingCalls]] + $elif kind==1 [[WarnUninterestingCalls]] + $else [[FailUninterestingCalls]]]] + +template +class $clazz : public MockClass { + public: + // We don't factor out the constructor body to a common method, as + // we have to avoid a possible clash with members of MockClass. + $clazz() { + ::testing::Mock::$method( + internal::ImplicitCast_(this)); + } + + // C++ doesn't (yet) allow inheritance of constructors, so we have + // to define it for each arity. + template + explicit $clazz(const A1& a1) : MockClass(a1) { + ::testing::Mock::$method( + internal::ImplicitCast_(this)); + } + +$range i 2..n +$for i [[ +$range j 1..i + template <$for j, [[typename A$j]]> + $clazz($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { + ::testing::Mock::$method( + internal::ImplicitCast_(this)); + } + + +]] + virtual ~$clazz() { + ::testing::Mock::UnregisterCallReaction( + internal::ImplicitCast_(this)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_($clazz); +}; + +]] + +// The following specializations catch some (relatively more common) +// user errors of nesting nice and strict mocks. They do NOT catch +// all possible errors. + +// These specializations are declared but not defined, as NiceMock, +// NaggyMock, and StrictMock cannot be nested. + +template +class NiceMock >; +template +class NiceMock >; +template +class NiceMock >; + +template +class NaggyMock >; +template +class NaggyMock >; +template +class NaggyMock >; + +template +class StrictMock >; +template +class StrictMock >; +template +class StrictMock >; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h new file mode 100644 index 0000000..33b37a7 --- /dev/null +++ b/googlemock/include/gmock/gmock-matchers.h @@ -0,0 +1,4399 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used argument matchers. More +// matchers can be defined by the user implementing the +// MatcherInterface interface if necessary. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ + +#include +#include +#include +#include +#include // NOLINT +#include +#include +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" + +#if GTEST_HAS_STD_INITIALIZER_LIST_ +# include // NOLINT -- must be after gtest.h +#endif + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +// TODO(wan@google.com): add method +// bool InterestedInWhy(bool result) const; +// to indicate whether the listener is interested in why the match +// result is 'result'. +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != NULL) + *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true iff the listener is interested in an explanation of + // the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != NULL; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true iff the matcher matches x; also explains the match + // result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Mock) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation accumulated so far. + internal::string str() const { return ss_.str(); } + + // Clears the explanation accumulated so far. + void Clear() { ss_.str(""); } + + private: + ::std::stringstream ss_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); +}; + +namespace internal { + +struct AnyEq { + template + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(NULL) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase { + public: + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true iff this matcher matches x. + bool Matches(T x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(T x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface* impl) + : impl_(impl) {} + + virtual ~MatcherBase() {} + + private: + // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar + // interfaces. The former dynamically allocates a chunk of memory + // to hold the reference count, while the latter tracks all + // references using a circular linked list without allocating + // memory. It has been observed that linked_ptr performs better in + // typical scenarios. However, shared_ptr can out-perform + // linked_ptr when there are many more uses of the copy constructor + // than the default constructor. + // + // If performance becomes a problem, we should see if using + // shared_ptr helps. + ::testing::internal::linked_ptr > impl_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a linked_ptr to const +// MatcherInterface, so copying is fairly cheap. Don't inherit +// from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_HAS_STRING_PIECE_ +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a StringPiece +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass StringPieces directly. + Matcher(StringPiece s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const internal::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass StringPieces directly. + Matcher(StringPiece s); // NOLINT +}; +#endif // GTEST_HAS_STRING_PIECE_ + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual void DescribeTo(::std::ostream* os) const { + impl_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + + GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); + }; + + Impl impl_; + + GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher); +}; + +// Creates a matcher from its implementation. This is easier to use +// than the Matcher constructor as it doesn't require you to +// explicitly write the template argument, e.g. +// +// MakeMatcher(foo); +// vs +// Matcher(foo); +template +inline Matcher MakeMatcher(const MatcherInterface* impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher(impl); +} + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +// The MatcherCastImpl class template is a helper for implementing +// MatcherCast(). We need this helper in order to partially +// specialize the implementation of MatcherCast() (C++ allows +// class/struct templates to be partially specialized, but not +// function templates.). + +// This general version is used when MatcherCast()'s argument is a +// polymorphic matcher (i.e. something that can be converted to a +// Matcher but is not one yet; for example, Eq(value)) or a value (for +// example, "hello"). +template +class MatcherCastImpl { + public: + static Matcher Cast(const M& polymorphic_matcher_or_value) { + // M can be a polymorhic matcher, in which case we want to use + // its conversion operator to create Matcher. Or it can be a value + // that should be passed to the Matcher's constructor. + // + // We can't call Matcher(polymorphic_matcher_or_value) when M is a + // polymorphic matcher because it'll be ambiguous if T has an implicit + // constructor from M (this usually happens when T has an implicit + // constructor from any type). + // + // It won't work to unconditionally implict_cast + // polymorphic_matcher_or_value to Matcher because it won't trigger + // a user-defined conversion from M to T if one exists (assuming M is + // a value). + return CastImpl( + polymorphic_matcher_or_value, + BooleanConstant< + internal::ImplicitlyConvertible >::value>()); + } + + private: + static Matcher CastImpl(const M& value, BooleanConstant) { + // M can't be implicitly converted to Matcher, so M isn't a polymorphic + // matcher. It must be a value then. Use direct initialization to create + // a matcher. + return Matcher(ImplicitCast_(value)); + } + + static Matcher CastImpl(const M& polymorphic_matcher_or_value, + BooleanConstant) { + // M is implicitly convertible to Matcher, which means that either + // M is a polymorhpic matcher or Matcher has an implicit constructor + // from M. In both cases using the implicit conversion will produce a + // matcher. + // + // Even if T has an implicit constructor from M, it won't be called because + // creating Matcher would require a chain of two user-defined conversions + // (first to create T from M and then to create Matcher from T). + return polymorphic_matcher_or_value; + } +}; + +// This more specialized version is used when MatcherCast()'s argument +// is already a Matcher. This only compiles when type T can be +// statically converted to type U. +template +class MatcherCastImpl > { + public: + static Matcher Cast(const Matcher& source_matcher) { + return Matcher(new Impl(source_matcher)); + } + + private: + class Impl : public MatcherInterface { + public: + explicit Impl(const Matcher& source_matcher) + : source_matcher_(source_matcher) {} + + // We delegate the matching logic to the source matcher. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return source_matcher_.MatchAndExplain(static_cast(x), listener); + } + + virtual void DescribeTo(::std::ostream* os) const { + source_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + source_matcher_.DescribeNegationTo(os); + } + + private: + const Matcher source_matcher_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; +}; + +// This even more specialized version is used for efficiently casting +// a matcher to its own type. +template +class MatcherCastImpl > { + public: + static Matcher Cast(const Matcher& matcher) { return matcher; } +}; + +} // namespace internal + +// In order to be safe and clear, casting between different matcher +// types is done explicitly via MatcherCast(m), which takes a +// matcher m and returns a Matcher. It compiles only when T can be +// statically converted to the argument type of m. +template +inline Matcher MatcherCast(const M& matcher) { + return internal::MatcherCastImpl::Cast(matcher); +} + +// Implements SafeMatcherCast(). +// +// We use an intermediate class to do the actual safe casting as Nokia's +// Symbian compiler cannot decide between +// template ... (M) and +// template ... (const Matcher&) +// for function templates but can for member function templates. +template +class SafeMatcherCastImpl { + public: + // This overload handles polymorphic matchers and values only since + // monomorphic matchers are handled by the next one. + template + static inline Matcher Cast(const M& polymorphic_matcher_or_value) { + return internal::MatcherCastImpl::Cast(polymorphic_matcher_or_value); + } + + // This overload handles monomorphic matchers. + // + // In general, if type T can be implicitly converted to type U, we can + // safely convert a Matcher to a Matcher (i.e. Matcher is + // contravariant): just keep a copy of the original Matcher, convert the + // argument from type T to U, and then pass it to the underlying Matcher. + // The only exception is when U is a reference and T is not, as the + // underlying Matcher may be interested in the argument's address, which + // is not preserved in the conversion from T to U. + template + static inline Matcher Cast(const Matcher& matcher) { + // Enforce that T can be implicitly converted to U. + GTEST_COMPILE_ASSERT_((internal::ImplicitlyConvertible::value), + T_must_be_implicitly_convertible_to_U); + // Enforce that we are not converting a non-reference type T to a reference + // type U. + GTEST_COMPILE_ASSERT_( + internal::is_reference::value || !internal::is_reference::value, + cannot_convert_non_referentce_arg_to_reference); + // In case both T and U are arithmetic types, enforce that the + // conversion is not lossy. + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU; + const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; + const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; + GTEST_COMPILE_ASSERT_( + kTIsOther || kUIsOther || + (internal::LosslessArithmeticConvertible::value), + conversion_of_arithmetic_types_must_be_lossless); + return MatcherCast(matcher); + } +}; + +template +inline Matcher SafeMatcherCast(const M& polymorphic_matcher) { + return SafeMatcherCastImpl::Cast(polymorphic_matcher); +} + +// A() returns a matcher that matches any value of type T. +template +Matcher A(); + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +// If the explanation is not empty, prints it to the ostream. +inline void PrintIfNotEmpty(const internal::string& explanation, + ::std::ostream* os) { + if (explanation != "" && os != NULL) { + *os << ", " << explanation; + } +} + +// Returns true if the given type name is easy to read by a human. +// This is used to decide whether printing the type of a value might +// be helpful. +inline bool IsReadableTypeName(const string& type_name) { + // We consider a type name readable if it's short or doesn't contain + // a template or function type. + return (type_name.length() <= 20 || + type_name.find_first_of("<(") == string::npos); +} + +// Matches the value against the given matcher, prints the value and explains +// the match result to the listener. Returns the match result. +// 'listener' must not be NULL. +// Value cannot be passed by const reference, because some matchers take a +// non-const argument. +template +bool MatchPrintAndExplain(Value& value, const Matcher& matcher, + MatchResultListener* listener) { + if (!listener->IsInterested()) { + // If the listener is not interested, we do not need to construct the + // inner explanation. + return matcher.Matches(value); + } + + StringMatchResultListener inner_listener; + const bool match = matcher.MatchAndExplain(value, &inner_listener); + + UniversalPrint(value, listener->stream()); +#if GTEST_HAS_RTTI + const string& type_name = GetTypeName(); + if (IsReadableTypeName(type_name)) + *listener->stream() << " (of type " << type_name << ")"; +#endif + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + + return match; +} + +// An internal helper class for doing compile-time loop on a tuple's +// fields. +template +class TuplePrefix { + public: + // TuplePrefix::Matches(matcher_tuple, value_tuple) returns true + // iff the first N fields of matcher_tuple matches the first N + // fields of value_tuple, respectively. + template + static bool Matches(const MatcherTuple& matcher_tuple, + const ValueTuple& value_tuple) { + return TuplePrefix::Matches(matcher_tuple, value_tuple) + && get(matcher_tuple).Matches(get(value_tuple)); + } + + // TuplePrefix::ExplainMatchFailuresTo(matchers, values, os) + // describes failures in matching the first N fields of matchers + // against the first N fields of values. If there is no failure, + // nothing will be streamed to os. + template + static void ExplainMatchFailuresTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { + // First, describes failures in the first N - 1 fields. + TuplePrefix::ExplainMatchFailuresTo(matchers, values, os); + + // Then describes the failure (if any) in the (N - 1)-th (0-based) + // field. + typename tuple_element::type matcher = + get(matchers); + typedef typename tuple_element::type Value; + Value value = get(values); + StringMatchResultListener listener; + if (!matcher.MatchAndExplain(value, &listener)) { + // TODO(wan): include in the message the name of the parameter + // as used in MOCK_METHOD*() when possible. + *os << " Expected arg #" << N - 1 << ": "; + get(matchers).DescribeTo(os); + *os << "\n Actual: "; + // We remove the reference in type Value to prevent the + // universal printer from printing the address of value, which + // isn't interesting to the user most of the time. The + // matcher's MatchAndExplain() method handles the case when + // the address is interesting. + internal::UniversalPrint(value, os); + PrintIfNotEmpty(listener.str(), os); + *os << "\n"; + } + } +}; + +// The base case. +template <> +class TuplePrefix<0> { + public: + template + static bool Matches(const MatcherTuple& /* matcher_tuple */, + const ValueTuple& /* value_tuple */) { + return true; + } + + template + static void ExplainMatchFailuresTo(const MatcherTuple& /* matchers */, + const ValueTuple& /* values */, + ::std::ostream* /* os */) {} +}; + +// TupleMatches(matcher_tuple, value_tuple) returns true iff all +// matchers in matcher_tuple match the corresponding fields in +// value_tuple. It is a compiler error if matcher_tuple and +// value_tuple have different number of fields or incompatible field +// types. +template +bool TupleMatches(const MatcherTuple& matcher_tuple, + const ValueTuple& value_tuple) { + // Makes sure that matcher_tuple and value_tuple have the same + // number of fields. + GTEST_COMPILE_ASSERT_(tuple_size::value == + tuple_size::value, + matcher_and_value_have_different_numbers_of_fields); + return TuplePrefix::value>:: + Matches(matcher_tuple, value_tuple); +} + +// Describes failures in matching matchers against values. If there +// is no failure, nothing will be streamed to os. +template +void ExplainMatchFailureTupleTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { + TuplePrefix::value>::ExplainMatchFailuresTo( + matchers, values, os); +} + +// TransformTupleValues and its helper. +// +// TransformTupleValuesHelper hides the internal machinery that +// TransformTupleValues uses to implement a tuple traversal. +template +class TransformTupleValuesHelper { + private: + typedef ::testing::tuple_size TupleSize; + + public: + // For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'. + // Returns the final value of 'out' in case the caller needs it. + static OutIter Run(Func f, const Tuple& t, OutIter out) { + return IterateOverTuple()(f, t, out); + } + + private: + template + struct IterateOverTuple { + OutIter operator() (Func f, const Tup& t, OutIter out) const { + *out++ = f(::testing::get(t)); + return IterateOverTuple()(f, t, out); + } + }; + template + struct IterateOverTuple { + OutIter operator() (Func /* f */, const Tup& /* t */, OutIter out) const { + return out; + } + }; +}; + +// Successively invokes 'f(element)' on each element of the tuple 't', +// appending each result to the 'out' iterator. Returns the final value +// of 'out'. +template +OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) { + return TransformTupleValuesHelper::Run(f, t, out); +} + +// Implements A(). +template +class AnyMatcherImpl : public MatcherInterface { + public: + virtual bool MatchAndExplain( + T /* x */, MatchResultListener* /* listener */) const { return true; } + virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; } + virtual void DescribeNegationTo(::std::ostream* os) const { + // This is mostly for completeness' safe, as it's not very useful + // to write Not(A()). However we cannot completely rule out + // such a possibility, and it doesn't hurt to be prepared. + *os << "never matches"; + } +}; + +// Implements _, a matcher that matches any value of any +// type. This is a polymorphic matcher, so we need a template type +// conversion operator to make it appearing as a Matcher for any +// type T. +class AnythingMatcher { + public: + template + operator Matcher() const { return A(); } +}; + +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + template + operator Matcher() const { + return MakeMatcher(new Impl(rhs_)); + } + + private: + template + class Impl : public MatcherInterface { + public: + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} + virtual bool MatchAndExplain( + Lhs lhs, MatchResultListener* /* listener */) const { + return Op()(lhs, rhs_); + } + virtual void DescribeTo(::std::ostream* os) const { + *os << D::Desc() << " "; + UniversalPrint(rhs_, os); + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << D::NegatedDesc() << " "; + UniversalPrint(rhs_, os); + } + private: + Rhs rhs_; + GTEST_DISALLOW_ASSIGN_(Impl); + }; + Rhs rhs_; + GTEST_DISALLOW_ASSIGN_(ComparisonBase); +}; + +template +class EqMatcher : public ComparisonBase, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template +class NeMatcher : public ComparisonBase, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template +class LtMatcher : public ComparisonBase, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template +class GtMatcher : public ComparisonBase, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template +class LeMatcher : public ComparisonBase, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template +class GeMatcher : public ComparisonBase, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; + +// Implements the polymorphic IsNull() matcher, which matches any raw or smart +// pointer that is NULL. +class IsNullMatcher { + public: + template + bool MatchAndExplain(const Pointer& p, + MatchResultListener* /* listener */) const { +#if GTEST_LANG_CXX11 + return p == nullptr; +#else // GTEST_LANG_CXX11 + return GetRawPointer(p) == NULL; +#endif // GTEST_LANG_CXX11 + } + + void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } + void DescribeNegationTo(::std::ostream* os) const { + *os << "isn't NULL"; + } +}; + +// Implements the polymorphic NotNull() matcher, which matches any raw or smart +// pointer that is not NULL. +class NotNullMatcher { + public: + template + bool MatchAndExplain(const Pointer& p, + MatchResultListener* /* listener */) const { +#if GTEST_LANG_CXX11 + return p != nullptr; +#else // GTEST_LANG_CXX11 + return GetRawPointer(p) != NULL; +#endif // GTEST_LANG_CXX11 + } + + void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; } + void DescribeNegationTo(::std::ostream* os) const { + *os << "is NULL"; + } +}; + +// Ref(variable) matches any argument that is a reference to +// 'variable'. This matcher is polymorphic as it can match any +// super type of the type of 'variable'. +// +// The RefMatcher template class implements Ref(variable). It can +// only be instantiated with a reference type. This prevents a user +// from mistakenly using Ref(x) to match a non-reference function +// argument. For example, the following will righteously cause a +// compiler error: +// +// int n; +// Matcher m1 = Ref(n); // This won't compile. +// Matcher m2 = Ref(n); // This will compile. +template +class RefMatcher; + +template +class RefMatcher { + // Google Mock is a generic framework and thus needs to support + // mocking any function types, including those that take non-const + // reference arguments. Therefore the template parameter T (and + // Super below) can be instantiated to either a const type or a + // non-const type. + public: + // RefMatcher() takes a T& instead of const T&, as we want the + // compiler to catch using Ref(const_value) as a matcher for a + // non-const reference. + explicit RefMatcher(T& x) : object_(x) {} // NOLINT + + template + operator Matcher() const { + // By passing object_ (type T&) to Impl(), which expects a Super&, + // we make sure that Super is a super type of T. In particular, + // this catches using Ref(const_value) as a matcher for a + // non-const reference, as you cannot implicitly convert a const + // reference to a non-const reference. + return MakeMatcher(new Impl(object_)); + } + + private: + template + class Impl : public MatcherInterface { + public: + explicit Impl(Super& x) : object_(x) {} // NOLINT + + // MatchAndExplain() takes a Super& (as opposed to const Super&) + // in order to match the interface MatcherInterface. + virtual bool MatchAndExplain( + Super& x, MatchResultListener* listener) const { + *listener << "which is located @" << static_cast(&x); + return &x == &object_; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "references the variable "; + UniversalPrinter::Print(object_, os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "does not reference the variable "; + UniversalPrinter::Print(object_, os); + } + + private: + const Super& object_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + T& object_; + + GTEST_DISALLOW_ASSIGN_(RefMatcher); +}; + +// Polymorphic helper functions for narrow and wide string matchers. +inline bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs) { + return String::CaseInsensitiveCStringEquals(lhs, rhs); +} + +inline bool CaseInsensitiveCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + return String::CaseInsensitiveWideCStringEquals(lhs, rhs); +} + +// String comparison for narrow or wide strings that can have embedded NUL +// characters. +template +bool CaseInsensitiveStringEquals(const StringType& s1, + const StringType& s2) { + // Are the heads equal? + if (!CaseInsensitiveCStringEquals(s1.c_str(), s2.c_str())) { + return false; + } + + // Skip the equal heads. + const typename StringType::value_type nul = 0; + const size_t i1 = s1.find(nul), i2 = s2.find(nul); + + // Are we at the end of either s1 or s2? + if (i1 == StringType::npos || i2 == StringType::npos) { + return i1 == i2; + } + + // Are the tails equal? + return CaseInsensitiveStringEquals(s1.substr(i1 + 1), s2.substr(i2 + 1)); +} + +// String matchers. + +// Implements equality-based string matchers like StrEq, StrCaseNe, and etc. +template +class StrEqualityMatcher { + public: + StrEqualityMatcher(const StringType& str, bool expect_eq, + bool case_sensitive) + : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + if (s == NULL) { + return !expect_eq_; + } + return MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + const bool eq = case_sensitive_ ? s2 == string_ : + CaseInsensitiveStringEquals(s2, string_); + return expect_eq_ == eq; + } + + void DescribeTo(::std::ostream* os) const { + DescribeToHelper(expect_eq_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + DescribeToHelper(!expect_eq_, os); + } + + private: + void DescribeToHelper(bool expect_eq, ::std::ostream* os) const { + *os << (expect_eq ? "is " : "isn't "); + *os << "equal to "; + if (!case_sensitive_) { + *os << "(ignoring case) "; + } + UniversalPrint(string_, os); + } + + const StringType string_; + const bool expect_eq_; + const bool case_sensitive_; + + GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher); +}; + +// Implements the polymorphic HasSubstr(substring) matcher, which +// can be used as a Matcher as long as T can be converted to a +// string. +template +class HasSubstrMatcher { + public: + explicit HasSubstrMatcher(const StringType& substring) + : substring_(substring) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + return s2.find(substring_) != StringType::npos; + } + + // Describes what this matcher matches. + void DescribeTo(::std::ostream* os) const { + *os << "has substring "; + UniversalPrint(substring_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "has no substring "; + UniversalPrint(substring_, os); + } + + private: + const StringType substring_; + + GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher); +}; + +// Implements the polymorphic StartsWith(substring) matcher, which +// can be used as a Matcher as long as T can be converted to a +// string. +template +class StartsWithMatcher { + public: + explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) { + } + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + return s2.length() >= prefix_.length() && + s2.substr(0, prefix_.length()) == prefix_; + } + + void DescribeTo(::std::ostream* os) const { + *os << "starts with "; + UniversalPrint(prefix_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't start with "; + UniversalPrint(prefix_, os); + } + + private: + const StringType prefix_; + + GTEST_DISALLOW_ASSIGN_(StartsWithMatcher); +}; + +// Implements the polymorphic EndsWith(substring) matcher, which +// can be used as a Matcher as long as T can be converted to a +// string. +template +class EndsWithMatcher { + public: + explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); + } + + // Matches anything that can convert to StringType. + // + // This is a template, not just a plain function with const StringType&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const StringType& s2(s); + return s2.length() >= suffix_.length() && + s2.substr(s2.length() - suffix_.length()) == suffix_; + } + + void DescribeTo(::std::ostream* os) const { + *os << "ends with "; + UniversalPrint(suffix_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't end with "; + UniversalPrint(suffix_, os); + } + + private: + const StringType suffix_; + + GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(internal::string(s), listener); + } + + // Matches anything that can convert to internal::string. + // + // This is a template, not just a plain function with const internal::string&, + // because StringPiece has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const internal::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) : + RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const internal::linked_ptr regex_; + const bool full_match_; + + GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); +}; + +// Implements a matcher that compares the two fields of a 2-tuple +// using one of the ==, <=, <, etc, operators. The two fields being +// compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq() can be +// used to match a tuple, a tuple, +// etc). Therefore we use a template type conversion operator in the +// implementation. +template +class PairMatchBase { + public: + template + operator Matcher< ::testing::tuple >() const { + return MakeMatcher(new Impl< ::testing::tuple >); + } + template + operator Matcher&>() const { + return MakeMatcher(new Impl&>); + } + + private: + static ::std::ostream& GetDesc(::std::ostream& os) { // NOLINT + return os << D::Desc(); + } + + template + class Impl : public MatcherInterface { + public: + virtual bool MatchAndExplain( + Tuple args, + MatchResultListener* /* listener */) const { + return Op()(::testing::get<0>(args), ::testing::get<1>(args)); + } + virtual void DescribeTo(::std::ostream* os) const { + *os << "are " << GetDesc; + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "aren't " << GetDesc; + } + }; +}; + +class Eq2Matcher : public PairMatchBase { + public: + static const char* Desc() { return "an equal pair"; } +}; +class Ne2Matcher : public PairMatchBase { + public: + static const char* Desc() { return "an unequal pair"; } +}; +class Lt2Matcher : public PairMatchBase { + public: + static const char* Desc() { return "a pair where the first < the second"; } +}; +class Gt2Matcher : public PairMatchBase { + public: + static const char* Desc() { return "a pair where the first > the second"; } +}; +class Le2Matcher : public PairMatchBase { + public: + static const char* Desc() { return "a pair where the first <= the second"; } +}; +class Ge2Matcher : public PairMatchBase { + public: + static const char* Desc() { return "a pair where the first >= the second"; } +}; + +// Implements the Not(...) matcher for a particular argument type T. +// We do not nest it inside the NotMatcher class template, as that +// will prevent different instantiations of NotMatcher from sharing +// the same NotMatcherImpl class. +template +class NotMatcherImpl : public MatcherInterface { + public: + explicit NotMatcherImpl(const Matcher& matcher) + : matcher_(matcher) {} + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return !matcher_.MatchAndExplain(x, listener); + } + + virtual void DescribeTo(::std::ostream* os) const { + matcher_.DescribeNegationTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + matcher_.DescribeTo(os); + } + + private: + const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(NotMatcherImpl); +}; + +// Implements the Not(m) matcher, which matches a value that doesn't +// match matcher m. +template +class NotMatcher { + public: + explicit NotMatcher(InnerMatcher matcher) : matcher_(matcher) {} + + // This template type conversion operator allows Not(m) to be used + // to match any type m can match. + template + operator Matcher() const { + return Matcher(new NotMatcherImpl(SafeMatcherCast(matcher_))); + } + + private: + InnerMatcher matcher_; + + GTEST_DISALLOW_ASSIGN_(NotMatcher); +}; + +// Implements the AllOf(m1, m2) matcher for a particular argument type +// T. We do not nest it inside the BothOfMatcher class template, as +// that will prevent different instantiations of BothOfMatcher from +// sharing the same BothOfMatcherImpl class. +template +class BothOfMatcherImpl : public MatcherInterface { + public: + BothOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) + : matcher1_(matcher1), matcher2_(matcher2) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeTo(os); + *os << ") and ("; + matcher2_.DescribeTo(os); + *os << ")"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeNegationTo(os); + *os << ") or ("; + matcher2_.DescribeNegationTo(os); + *os << ")"; + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + // If either matcher1_ or matcher2_ doesn't match x, we only need + // to explain why one of them fails. + StringMatchResultListener listener1; + if (!matcher1_.MatchAndExplain(x, &listener1)) { + *listener << listener1.str(); + return false; + } + + StringMatchResultListener listener2; + if (!matcher2_.MatchAndExplain(x, &listener2)) { + *listener << listener2.str(); + return false; + } + + // Otherwise we need to explain why *both* of them match. + const internal::string s1 = listener1.str(); + const internal::string s2 = listener2.str(); + + if (s1 == "") { + *listener << s2; + } else { + *listener << s1; + if (s2 != "") { + *listener << ", and " << s2; + } + } + return true; + } + + private: + const Matcher matcher1_; + const Matcher matcher2_; + + GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl); +}; + +#if GTEST_LANG_CXX11 +// MatcherList provides mechanisms for storing a variable number of matchers in +// a list structure (ListType) and creating a combining matcher from such a +// list. +// The template is defined recursively using the following template paramters: +// * kSize is the length of the MatcherList. +// * Head is the type of the first matcher of the list. +// * Tail denotes the types of the remaining matchers of the list. +template +struct MatcherList { + typedef MatcherList MatcherListTail; + typedef ::std::pair ListType; + + // BuildList stores variadic type values in a nested pair structure. + // Example: + // MatcherList<3, int, string, float>::BuildList(5, "foo", 2.0) will return + // the corresponding result of type pair>. + static ListType BuildList(const Head& matcher, const Tail&... tail) { + return ListType(matcher, MatcherListTail::BuildList(tail...)); + } + + // CreateMatcher creates a Matcher from a given list of matchers (built + // by BuildList()). CombiningMatcher is used to combine the matchers of the + // list. CombiningMatcher must implement MatcherInterface and have a + // constructor taking two Matchers as input. + template class CombiningMatcher> + static Matcher CreateMatcher(const ListType& matchers) { + return Matcher(new CombiningMatcher( + SafeMatcherCast(matchers.first), + MatcherListTail::template CreateMatcher( + matchers.second))); + } +}; + +// The following defines the base case for the recursive definition of +// MatcherList. +template +struct MatcherList<2, Matcher1, Matcher2> { + typedef ::std::pair ListType; + + static ListType BuildList(const Matcher1& matcher1, + const Matcher2& matcher2) { + return ::std::pair(matcher1, matcher2); + } + + template class CombiningMatcher> + static Matcher CreateMatcher(const ListType& matchers) { + return Matcher(new CombiningMatcher( + SafeMatcherCast(matchers.first), + SafeMatcherCast(matchers.second))); + } +}; + +// VariadicMatcher is used for the variadic implementation of +// AllOf(m_1, m_2, ...) and AnyOf(m_1, m_2, ...). +// CombiningMatcher is used to recursively combine the provided matchers +// (of type Args...). +template