From e35fdd936d133bf8a48de140a3c666897588a053 Mon Sep 17 00:00:00 2001 From: shiqian Date: Wed, 10 Dec 2008 05:08:54 +0000 Subject: Initial drop of Google Mock. The files are incomplete and thus may not build correctly yet. --- CHANGES | 3 + CONTRIBUTORS | 37 + COPYING | 28 + Makefile.am | 181 ++ README | 242 ++ build-aux/.keep | 0 configure.ac | 115 + include/gmock/gmock-actions.h | 900 +++++++ include/gmock/gmock-cardinalities.h | 146 ++ include/gmock/gmock-generated-actions.h | 1329 ++++++++++ include/gmock/gmock-generated-actions.h.pump | 567 +++++ include/gmock/gmock-generated-function-mockers.h | 706 ++++++ .../gmock/gmock-generated-function-mockers.h.pump | 200 ++ include/gmock/gmock-generated-matchers.h | 650 +++++ include/gmock/gmock-generated-matchers.h.pump | 303 +++ include/gmock/gmock-generated-nice-strict.h | 244 ++ include/gmock/gmock-generated-nice-strict.h.pump | 146 ++ include/gmock/gmock-matchers.h | 2094 ++++++++++++++++ include/gmock/gmock-printers.h | 514 ++++ include/gmock/gmock-spec-builders.h | 1568 ++++++++++++ include/gmock/gmock.h | 92 + .../internal/gmock-generated-internal-utils.h | 277 +++ .../internal/gmock-generated-internal-utils.h.pump | 136 + include/gmock/internal/gmock-internal-utils.h | 339 +++ include/gmock/internal/gmock-port.h | 314 +++ make/Makefile | 109 + scripts/generator/COPYING | 203 ++ scripts/generator/README | 33 + scripts/generator/README.cppclean | 115 + scripts/generator/cpp/__init__.py | 0 scripts/generator/cpp/ast.py | 1713 +++++++++++++ scripts/generator/cpp/gmock_class.py | 148 ++ scripts/generator/cpp/keywords.py | 58 + scripts/generator/cpp/tokenize.py | 287 +++ scripts/generator/cpp/utils.py | 41 + scripts/generator/gmock_gen.py | 31 + scripts/gmock_doctor.py | 376 +++ src/gmock-all.cc | 43 + src/gmock-cardinalities.cc | 155 ++ src/gmock-internal-utils.cc | 135 + src/gmock-matchers.cc | 61 + src/gmock-printers.cc | 309 +++ src/gmock-spec-builders.cc | 337 +++ src/gmock.cc | 155 ++ src/gmock_main.cc | 43 + test/gmock-actions_test.cc | 902 +++++++ test/gmock-cardinalities_test.cc | 422 ++++ test/gmock-generated-actions_test.cc | 946 +++++++ test/gmock-generated-function-mockers_test.cc | 426 ++++ test/gmock-generated-internal-utils_test.cc | 127 + test/gmock-generated-matchers_test.cc | 373 +++ test/gmock-internal-utils_test.cc | 521 ++++ test/gmock-matchers_test.cc | 2629 ++++++++++++++++++++ test/gmock-nice-strict_test.cc | 228 ++ test/gmock-port_test.cc | 95 + test/gmock-printers_test.cc | 903 +++++++ test/gmock-sample.cc | 32 + test/gmock-sample.h | 49 + test/gmock-spec-builders_test.cc | 1889 ++++++++++++++ test/gmock_link_test.cc | 37 + test/gmock_output_test.py | 200 ++ test/gmock_output_test_.cc | 241 ++ test/gmock_output_test_golden.txt | 296 +++ test/gmock_test.cc | 248 ++ test/gmock_test_utils.py | 126 + 65 files changed, 26173 insertions(+) create mode 100644 CHANGES create mode 100644 CONTRIBUTORS create mode 100644 COPYING create mode 100644 Makefile.am create mode 100644 README create mode 100644 build-aux/.keep create mode 100644 configure.ac create mode 100644 include/gmock/gmock-actions.h create mode 100644 include/gmock/gmock-cardinalities.h create mode 100644 include/gmock/gmock-generated-actions.h create mode 100644 include/gmock/gmock-generated-actions.h.pump create mode 100644 include/gmock/gmock-generated-function-mockers.h create mode 100644 include/gmock/gmock-generated-function-mockers.h.pump create mode 100644 include/gmock/gmock-generated-matchers.h create mode 100644 include/gmock/gmock-generated-matchers.h.pump create mode 100644 include/gmock/gmock-generated-nice-strict.h create mode 100644 include/gmock/gmock-generated-nice-strict.h.pump create mode 100644 include/gmock/gmock-matchers.h create mode 100644 include/gmock/gmock-printers.h create mode 100644 include/gmock/gmock-spec-builders.h create mode 100644 include/gmock/gmock.h create mode 100644 include/gmock/internal/gmock-generated-internal-utils.h create mode 100644 include/gmock/internal/gmock-generated-internal-utils.h.pump create mode 100644 include/gmock/internal/gmock-internal-utils.h create mode 100644 include/gmock/internal/gmock-port.h create mode 100644 make/Makefile create mode 100644 scripts/generator/COPYING create mode 100644 scripts/generator/README create mode 100644 scripts/generator/README.cppclean create mode 100755 scripts/generator/cpp/__init__.py create mode 100755 scripts/generator/cpp/ast.py create mode 100755 scripts/generator/cpp/gmock_class.py create mode 100755 scripts/generator/cpp/keywords.py create mode 100755 scripts/generator/cpp/tokenize.py create mode 100755 scripts/generator/cpp/utils.py create mode 100755 scripts/generator/gmock_gen.py create mode 100755 scripts/gmock_doctor.py create mode 100644 src/gmock-all.cc create mode 100644 src/gmock-cardinalities.cc create mode 100644 src/gmock-internal-utils.cc create mode 100644 src/gmock-matchers.cc create mode 100644 src/gmock-printers.cc create mode 100644 src/gmock-spec-builders.cc create mode 100644 src/gmock.cc create mode 100644 src/gmock_main.cc create mode 100644 test/gmock-actions_test.cc create mode 100644 test/gmock-cardinalities_test.cc create mode 100644 test/gmock-generated-actions_test.cc create mode 100644 test/gmock-generated-function-mockers_test.cc create mode 100644 test/gmock-generated-internal-utils_test.cc create mode 100644 test/gmock-generated-matchers_test.cc create mode 100644 test/gmock-internal-utils_test.cc create mode 100644 test/gmock-matchers_test.cc create mode 100644 test/gmock-nice-strict_test.cc create mode 100644 test/gmock-port_test.cc create mode 100644 test/gmock-printers_test.cc create mode 100644 test/gmock-sample.cc create mode 100644 test/gmock-sample.h create mode 100644 test/gmock-spec-builders_test.cc create mode 100644 test/gmock_link_test.cc create mode 100755 test/gmock_output_test.py create mode 100644 test/gmock_output_test_.cc create mode 100644 test/gmock_output_test_golden.txt create mode 100644 test/gmock_test.cc create mode 100755 test/gmock_test_utils.py diff --git a/CHANGES b/CHANGES new file mode 100644 index 00000000..be9b0ac2 --- /dev/null +++ b/CHANGES @@ -0,0 +1,3 @@ +Changes for 1.0.0: + + * Initial Open Source release of Google Mock diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 00000000..50209471 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,37 @@ +# 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 +Mario Tanev +Mark Paskin +Markus Heule +Matthew Simmons +Mike Bland +Neal Norwitz +Owen Carlsen +Paneendra Ba +Paul Menage +Piotr Kaminski +Russ Rufer +Takeshi Yoshino +Vadim Berman +Vlad Losev +Wolfgang Klier +Zhanyong Wan diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..1941a11f --- /dev/null +++ b/COPYING @@ -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/Makefile.am b/Makefile.am new file mode 100644 index 00000000..6e6b6ec2 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,181 @@ +# Nonstandard package files for distribution. +EXTRA_DIST = + +# Scripts and utilities to be installed by 'make install'. +dist_bin_SCRIPTS = scripts/gmock_doctor.py + +# We define the global AM_CPPFLAGS as everything we compile includes from these +# directories. +AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include + +# Build rules for libraries. +lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la + +lib_libgmock_la_SOURCES = src/gmock.cc \ + src/gmock-cardinalities.cc \ + src/gmock-internal-utils.cc \ + src/gmock-matchers.cc \ + src/gmock-printers.cc \ + src/gmock-spec-builders.cc + +pkginclude_HEADERS = include/gmock/gmock.h \ + 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-printers.h \ + include/gmock/gmock-spec-builders.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 + +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= +TESTS_ENVIRONMENT = GMOCK_SOURCE_DIR="$(srcdir)/test" \ + GMOCK_BUILD_DIR="$(top_builddir)/test" +check_PROGRAMS= +AM_LDFLAGS = $(GTEST_LDFLAGS) + +TESTS += test/gmock-actions_test +check_PROGRAMS += test/gmock-actions_test +test_gmock_actions_test_SOURCES = test/gmock-actions_test.cc +test_gmock_actions_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-cardinalities_test +check_PROGRAMS += test/gmock-cardinalities_test +test_gmock_cardinalities_test_SOURCES = test/gmock-cardinalities_test.cc +test_gmock_cardinalities_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-generated-actions_test +check_PROGRAMS += test/gmock-generated-actions_test +test_gmock_generated_actions_test_SOURCES = test/gmock-generated-actions_test.cc +test_gmock_generated_actions_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-generated-function-mockers_test +check_PROGRAMS += test/gmock-generated-function-mockers_test +test_gmock_generated_function_mockers_test_SOURCES = \ + test/gmock-generated-function-mockers_test.cc +test_gmock_generated_function_mockers_test_LDADD = $(GTEST_LIBS) \ + lib/libgmock_main.la + +TESTS += test/gmock-generated-internal-utils_test +check_PROGRAMS += test/gmock-generated-internal-utils_test +test_gmock_generated_internal_utils_test_SOURCES = \ + test/gmock-generated-internal-utils_test.cc +test_gmock_generated_internal_utils_test_LDADD = $(GTEST_LIBS) \ + lib/libgmock_main.la + +TESTS += test/gmock-generated-matchers_test +check_PROGRAMS += test/gmock-generated-matchers_test +test_gmock_generated_matchers_test_SOURCES = \ + test/gmock-generated-matchers_test.cc +test_gmock_generated_matchers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-internal-utils_test +check_PROGRAMS += test/gmock-internal-utils_test +test_gmock_internal_utils_test_SOURCES = test/gmock-internal-utils_test.cc +test_gmock_internal_utils_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock_link_test +check_PROGRAMS += test/gmock_link_test +test_gmock_link_test_SOURCES = test/gmock_link_test.cc \ + test/gmock-sample.cc \ + test/gmock-sample.h +test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-matchers_test +check_PROGRAMS += test/gmock-matchers_test +test_gmock_matchers_test_SOURCES = test/gmock-matchers_test.cc +test_gmock_matchers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-nice-strict_test +check_PROGRAMS += test/gmock-nice-strict_test +test_gmock_nice_strict_test_SOURCES = test/gmock-nice-strict_test.cc +test_gmock_nice_strict_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-port_test +check_PROGRAMS += test/gmock-port_test +test_gmock_port_test_SOURCES = test/gmock-port_test.cc +test_gmock_port_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +TESTS += test/gmock-printers_test +check_PROGRAMS += test/gmock-printers_test +test_gmock_printers_test_SOURCES = test/gmock-printers_test.cc +test_gmock_printers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +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_main.la + +TESTS += test/gmock_test +check_PROGRAMS += test/gmock_test +test_gmock_test_SOURCES = test/gmock_test.cc +test_gmock_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + +# The following tests depend on the presence of a Python installation and are +# keyed off of it. We only add them to the TESTS variable when a Python +# interpreter is available. TODO(chandlerc@google.com): While we currently only +# attempt to build and execute these tests if Autoconf has found Python v2.3 on +# the system, we don't use the PYTHON variable it specified as the valid +# interpreter. The problem is that TESTS_ENVIRONMENT is a global variable, and +# thus we cannot distinguish between C++ unit tests and Python unit tests. +dist_check_SCRIPTS = + +# Python modules used by multiple Python tests below. +dist_check_SCRIPTS += test/gmock_test_utils.py + +check_PROGRAMS += test/gmock_output_test_ +test_gmock_output_test__SOURCES = test/gmock_output_test_.cc +test_gmock_output_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la +dist_check_SCRIPTS += test/gmock_output_test.py +EXTRA_DIST += test/gmock_output_test_golden.txt + +# Enable all the python driven tests when we can run them. +if HAVE_PYTHON +TESTS += test/gmock_output_test.py +endif + +# Nonstandard package files for distribution. +EXTRA_DIST += \ + CHANGES \ + CONTRIBUTORS \ + make/Makefile \ + src/gmock-all.cc + +# 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 + +# The Google Mock Generator tool from the cppclean project. +EXTRA_DIST += \ + scripts/generator/COPYING \ + 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 + +# TODO(wan@google.com): add the MSVC projects to EXTRA_DIST. diff --git a/README b/README new file mode 100644 index 00000000..0f382147 --- /dev/null +++ b/README @@ -0,0 +1,242 @@ +Google C++ Mocking Framework +============================ +http://code.google.com/p/googlemock/ + +Overview +-------- +Google's framework for writing and using C++ mock classes on Linux, +Mac OS X, and Windows. Inspired by jMock, EasyMock, and Hamcrest, and +designed with C++'s specifics in mind, it can help you derive better +designs of your system and write better tests. + +Google Mock: + +- 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, and +- is easy to learn and use. + +Please see the project page above for more information as well as mailing lists +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/ is from the cppclean +project (http://code.google.com/p/cppclean/) and under the Apache +License. + +Requirements +------------ +Google Mock is not a testing framework itself. Instead, it needs a +testing framework for writing tests. Currently Google Mock only works +with Google Test (http://code.google.com/p/googletest/), although +eventually we plan to support other C++ testing frameworks. You can +use either the copy of Google Test that comes with Google Mock, or a +compatible version you already have. + +TODO(wan@google.com): describe which Google Test versions are +compatible with the latest Google Mock release. + +Google Mock depends on advanced C++ features and thus requires a more +modern compiler. The following are needed to use Google Mock: + +### Linux Requirements ### +These are the base requirements to build and use Google Mock from a source +package (as described below): + * GNU-compatible Make or "gmake" + * POSIX-standard shell + * POSIX(-2) Regular Expressions (regex.h) + * gcc 4.0 or newer + +Furthermore, if you are building Google Mock from a VCS Checkout (also +described below), there are further requirements: + * Automake version 1.9 or newer + * Autoconf version 2.59 or newer + * Libtool / Libtoolize + * Python version 2.3 or newer + +### Windows Requirements ### + * Microsoft Visual C++ 8.0 SP1 or newer + * An implementation of the tr1 C++ library (You can get it for free + from http://www.boost.org/. We have verified that version 1.36.0 + works. One caveat is this implementation exposes a bug in Visual + C++'s header when exceptions are disabled. Therefore + your project must enable exceptions for this configuration to work.) + +### Mac OS X Requirements ### + * Mac OS X 10.4 Tiger or newer + * Developer Tools Installed + +Getting the Source +------------------ +There are two primary ways of getting Google Mock's source code: you can +download a source release in your preferred archive format, or directly check +out the source from a Version Control System (VCS, we use Google Code's +Subversion hosting). The VCS checkout requires a few extra steps and some extra +software packages on your system, but lets you track development, and make +patches to contribute much more easily, so we highly encourage it. + +### VCS Checkout: ### +The first step is to select whether you want to check out the main line of +development on Google Mock, or one of the released branches. The former will be +much more active and have the latest features, but the latter provides much +more stability and predictability. Choose whichever fits your needs best, and +proceed with the following Subversion commands: + + $ svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn + +or for a release version X.Y.*'s branch: + + $ svn checkout http://googlemock.googlecode.com/svn/branches/release-X.Y/ \ + gmock-X.Y-svn + +Next you will need to prepare the GNU Autotools build system, if you +are using Linux or Mac OS X. Enter the target directory of the +checkout command you used ('gmock-svn' or 'gmock-X.Y-svn' above) and +proceed with the following commands: + + $ aclocal-1.9 # Where "1.9" must match the following automake command. + $ libtoolize -c # Use "glibtoolize -c" instead on Mac OS X. + $ autoheader + $ automake-1.9 -ac # See Automake version requirements above. + $ autoconf + +While this is a bit complicated, it will most often be automatically re-run by +your "make" invocations, so in practice you shouldn't need to worry too much. +Once you have completed these steps, you are ready to build the library. + +TODO(chandlerc@google.com): Update the above with instructions on +preparing the build system for Google Test. + +### Source Package: ### +Google Mock is also released in source packages which can be downloaded from +its Google Code download page[1]. Several different archive formats are +provided, but the only difference is the tools used to manipulate them, and the +size of the resulting file. Download whichever you are most comfortable with. + + [1] Google Mock Downloads: http://code.google.com/p/googlemock/downloads/list + +Once downloaded expand the archive using whichever tools you prefer for that +type. This will always result in a new directory with the name "gmock-X.Y.Z" +which contains all of the source code. Here are some examples in Linux: + + $ tar -xvzf gmock-X.Y.Z.tar.gz + $ tar -xvjf gmock-X.Y.Z.tar.bz2 + $ unzip gmock-X.Y.Z.zip + +Building the Source +------------------- +### Linux and Mac OS X (without Xcode) ### +There are two primary options for building the source at this point: build it +inside the source code tree, or in a separate directory. We recommend building +in a separate directory as that tends to produce both more consistent results +and be easier to clean up should anything go wrong, but both patterns are +supported. The only hard restriction is that while the build directory can be +a subdirectory of the source directory, the opposite is not possible and will +result in errors. Once you have selected where you wish to build Google Mock, +create the directory if necessary, and enter it. The following steps apply for +either approach by simply substituting the shell variable SRCDIR with "." for +building inside the source directory, and the relative path to the source +directory otherwise. + + $ ${SRCDIR}/configure # Standard GNU configure script, --help for more info + $ make # Standard makefile following GNU conventions + $ make check # Builds and runs all tests - all should pass + +Other programs will only be able to use Google Mock's functionality if you +install it in a location which they can access, in Linux this is typically +under '/usr/local'. The following command will install all of the Google Mock +libraries, public headers, and utilities necessary for other programs and +libraries to leverage it: + + $ sudo make install # Not necessary, but allows use by other programs + +TODO(chandlerc@google.com): This section needs to be expanded when the +'gmock-config' script is finished and Autoconf macro's are provided (or not +provided) in order to properly reflect the process for other programs to +locate, include, and link against Google Mock. + +Finally, should you need to remove Google Mock from your system after having +installed it, run the following command, and it will back out its changes. +However, note carefully that you must run this command on the *same* Google +Mock build that you ran the install from, or the results are not predictable. +If you install Google Mock on your system, and are working from a VCS checkout, +make sure you run this *before* updating your checkout of the source in order +to uninstall the same version which you installed. + + $ sudo make uninstall # Must be run against the exact same build as "install" + +TODO(chandlerc@google.com): Fixes the above instructions to match the +actual implementation. + +### Windows ### +We don't have the Visual Studio project files for Google Mock ready +yet. Please see the next two sections on how you can integrate Google +Mock into your project's build system. + +### Using GNU Make ### +The make/ directory contains a Makefile that you can use to build +Google Mock on systems where GNU make is available (e.g. Linux and Mac +OS X). It doesn't try to build Google Mock's own tests. Instead, it +just builds the Google Mock libraries and some sample tests. You can +use it as a starting point for your own Makefile. + +If the default settings are correct for your environment, the +following commands should succeed: + + $ cd ${SRCDIR}/make + $ make + $ ./gmock_test + +If you see errors, try to tweak the contents of make/Makefile to make +them go away. There are instructions in make/Makefile on how to do +it. + +### Using Your Own Build System ### +If none of the build solutions we provide works for you, or if you +prefer your own build system, you just need to compile +${GTEST_SRCDIR}/src/gtest-all.cc (where GTEST_SRCDIR is the root of +the Google Test source tree) and src/gmock-all.cc into a library and +link your tests with it. Assuming a Linux-like system and gcc, +something like the following will do: + + $ cd ${SRCDIR} + $ g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ + -c {GTEST_SRCDIR}/src/gtest-all.cc + $ g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ + -c src/gmock-all.cc + $ ar -rv libgmock.a gtest-all.o gmock-all.o + $ g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ + path/to/your_test.cc libgmock.a -o your_test + +On Windows, you'll also need to add the include path for the boost +headers to the compiler command line. See +http://www.boost.org/doc/libs/1_36_0/doc/html/boost_tr1/usage.html for +how to do it. + +Regenerating Source Files +------------------------- +Some of Google Mock's source files are generated from templates (not +in the C++ sense) using a script. A template file is named FOO.pump, +where FOO is the name of the file it will generate. For example, the +file include/gmock/gmock-generated-actions.h.pump is used to generate +gmock-generated-actions.h in the same directory. + +Normally you don't need to worry about regenerating the source files, +unless you need to modify them (e.g. if you are working on a patch for +Google Mock). In that case, you should modify the corresponding .pump +files instead and run the 'pump' script (for Pump is Useful for Meta +Programming) to regenerate them. We are still working on releasing +the script and its documentation. If you need it now, please email +googlemock@googlegroups.com such that we know to make it happen +sooner. + +Happy testing! diff --git a/build-aux/.keep b/build-aux/.keep new file mode 100644 index 00000000..e69de29b diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..daacfdd8 --- /dev/null +++ b/configure.ac @@ -0,0 +1,115 @@ +AC_INIT([Google C++ Mocking Framework], + [1.0.0], + [googlemock@googlegroups.com], + [gmock]) + +# Provide various options to initialize the Autoconf and configure processes. +AC_PREREQ([2.59]) +AC_CONFIG_SRCDIR([./COPYING]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([build-aux/config.h]) +AC_CONFIG_FILES([Makefile]) + +# 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. + +# 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]) +AS_IF([test "x$with_gtest" == "xno"], + [AC_MSG_ERROR([ +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" + +# TODO(chandlerc@google.com): This is arbitrary, but we will need to introduce +# some features to the GoogleTest build system to help support GoogleMock, and +# at that point it will become more meaningful. +GTEST_MIN_VERSION="1.0.0" + +# 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([ +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 with 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])])]) + +# TODO(chandlerc@google.com): Need to add support for passing a custom prefix +# into the gtest-config script.. +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_MSG_ERROR([TODO(chandlerc@google.com): Need to add support for + building the internal gtest.])]) + +# 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/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h new file mode 100644 index 00000000..a4327588 --- /dev/null +++ b/include/gmock/gmock-actions.h @@ -0,0 +1,900 @@ +// 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_ + +#include +#include +#include +#include +#include + +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 MonomorphicDoDefaultActionImpl; + +template +class ActionAdaptor; + +// BuiltInDefaultValue::Get() returns the "built-in" default +// value for type T, which is NULL when T is a pointer type, 0 when T +// is a numeric type, false when T is bool, or "" when T is string or +// std::string. For any other type T, this value is undefined and the +// function will abort the process. +template +class BuiltInDefaultValue { + public: + 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. + } +}; + +// This partial specialization says that we use the same built-in +// default value for T and const T. +template +class BuiltInDefaultValue { + public: + static T Get() { return BuiltInDefaultValue::Get(); } +}; + +// This partial specialization defines the default values for pointer +// types. +template +class BuiltInDefaultValue { + public: + 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 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 +#if GTEST_HAS_STD_STRING +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(::std::string, ""); +#endif // GTEST_HAS_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'); + +// signed wchar_t and unsigned wchar_t are NOT in the C++ standard. +// Using them is a bad practice and not portable. So don't use them. +// +// Still, Google Mock is designed to work even if the user uses signed +// wchar_t or unsigned wchar_t (obviously, assuming the compiler +// supports them). +// +// To gcc, +// +// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int +// +// MSVC does not recognize signed wchar_t or unsigned wchar_t. It +// treats wchar_t as a native type usually, but treats it as the same +// as unsigned short when the compiler option /Zc:wchar_t- is +// specified. +// +// Therefore we provide a default action for wchar_t when compiled +// with gcc or _NATIVE_WCHAR_T_DEFINED is defined. +// +// 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 defined(__GNUC__) || defined(_NATIVE_WCHAR_T_DEFINED) +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 value_; + value_ = new T(x); + } + + // Unsets the default value for type T. + static void Clear() { + delete value_; + value_ = NULL; + } + + // Returns true iff the user has set the default value for type T. + static bool IsSet() { return value_ != NULL; } + + // 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 value_ == NULL ? + internal::BuiltInDefaultValue::Get() : *value_; + } + private: + static const T* value_; +}; + +// 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 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 void Get() {} +}; + +// Points to the user-set default value for type T. +template +const T* DefaultValue::value_ = 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() : is_do_default_(false) {} + + 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; + + // Returns true iff this is the DoDefault() action. + bool IsDoDefault() const { return is_do_default_; } + private: + template + friend class internal::MonomorphicDoDefaultActionImpl; + + // This private constructor is reserved for implementing + // DoDefault(), the default action for a given mock function. + explicit ActionInterface(bool is_do_default) + : is_do_default_(is_do_default) {} + + // True iff this action is DoDefault(). + const bool is_do_default_; +}; + +// 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. + 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 cann 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_->IsDoDefault(); } + + // 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 { + 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_; + }; + + Impl impl_; +}; + +// 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_; +}; + +// Implements the polymorphic Return(x) action, which can be used in +// any function that returns the type of x, regardless of the argument +// types. +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_(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; + GMOCK_COMPILE_ASSERT(!internal::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; + + explicit Impl(R value) : value_(value) {} + + virtual Result Perform(const ArgumentTuple&) { return value_; } + + private: + R value_; + }; + + R value_; +}; + +// Implements the ReturnNull() action. +class ReturnNullAction { + public: + // Allows ReturnNull() to be used in any pointer-returning function. + template + static Result Perform(const ArgumentTuple&) { + GMOCK_COMPILE_ASSERT(internal::is_pointer::value, + ReturnNull_can_be_used_to_return_a_pointer_only); + return NULL; + } +}; + +// 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. + GMOCK_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_; + }; + + T& ref_; +}; + +// Implements the DoDefault() action for a particular function type F. +template +class MonomorphicDoDefaultActionImpl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + MonomorphicDoDefaultActionImpl() : ActionInterface(true) {} + + // For technical reasons, DoDefault() cannot be used inside a + // composite action (e.g. DoAll(...)). It can only be used at the + // top level in an EXPECT_CALL(). If this function is called, the + // user must be using DoDefault() inside a composite action, and we + // have to generate a run-time error. + virtual Result Perform(const ArgumentTuple&) { + Assert(false, __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 internal::Invalid(); + // The above statement will never be reached, but is required in + // order for this function to compile. + } +}; + +// 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(new MonomorphicDoDefaultActionImpl); + } +}; + +// 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_; +}; + +// 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_; +}; + +// 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(); + *::std::tr1::get(args) = value_; + } + + private: + const A value_; +}; + +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(); + ::std::tr1::get(args)->CopyFrom(*proto_); + } + private: + const internal::linked_ptr proto_; +}; + +// Implements the SetArrayArgument(first, last) action for any function +// whose N-th argument (0-based) is a pointer or iterator to a type that can be +// implicitly converted from *first. +template +class SetArrayArgumentAction { + public: + // Constructs an action that sets the variable pointed to by the + // N-th function argument to 'value'. + explicit SetArrayArgumentAction(InputIterator first, InputIterator last) + : first_(first), last_(last) { + } + + template + void Perform(const ArgumentTuple& args) const { + CompileAssertTypesEqual(); + + // Microsoft compiler deprecates ::std::copy, so we want to suppress warning + // 4996 (Function call with parameters that may be unsafe) there. +#ifdef GTEST_OS_WINDOWS +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. +#endif // GTEST_OS_WINDOWS + ::std::copy(first_, last_, ::std::tr1::get(args)); +#ifdef GTEST_OS_WINDOWS +#pragma warning(pop) // Restores the warning state. +#endif // GTEST_OS_WINDOWS + } + + private: + const InputIterator first_; + const InputIterator last_; +}; + +// 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_; +}; + +// 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_; +}; + +// 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_; + }; + + const A action_; +}; + +} // 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(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 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> > +SetArgumentPointee(const T& x) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, T, internal::IsAProtocolMessage::value>(x)); +} + +// Creates an action that sets the elements of the array pointed to by the N-th +// (0-based) function argument, which can be either a pointer or an iterator, +// to the values of the elements in the source range [first, last). +template +PolymorphicAction > +SetArrayArgument(InputIterator first, InputIterator last) { + return MakePolymorphicAction(internal::SetArrayArgumentAction< + N, InputIterator>(first, last)); +} + +// 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)); +} + +// Creates an action that sets errno and returns the appropriate error. +template +PolymorphicAction > +SetErrnoAndReturn(int errval, T result) { + return MakePolymorphicAction( + internal::SetErrnoAndReturnAction(errval, result)); +} + +// 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); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/include/gmock/gmock-cardinalities.h b/include/gmock/gmock-cardinalities.h new file mode 100644 index 00000000..ae4cb641 --- /dev/null +++ b/include/gmock/gmock-cardinalities.h @@ -0,0 +1,146 @@ +// 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 +#include + +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 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. +Cardinality AtLeast(int n); + +// Creates a cardinality that allows at most n calls. +Cardinality AtMost(int n); + +// Creates a cardinality that allows any number of calls. +Cardinality AnyNumber(); + +// Creates a cardinality that allows between min and max calls. +Cardinality Between(int min, int max); + +// Creates a cardinality that allows exactly n calls. +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/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h new file mode 100644 index 00000000..ec696b30 --- /dev/null +++ b/include/gmock/gmock-generated-actions.h @@ -0,0 +1,1329 @@ +// 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 +#include + +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 ::std::tr1::tuple<>&) { + return function(); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple<>&) { + return (obj_ptr->*method_ptr)(); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args)); + } +}; + +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return function(get<0>(args), get<1>(args), get<2>(args)); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + 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)); + } +}; + + +// Implements the Invoke(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. Invoke(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 InvokeAction { + public: + // The c'tor makes a copy of function_impl (either a function + // pointer or a functor). + explicit InvokeAction(FunctionImpl function_impl) + : function_impl_(function_impl) {} + + template + Result Perform(const ArgumentTuple& args) { + return InvokeHelper::Invoke(function_impl_, args); + } + private: + FunctionImpl function_impl_; +}; + +// Implements the Invoke(object_ptr, &Class::Method) action. +template +class InvokeMethodAction { + public: + InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr) + : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} + + template + Result Perform(const ArgumentTuple& args) const { + return InvokeHelper::InvokeMethod( + obj_ptr_, method_ptr_, args); + } + private: + Class* const obj_ptr_; + const MethodPtr method_ptr_; +}; + +// 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_; +}; + +// CallableHelper has static methods for invoking "callables", +// i.e. function pointers and functors. It uses overloading to +// provide a uniform interface for invoking different kinds of +// callables. In particular, you can use: +// +// CallableHelper::Call(callable, a1, a2, ..., an) +// +// to invoke an n-ary callable, where R is its return type. If an +// argument, say a2, needs to be passed by reference, you should write +// ByRef(a2) instead of a2 in the above expression. +template +class CallableHelper { + public: + // Calls a nullary callable. + template + static R Call(Function function) { return function(); } + + // Calls a unary callable. + + // We deliberately pass a1 by value instead of const reference here + // in case it is a C-string literal. If we had declared the + // parameter as 'const A1& a1' and write Call(function, "Hi"), the + // compiler would've thought A1 is 'char[3]', which causes trouble + // when you need to copy a value of type A1. By declaring the + // parameter as 'A1 a1', the compiler will correctly infer that A1 + // is 'const char*' when it sees Call(function, "Hi"). + // + // Since this function is defined inline, the compiler can get rid + // of the copying of the arguments. Therefore the performance won't + // be hurt. + template + static R Call(Function function, A1 a1) { return function(a1); } + + // Calls a binary callable. + template + static R Call(Function function, A1 a1, A2 a2) { + return function(a1, a2); + } + + // Calls a ternary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3) { + return function(a1, a2, a3); + } + + // Calls a 4-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4) { + return function(a1, a2, a3, a4); + } + + // Calls a 5-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return function(a1, a2, a3, a4, a5); + } + + // Calls a 6-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return function(a1, a2, a3, a4, a5, a6); + } + + // Calls a 7-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7) { + return function(a1, a2, a3, a4, a5, a6, a7); + } + + // Calls a 8-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8) { + return function(a1, a2, a3, a4, a5, a6, a7, a8); + } + + // Calls a 9-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8, A9 a9) { + return function(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + // Calls a 10-ary callable. + template + static R Call(Function function, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7, A8 a8, A9 a9, A10 a10) { + return function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + +}; // class CallableHelper + +// Invokes a nullary callable argument. +template +class InvokeArgumentAction0 { + public: + template + static Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args)); + } +}; + +// Invokes a unary callable argument with the given argument. +template +class InvokeArgumentAction1 { + public: + // We deliberately pass a1 by value instead of const reference here + // in case it is a C-string literal. + // + // Since this function is defined inline, the compiler can get rid + // of the copying of the arguments. Therefore the performance won't + // be hurt. + explicit InvokeArgumentAction1(A1 a1) : arg1_(a1) {} + + template + Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args), arg1_); + } + private: + const A1 arg1_; +}; + +// Invokes a binary callable argument with the given arguments. +template +class InvokeArgumentAction2 { + public: + InvokeArgumentAction2(A1 a1, A2 a2) : + arg1_(a1), arg2_(a2) {} + + template + Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args), arg1_, arg2_); + } + private: + const A1 arg1_; + const A2 arg2_; +}; + +// Invokes a ternary callable argument with the given arguments. +template +class InvokeArgumentAction3 { + public: + InvokeArgumentAction3(A1 a1, A2 a2, A3 a3) : + arg1_(a1), arg2_(a2), arg3_(a3) {} + + template + Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args), arg1_, arg2_, + arg3_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; +}; + +// Invokes a 4-ary callable argument with the given arguments. +template +class InvokeArgumentAction4 { + public: + InvokeArgumentAction4(A1 a1, A2 a2, A3 a3, A4 a4) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4) {} + + template + Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args), arg1_, arg2_, + arg3_, arg4_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; +}; + +// Invokes a 5-ary callable argument with the given arguments. +template +class InvokeArgumentAction5 { + public: + InvokeArgumentAction5(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5) {} + + template + Result Perform(const ArgumentTuple& args) { + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function(arg1_, arg2_, arg3_, arg4_, arg5_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; +}; + +// Invokes a 6-ary callable argument with the given arguments. +template +class InvokeArgumentAction6 { + public: + InvokeArgumentAction6(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6) {} + + template + Result Perform(const ArgumentTuple& args) { + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; +}; + +// Invokes a 7-ary callable argument with the given arguments. +template +class InvokeArgumentAction7 { + public: + InvokeArgumentAction7(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), + arg7_(a7) {} + + template + Result Perform(const ArgumentTuple& args) { + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; +}; + +// Invokes a 8-ary callable argument with the given arguments. +template +class InvokeArgumentAction8 { + public: + InvokeArgumentAction8(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, + A8 a8) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), + arg7_(a7), arg8_(a8) {} + + template + Result Perform(const ArgumentTuple& args) { + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; +}; + +// Invokes a 9-ary callable argument with the given arguments. +template +class InvokeArgumentAction9 { + public: + InvokeArgumentAction9(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, + A9 a9) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), + arg7_(a7), arg8_(a8), arg9_(a9) {} + + template + Result Perform(const ArgumentTuple& args) { + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, + arg9_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; + const A9 arg9_; +}; + +// Invokes a 10-ary callable argument with the given arguments. +template +class InvokeArgumentAction10 { + public: + InvokeArgumentAction10(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, + A8 a8, A9 a9, A10 a10) : + arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), + arg7_(a7), arg8_(a8), arg9_(a9), arg10_(a10) {} + + template + Result Perform(const ArgumentTuple& args) { + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, + arg9_, arg10_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; + const A9 arg9_; + const A10 arg10_; +}; + +// 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 ::std::tr1::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( +// ::std::tr1::make_tuple(true, 'a', 2.5)) +// returns ::std::tr1::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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + return SelectedArgs(); + } +}; + +template +class SelectArgs { + public: + typedef Result type(GMOCK_FIELD(ArgumentTuple, k1)); + typedef typename Function::ArgumentTuple SelectedArgs; + static SelectedArgs Select(const ArgumentTuple& args) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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) { + using ::std::tr1::get; + 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 { + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename SelectArgs::type + InnerFunctionType; + + class Impl : public ActionInterface { + public: + explicit Impl(const InnerAction& action) : action_(action) {} + + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + private: + Action action_; + }; + + return MakeAction(new Impl(action_)); + } + private: + const InnerAction action_; +}; + +// 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 { + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::MakeResultVoid VoidResult; + + // Implements the DoAll(...) action for a particular function type F. + class Impl : public ActionInterface { + public: + 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_; + }; + + return Action(new Impl(action1_, action2_)); + } + private: + Action1 action1_; + Action2 action2_; +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// Creates an action that invokes 'function_impl' with the mock +// function's arguments. +template +PolymorphicAction > Invoke( + FunctionImpl function_impl) { + return MakePolymorphicAction( + internal::InvokeAction(function_impl)); +} + +// Creates an action that invokes the given method on the given object +// with the mock function's arguments. +template +PolymorphicAction > Invoke( + Class* obj_ptr, MethodPtr method_ptr) { + return MakePolymorphicAction( + internal::InvokeMethodAction(obj_ptr, method_ptr)); +} + +// 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); +} + +// 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. +template +inline PolymorphicAction > InvokeArgument() { + return MakePolymorphicAction(internal::InvokeArgumentAction0()); +} + +// We deliberately pass a1 by value instead of const reference here in +// case it is a C-string literal. If we had declared the parameter as +// 'const A1& a1' and write InvokeArgument<0>("Hi"), the compiler +// would've thought A1 is 'char[3]', which causes trouble as the +// implementation needs to copy a value of type A1. By declaring the +// parameter as 'A1 a1', the compiler will correctly infer that A1 is +// 'const char*' when it sees InvokeArgument<0>("Hi"). +// +// Since this function is defined inline, the compiler can get rid of +// the copying of the arguments. Therefore the performance won't be +// hurt. +template +inline PolymorphicAction > +InvokeArgument(A1 a1) { + return MakePolymorphicAction(internal::InvokeArgumentAction1(a1)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2) { + return MakePolymorphicAction( + internal::InvokeArgumentAction2(a1, a2)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3) { + return MakePolymorphicAction( + internal::InvokeArgumentAction3(a1, a2, a3)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4) { + return MakePolymorphicAction( + internal::InvokeArgumentAction4(a1, a2, a3, a4)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return MakePolymorphicAction( + internal::InvokeArgumentAction5(a1, a2, a3, a4, + a5)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return MakePolymorphicAction( + internal::InvokeArgumentAction6(a1, a2, a3, + a4, a5, a6)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return MakePolymorphicAction( + internal::InvokeArgumentAction7(a1, a2, + a3, a4, a5, a6, a7)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return MakePolymorphicAction( + internal::InvokeArgumentAction8(a1, + a2, a3, a4, a5, a6, a7, a8)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return MakePolymorphicAction( + internal::InvokeArgumentAction9(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template +inline PolymorphicAction > +InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, + A10 a10) { + return MakePolymorphicAction( + internal::InvokeArgumentAction10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); +} + +// WithoutArgs(inner_action) can be used in a mock function with a +// non-empty argument list to perform inner_action, which takes no +// argument. In other words, it adapts an action accepting no +// argument to one that accepts (and ignores) arguments. +template +inline internal::WithArgsAction +WithoutArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// WithArg(an_action) creates an action that passes the k-th +// (0-based) argument of the mock function to an_action and performs +// it. It adapts an action accepting one argument to one that accepts +// multiple arguments. For convenience, we also provide +// WithArgs(an_action) (defined below) as a synonym. +template +inline internal::WithArgsAction +WithArg(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// 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 + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump new file mode 100644 index 00000000..d3dfac09 --- /dev/null +++ b/include/gmock/gmock-generated-actions.h.pump @@ -0,0 +1,567 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-variadic-actions.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 some commonly used variadic actions. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ + +#include +#include + +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 import = [[$if i==0 [[]] $else [[ + using ::std::tr1::get; + +]]]] +$var gets = [[$for j, [[get<$(j - 1)>(args)]]]] +template +class InvokeHelper > { + public: + template + static R Invoke(Function function, const ::std::tr1::tuple<$as>&$args) { +$import return function($gets); + } + + template + static R InvokeMethod(Class* obj_ptr, + MethodPtr method_ptr, + const ::std::tr1::tuple<$as>&$args) { +$import return (obj_ptr->*method_ptr)($gets); + } +}; + + +]] + +// Implements the Invoke(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. Invoke(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 InvokeAction { + public: + // The c'tor makes a copy of function_impl (either a function + // pointer or a functor). + explicit InvokeAction(FunctionImpl function_impl) + : function_impl_(function_impl) {} + + template + Result Perform(const ArgumentTuple& args) { + return InvokeHelper::Invoke(function_impl_, args); + } + private: + FunctionImpl function_impl_; +}; + +// Implements the Invoke(object_ptr, &Class::Method) action. +template +class InvokeMethodAction { + public: + InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr) + : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} + + template + Result Perform(const ArgumentTuple& args) const { + return InvokeHelper::InvokeMethod( + obj_ptr_, method_ptr_, args); + } + private: + Class* const obj_ptr_; + const MethodPtr method_ptr_; +}; + +// 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_; +}; + +// CallableHelper has static methods for invoking "callables", +// i.e. function pointers and functors. It uses overloading to +// provide a uniform interface for invoking different kinds of +// callables. In particular, you can use: +// +// CallableHelper::Call(callable, a1, a2, ..., an) +// +// to invoke an n-ary callable, where R is its return type. If an +// argument, say a2, needs to be passed by reference, you should write +// ByRef(a2) instead of a2 in the above expression. +template +class CallableHelper { + public: + // Calls a nullary callable. + template + static R Call(Function function) { return function(); } + + // Calls a unary callable. + + // We deliberately pass a1 by value instead of const reference here + // in case it is a C-string literal. If we had declared the + // parameter as 'const A1& a1' and write Call(function, "Hi"), the + // compiler would've thought A1 is 'char[3]', which causes trouble + // when you need to copy a value of type A1. By declaring the + // parameter as 'A1 a1', the compiler will correctly infer that A1 + // is 'const char*' when it sees Call(function, "Hi"). + // + // Since this function is defined inline, the compiler can get rid + // of the copying of the arguments. Therefore the performance won't + // be hurt. + template + static R Call(Function function, A1 a1) { return function(a1); } + +$range i 2..n +$for i +[[ +$var arity = [[$if i==2 [[binary]] $elif i==3 [[ternary]] $else [[$i-ary]]]] + + // Calls a $arity callable. + +$range j 1..i +$var typename_As = [[$for j, [[typename A$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var as = [[$for j, [[a$j]]]] +$var typename_Ts = [[$for j, [[typename T$j]]]] +$var Ts = [[$for j, [[T$j]]]] + template + static R Call(Function function, $Aas) { + return function($as); + } + +]] + +}; // class CallableHelper + +// Invokes a nullary callable argument. +template +class InvokeArgumentAction0 { + public: + template + static Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args)); + } +}; + +// Invokes a unary callable argument with the given argument. +template +class InvokeArgumentAction1 { + public: + // We deliberately pass a1 by value instead of const reference here + // in case it is a C-string literal. + // + // Since this function is defined inline, the compiler can get rid + // of the copying of the arguments. Therefore the performance won't + // be hurt. + explicit InvokeArgumentAction1(A1 a1) : arg1_(a1) {} + + template + Result Perform(const ArgumentTuple& args) { + return CallableHelper::Call(::std::tr1::get(args), arg1_); + } + private: + const A1 arg1_; +}; + +$range i 2..n +$for i [[ +$var arity = [[$if i==2 [[binary]] $elif i==3 [[ternary]] $else [[$i-ary]]]] +$range j 1..i +$var typename_As = [[$for j, [[typename A$j]]]] +$var args_ = [[$for j, [[arg$j[[]]_]]]] + +// Invokes a $arity callable argument with the given arguments. +template +class InvokeArgumentAction$i { + public: + InvokeArgumentAction$i($for j, [[A$j a$j]]) : + $for j, [[arg$j[[]]_(a$j)]] {} + + template + Result Perform(const ArgumentTuple& args) { +$if i <= 4 [[ + + return CallableHelper::Call(::std::tr1::get(args), $args_); + +]] $else [[ + + // We extract the callable to a variable before invoking it, in + // case it is a functor passed by value and its operator() is not + // const. + typename ::std::tr1::tuple_element::type function = + ::std::tr1::get(args); + return function($args_); + +]] + } + private: +$for j [[ + + const A$j arg$j[[]]_; +]] + +}; + +]] + +// 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 ::std::tr1::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( +// ::std::tr1::make_tuple(true, 'a', 2.5)) +// returns ::std::tr1::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) { + using ::std::tr1::get; + 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& args) { + using ::std::tr1::get; + 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 { + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename SelectArgs::type + InnerFunctionType; + + class Impl : public ActionInterface { + public: + explicit Impl(const InnerAction& action) : action_(action) {} + + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + private: + Action action_; + }; + + return MakeAction(new Impl(action_)); + } + private: + const InnerAction action_; +}; + +// 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 { + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::MakeResultVoid VoidResult; + + // Implements the DoAll(...) action for a particular function type F. + class Impl : public ActionInterface { + public: + 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_; + }; + + return Action(new Impl(action1_, action2_)); + } + private: + Action1 action1_; + Action2 action2_; +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// Creates an action that invokes 'function_impl' with the mock +// function's arguments. +template +PolymorphicAction > Invoke( + FunctionImpl function_impl) { + return MakePolymorphicAction( + internal::InvokeAction(function_impl)); +} + +// Creates an action that invokes the given method on the given object +// with the mock function's arguments. +template +PolymorphicAction > Invoke( + Class* obj_ptr, MethodPtr method_ptr) { + return MakePolymorphicAction( + internal::InvokeMethodAction(obj_ptr, method_ptr)); +} + +// 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); +} + +// 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. +template +inline PolymorphicAction > InvokeArgument() { + return MakePolymorphicAction(internal::InvokeArgumentAction0()); +} + +// We deliberately pass a1 by value instead of const reference here in +// case it is a C-string literal. If we had declared the parameter as +// 'const A1& a1' and write InvokeArgument<0>("Hi"), the compiler +// would've thought A1 is 'char[3]', which causes trouble as the +// implementation needs to copy a value of type A1. By declaring the +// parameter as 'A1 a1', the compiler will correctly infer that A1 is +// 'const char*' when it sees InvokeArgument<0>("Hi"). +// +// Since this function is defined inline, the compiler can get rid of +// the copying of the arguments. Therefore the performance won't be +// hurt. +template +inline PolymorphicAction > +InvokeArgument(A1 a1) { + return MakePolymorphicAction(internal::InvokeArgumentAction1(a1)); +} + +$range i 2..n +$for i [[ +$range j 1..i +$var typename_As = [[$for j, [[typename A$j]]]] +$var As = [[$for j, [[A$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var as = [[$for j, [[a$j]]]] + +template +inline PolymorphicAction > +InvokeArgument($Aas) { + return MakePolymorphicAction( + internal::InvokeArgumentAction$i($as)); +} + +]] + +// WithoutArgs(inner_action) can be used in a mock function with a +// non-empty argument list to perform inner_action, which takes no +// argument. In other words, it adapts an action accepting no +// argument to one that accepts (and ignores) arguments. +template +inline internal::WithArgsAction +WithoutArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// WithArg(an_action) creates an action that passes the k-th +// (0-based) argument of the mock function to an_action and performs +// it. It adapts an action accepting one argument to one that accepts +// multiple arguments. For convenience, we also provide +// WithArgs(an_action) (defined below) as a synonym. +template +inline internal::WithArgsAction +WithArg(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// 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 + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h new file mode 100644 index 00000000..abdfc9e0 --- /dev/null +++ b/include/gmock/gmock-generated-function-mockers.h @@ -0,0 +1,706 @@ +// 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 function mockers of various arities. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ + +#include +#include + +namespace testing { + +template +class MockSpec; + +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() { + return 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(::std::tr1::make_tuple(m1)); + return this->current_spec(); + } + + R Invoke(A1 a1) { + return 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(::std::tr1::make_tuple(m1, m2)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2) { + return 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(::std::tr1::make_tuple(m1, m2, m3)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3) { + return 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(::std::tr1::make_tuple(m1, m2, m3, m4)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) { + return 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(::std::tr1::make_tuple(m1, m2, m3, m4, + m5)); + return this->current_spec(); + } + + R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return 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(::std::tr1::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) { + return 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(::std::tr1::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) { + return 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(::std::tr1::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) { + return 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(::std::tr1::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) { + return 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(::std::tr1::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) { + return 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; + +// The result type of function type F. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_RESULT(tn, F) tn ::testing::internal::Function::Result + +// The type of argument N of function type F. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_ARG(tn, F, N) tn ::testing::internal::Function::Argument##N + +// The matcher type for argument N of function type F. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MATCHER(tn, F, N) const ::testing::Matcher& + +// The variable for mocking the given method. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MOCKER(Method) GMOCK_CONCAT_TOKEN(gmock_##Method##_, __LINE__) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD0(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method() constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 0, \ + this_method_does_not_take_0_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(); \ + } \ + ::testing::MockSpec& \ + gmock_##Method() constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD1(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 1, \ + this_method_does_not_take_1_argument); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD2(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 2, \ + this_method_does_not_take_2_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD3(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 3, \ + this_method_does_not_take_3_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD4(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 4, \ + this_method_does_not_take_4_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD5(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4, \ + GMOCK_ARG(tn, F, 5) gmock_a5) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 5, \ + this_method_does_not_take_5_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER(tn, F, 5) gmock_a5) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD6(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4, \ + GMOCK_ARG(tn, F, 5) gmock_a5, \ + GMOCK_ARG(tn, F, 6) gmock_a6) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 6, \ + this_method_does_not_take_6_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER(tn, F, 6) gmock_a6) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD7(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4, \ + GMOCK_ARG(tn, F, 5) gmock_a5, \ + GMOCK_ARG(tn, F, 6) gmock_a6, \ + GMOCK_ARG(tn, F, 7) gmock_a7) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 7, \ + this_method_does_not_take_7_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER(tn, F, 7) gmock_a7) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD8(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4, \ + GMOCK_ARG(tn, F, 5) gmock_a5, \ + GMOCK_ARG(tn, F, 6) gmock_a6, \ + GMOCK_ARG(tn, F, 7) gmock_a7, \ + GMOCK_ARG(tn, F, 8) gmock_a8) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 8, \ + this_method_does_not_take_8_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER(tn, F, 7) gmock_a7, \ + GMOCK_MATCHER(tn, F, 8) gmock_a8) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD9(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4, \ + GMOCK_ARG(tn, F, 5) gmock_a5, \ + GMOCK_ARG(tn, F, 6) gmock_a6, \ + GMOCK_ARG(tn, F, 7) gmock_a7, \ + GMOCK_ARG(tn, F, 8) gmock_a8, \ + GMOCK_ARG(tn, F, 9) gmock_a9) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 9, \ + this_method_does_not_take_9_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER(tn, F, 7) gmock_a7, \ + GMOCK_MATCHER(tn, F, 8) gmock_a8, \ + GMOCK_MATCHER(tn, F, 9) gmock_a9) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ + gmock_a9); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD10(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ + GMOCK_ARG(tn, F, 2) gmock_a2, \ + GMOCK_ARG(tn, F, 3) gmock_a3, \ + GMOCK_ARG(tn, F, 4) gmock_a4, \ + GMOCK_ARG(tn, F, 5) gmock_a5, \ + GMOCK_ARG(tn, F, 6) gmock_a6, \ + GMOCK_ARG(tn, F, 7) gmock_a7, \ + GMOCK_ARG(tn, F, 8) gmock_a8, \ + GMOCK_ARG(tn, F, 9) gmock_a9, \ + GMOCK_ARG(tn, F, 10) gmock_a10) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == 10, \ + this_method_does_not_take_10_arguments); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + gmock_a10); \ + } \ + ::testing::MockSpec& \ + gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER(tn, F, 7) gmock_a7, \ + GMOCK_MATCHER(tn, F, 8) gmock_a8, \ + GMOCK_MATCHER(tn, F, 9) gmock_a9, \ + GMOCK_MATCHER(tn, F, 10) gmock_a10) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + gmock_a10); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + +#define MOCK_METHOD0(m, F) GMOCK_METHOD0(, , , m, F) +#define MOCK_METHOD1(m, F) GMOCK_METHOD1(, , , m, F) +#define MOCK_METHOD2(m, F) GMOCK_METHOD2(, , , m, F) +#define MOCK_METHOD3(m, F) GMOCK_METHOD3(, , , m, F) +#define MOCK_METHOD4(m, F) GMOCK_METHOD4(, , , m, F) +#define MOCK_METHOD5(m, F) GMOCK_METHOD5(, , , m, F) +#define MOCK_METHOD6(m, F) GMOCK_METHOD6(, , , m, F) +#define MOCK_METHOD7(m, F) GMOCK_METHOD7(, , , m, F) +#define MOCK_METHOD8(m, F) GMOCK_METHOD8(, , , m, F) +#define MOCK_METHOD9(m, F) GMOCK_METHOD9(, , , m, F) +#define MOCK_METHOD10(m, F) GMOCK_METHOD10(, , , m, F) + +#define MOCK_CONST_METHOD0(m, F) GMOCK_METHOD0(, const, , m, F) +#define MOCK_CONST_METHOD1(m, F) GMOCK_METHOD1(, const, , m, F) +#define MOCK_CONST_METHOD2(m, F) GMOCK_METHOD2(, const, , m, F) +#define MOCK_CONST_METHOD3(m, F) GMOCK_METHOD3(, const, , m, F) +#define MOCK_CONST_METHOD4(m, F) GMOCK_METHOD4(, const, , m, F) +#define MOCK_CONST_METHOD5(m, F) GMOCK_METHOD5(, const, , m, F) +#define MOCK_CONST_METHOD6(m, F) GMOCK_METHOD6(, const, , m, F) +#define MOCK_CONST_METHOD7(m, F) GMOCK_METHOD7(, const, , m, F) +#define MOCK_CONST_METHOD8(m, F) GMOCK_METHOD8(, const, , m, F) +#define MOCK_CONST_METHOD9(m, F) GMOCK_METHOD9(, const, , m, F) +#define MOCK_CONST_METHOD10(m, F) GMOCK_METHOD10(, const, , m, F) + +#define MOCK_METHOD0_T(m, F) GMOCK_METHOD0(typename, , , m, F) +#define MOCK_METHOD1_T(m, F) GMOCK_METHOD1(typename, , , m, F) +#define MOCK_METHOD2_T(m, F) GMOCK_METHOD2(typename, , , m, F) +#define MOCK_METHOD3_T(m, F) GMOCK_METHOD3(typename, , , m, F) +#define MOCK_METHOD4_T(m, F) GMOCK_METHOD4(typename, , , m, F) +#define MOCK_METHOD5_T(m, F) GMOCK_METHOD5(typename, , , m, F) +#define MOCK_METHOD6_T(m, F) GMOCK_METHOD6(typename, , , m, F) +#define MOCK_METHOD7_T(m, F) GMOCK_METHOD7(typename, , , m, F) +#define MOCK_METHOD8_T(m, F) GMOCK_METHOD8(typename, , , m, F) +#define MOCK_METHOD9_T(m, F) GMOCK_METHOD9(typename, , , m, F) +#define MOCK_METHOD10_T(m, F) GMOCK_METHOD10(typename, , , m, F) + +#define MOCK_CONST_METHOD0_T(m, F) GMOCK_METHOD0(typename, const, , m, F) +#define MOCK_CONST_METHOD1_T(m, F) GMOCK_METHOD1(typename, const, , m, F) +#define MOCK_CONST_METHOD2_T(m, F) GMOCK_METHOD2(typename, const, , m, F) +#define MOCK_CONST_METHOD3_T(m, F) GMOCK_METHOD3(typename, const, , m, F) +#define MOCK_CONST_METHOD4_T(m, F) GMOCK_METHOD4(typename, const, , m, F) +#define MOCK_CONST_METHOD5_T(m, F) GMOCK_METHOD5(typename, const, , m, F) +#define MOCK_CONST_METHOD6_T(m, F) GMOCK_METHOD6(typename, const, , m, F) +#define MOCK_CONST_METHOD7_T(m, F) GMOCK_METHOD7(typename, const, , m, F) +#define MOCK_CONST_METHOD8_T(m, F) GMOCK_METHOD8(typename, const, , m, F) +#define MOCK_CONST_METHOD9_T(m, F) GMOCK_METHOD9(typename, const, , m, F) +#define MOCK_CONST_METHOD10_T(m, F) GMOCK_METHOD10(typename, const, , m, F) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD0(, , ct, m, F) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD1(, , ct, m, F) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD2(, , ct, m, F) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD3(, , ct, m, F) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD4(, , ct, m, F) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD5(, , ct, m, F) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD6(, , ct, m, F) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD7(, , ct, m, F) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD8(, , ct, m, F) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD9(, , ct, m, F) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD10(, , ct, m, F) + +#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD0(, const, ct, m, F) +#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD1(, const, ct, m, F) +#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD2(, const, ct, m, F) +#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD3(, const, ct, m, F) +#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD4(, const, ct, m, F) +#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD5(, const, ct, m, F) +#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD6(, const, ct, m, F) +#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD7(, const, ct, m, F) +#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD8(, const, ct, m, F) +#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD9(, const, ct, m, F) +#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD10(, const, ct, m, F) + +#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD0(typename, , ct, m, F) +#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD1(typename, , ct, m, F) +#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD2(typename, , ct, m, F) +#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD3(typename, , ct, m, F) +#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD4(typename, , ct, m, F) +#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD5(typename, , ct, m, F) +#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD6(typename, , ct, m, F) +#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD7(typename, , ct, m, F) +#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD8(typename, , ct, m, F) +#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD9(typename, , ct, m, F) +#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD10(typename, , ct, m, F) + +#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD0(typename, const, ct, m, F) +#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD1(typename, const, ct, m, F) +#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD2(typename, const, ct, m, F) +#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD3(typename, const, ct, m, F) +#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD4(typename, const, ct, m, F) +#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD5(typename, const, ct, m, F) +#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD6(typename, const, ct, m, F) +#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD7(typename, const, ct, m, F) +#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD8(typename, const, ct, m, F) +#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD9(typename, const, ct, m, F) +#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD10(typename, const, ct, m, F) + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump new file mode 100644 index 00000000..4f7fdc16 --- /dev/null +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -0,0 +1,200 @@ +$$ -*- 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 +#include + +namespace testing { + +template +class MockSpec; + +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(::std::tr1::make_tuple($ms)); + +]] + return this->current_spec(); + } + + R Invoke($Aas) { + return 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; + +// The result type of function type F. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_RESULT(tn, F) tn ::testing::internal::Function::Result + +// The type of argument N of function type F. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_ARG(tn, F, N) tn ::testing::internal::Function::Argument##N + +// The matcher type for argument N of function type F. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MATCHER(tn, F, N) const ::testing::Matcher& + +// The variable for mocking the given method. +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_MOCKER(Method) GMOCK_CONCAT_TOKEN(gmock_##Method##_, __LINE__) + + +$for i [[ +$range j 1..i +$var arg_as = [[$for j, \ + [[GMOCK_ARG(tn, F, $j) gmock_a$j]]]] +$var as = [[$for j, [[gmock_a$j]]]] +$var matcher_as = [[$for j, \ + [[GMOCK_MATCHER(tn, F, $j) gmock_a$j]]]] +// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! +#define GMOCK_METHOD$i(tn, constness, ct, Method, F) \ + GMOCK_RESULT(tn, F) ct Method($arg_as) constness { \ + GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ + tn ::testing::internal::Function::ArgumentTuple>::value == $i, \ + this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ + GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER(Method).Invoke($as); \ + } \ + ::testing::MockSpec& \ + gmock_##Method($matcher_as) constness { \ + return GMOCK_MOCKER(Method).RegisterOwner(this).With($as); \ + } \ + mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + + +]] +$for i [[ +#define MOCK_METHOD$i(m, F) GMOCK_METHOD$i(, , , m, F) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i(m, F) GMOCK_METHOD$i(, const, , m, F) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_T(m, F) GMOCK_METHOD$i(typename, , , m, F) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_T(m, F) GMOCK_METHOD$i(typename, const, , m, F) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD$i(, , ct, m, F) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD$i(, const, ct, m, F) + +]] + + +$for i [[ +#define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD$i(typename, , ct, m, F) + +]] + + +$for i [[ +#define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, F) \ + GMOCK_METHOD$i(typename, const, ct, m, F) + +]] + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h new file mode 100644 index 00000000..09ccc9c3 --- /dev/null +++ b/include/gmock/gmock-generated-matchers.h @@ -0,0 +1,650 @@ +// This file was GENERATED by a script. 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 + +namespace testing { +namespace internal { + +// Implements ElementsAre() and ElementsAreArray(). +template +class ElementsAreMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + // Constructs the matcher from a sequence of element values or + // element matchers. + template + ElementsAreMatcherImpl(InputIter first, size_t count) { + matchers_.reserve(count); + InputIter it = first; + for (size_t i = 0; i != count; ++i, ++it) { + matchers_.push_back(MatcherCast(*it)); + } + } + + // Returns true iff 'container' matches. + virtual bool Matches(Container container) const { + if (container.size() != count()) + return false; + + typename RawContainer::const_iterator container_iter = container.begin(); + for (size_t i = 0; i != count(); ++container_iter, ++i) { + if (!matchers_[i].Matches(*container_iter)) + return false; + } + + return true; + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + if (count() == 0) { + *os << "is empty"; + } else if (count() == 1) { + *os << "has 1 element that "; + matchers_[0].DescribeTo(os); + } else { + *os << "has " << Elements(count()) << " where\n"; + for (size_t i = 0; i != count(); ++i) { + *os << "element " << i << " "; + matchers_[i].DescribeTo(os); + if (i + 1 < count()) { + *os << ",\n"; + } + } + } + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + if (count() == 0) { + *os << "is not empty"; + return; + } + + *os << "does not have " << Elements(count()) << ", or\n"; + for (size_t i = 0; i != count(); ++i) { + *os << "element " << i << " "; + matchers_[i].DescribeNegationTo(os); + if (i + 1 < count()) { + *os << ", or\n"; + } + } + } + + // Explains why 'container' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(Container container, + ::std::ostream* os) const { + if (Matches(container)) { + // We need to explain why *each* element matches (the obvious + // ones can be skipped). + + bool reason_printed = false; + typename RawContainer::const_iterator container_iter = container.begin(); + for (size_t i = 0; i != count(); ++container_iter, ++i) { + ::std::stringstream ss; + matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + + const string s = ss.str(); + if (!s.empty()) { + if (reason_printed) { + *os << ",\n"; + } + *os << "element " << i << " " << s; + reason_printed = true; + } + } + } else { + // We need to explain why the container doesn't match. + const size_t actual_count = container.size(); + if (actual_count != count()) { + // The element count doesn't match. If the container is + // empty, there's no need to explain anything as Google Mock + // already prints the empty container. Otherwise we just need + // to show how many elements there actually are. + if (actual_count != 0) { + *os << "has " << Elements(actual_count); + } + return; + } + + // The container has the right size but at least one element + // doesn't match expectation. We need to find this element and + // explain why it doesn't match. + typename RawContainer::const_iterator container_iter = container.begin(); + for (size_t i = 0; i != count(); ++container_iter, ++i) { + if (matchers_[i].Matches(*container_iter)) { + continue; + } + + *os << "element " << i << " doesn't match"; + + ::std::stringstream ss; + matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + const string s = ss.str(); + if (!s.empty()) { + *os << " (" << s << ")"; + } + return; + } + } + } + + private: + static Message Elements(size_t count) { + return Message() << count << (count == 1 ? " element" : " elements"); + } + + size_t count() const { return matchers_.size(); } + std::vector > matchers_; +}; + +// Implements ElementsAre() of 0-10 arguments. + +class ElementsAreMatcher0 { + public: + ElementsAreMatcher0() {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher* const matchers = NULL; + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); + } +}; + +template +class ElementsAreMatcher1 { + public: + explicit ElementsAreMatcher1(const T1& e1) : e1_(e1) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 1)); + } + + private: + const T1& e1_; +}; + +template +class ElementsAreMatcher2 { + public: + ElementsAreMatcher2(const T1& e1, const T2& e2) : e1_(e1), e2_(e2) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 2)); + } + + private: + const T1& e1_; + const T2& e2_; +}; + +template +class ElementsAreMatcher3 { + public: + ElementsAreMatcher3(const T1& e1, const T2& e2, const T3& e3) : e1_(e1), + e2_(e2), e3_(e3) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 3)); + } + + private: + const T1& e1_; + const T2& e2_; + const T3& e3_; +}; + +template +class ElementsAreMatcher4 { + public: + ElementsAreMatcher4(const T1& e1, const T2& e2, const T3& e3, + const T4& e4) : e1_(e1), e2_(e2), e3_(e3), e4_(e4) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 4)); + } + + private: + const T1& e1_; + const T2& e2_; + const T3& e3_; + const T4& e4_; +}; + +template +class ElementsAreMatcher5 { + public: + ElementsAreMatcher5(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), e5_(e5) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + MatcherCast(e5_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 5)); + } + + private: + const T1& e1_; + const T2& e2_; + const T3& e3_; + const T4& e4_; + const T5& e5_; +}; + +template +class ElementsAreMatcher6 { + public: + ElementsAreMatcher6(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), + e5_(e5), e6_(e6) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + MatcherCast(e5_), + MatcherCast(e6_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 6)); + } + + private: + const T1& e1_; + const T2& e2_; + const T3& e3_; + const T4& e4_; + const T5& e5_; + const T6& e6_; +}; + +template +class ElementsAreMatcher7 { + public: + ElementsAreMatcher7(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) : e1_(e1), e2_(e2), e3_(e3), + e4_(e4), e5_(e5), e6_(e6), e7_(e7) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + MatcherCast(e5_), + MatcherCast(e6_), + MatcherCast(e7_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 7)); + } + + private: + const T1& e1_; + const T2& e2_; + const T3& e3_; + const T4& e4_; + const T5& e5_; + const T6& e6_; + const T7& e7_; +}; + +template +class ElementsAreMatcher8 { + public: + ElementsAreMatcher8(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8) : e1_(e1), + e2_(e2), e3_(e3), e4_(e4), e5_(e5), e6_(e6), e7_(e7), e8_(e8) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + MatcherCast(e5_), + MatcherCast(e6_), + MatcherCast(e7_), + MatcherCast(e8_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 8)); + } + + private: + const T1& e1_; + const T2& e2_; + const T3& e3_; + const T4& e4_; + const T5& e5_; + const T6& e6_; + const T7& e7_; + const T8& e8_; +}; + +template +class ElementsAreMatcher9 { + public: + ElementsAreMatcher9(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) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), e5_(e5), e6_(e6), + e7_(e7), e8_(e8), e9_(e9) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + MatcherCast(e5_), + MatcherCast(e6_), + MatcherCast(e7_), + MatcherCast(e8_), + MatcherCast(e9_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 9)); + } + + private: + 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_; +}; + +template +class ElementsAreMatcher10 { + public: + ElementsAreMatcher10(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) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), e5_(e5), e6_(e6), + e7_(e7), e8_(e8), e9_(e9), e10_(e10) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + MatcherCast(e1_), + MatcherCast(e2_), + MatcherCast(e3_), + MatcherCast(e4_), + MatcherCast(e5_), + MatcherCast(e6_), + MatcherCast(e7_), + MatcherCast(e8_), + MatcherCast(e9_), + MatcherCast(e10_), + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 10)); + } + + private: + 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_; +}; + +// Implements ElementsAreArray(). +template +class ElementsAreArrayMatcher { + public: + ElementsAreArrayMatcher(const T* first, size_t count) : + first_(first), count_(count) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); + } + + private: + const T* const first_; + const size_t count_; +}; + +} // namespace internal + +// ElementsAre(e0, e1, ..., e_n) matches an STL-style container with +// (n + 1) 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. +// +// 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::ElementsAreMatcher0 ElementsAre() { + return internal::ElementsAreMatcher0(); +} + +template +inline internal::ElementsAreMatcher1 ElementsAre(const T1& e1) { + return internal::ElementsAreMatcher1(e1); +} + +template +inline internal::ElementsAreMatcher2 ElementsAre(const T1& e1, + const T2& e2) { + return internal::ElementsAreMatcher2(e1, e2); +} + +template +inline internal::ElementsAreMatcher3 ElementsAre(const T1& e1, + const T2& e2, const T3& e3) { + return internal::ElementsAreMatcher3(e1, e2, e3); +} + +template +inline internal::ElementsAreMatcher4 ElementsAre(const T1& e1, + const T2& e2, const T3& e3, const T4& e4) { + return internal::ElementsAreMatcher4(e1, e2, e3, e4); +} + +template +inline internal::ElementsAreMatcher5 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) { + return internal::ElementsAreMatcher5(e1, e2, e3, e4, e5); +} + +template +inline internal::ElementsAreMatcher6 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) { + return internal::ElementsAreMatcher6(e1, e2, e3, e4, + e5, e6); +} + +template +inline internal::ElementsAreMatcher7 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) { + return internal::ElementsAreMatcher7(e1, e2, e3, + e4, e5, e6, e7); +} + +template +inline internal::ElementsAreMatcher8 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) { + return internal::ElementsAreMatcher8(e1, e2, + e3, e4, e5, e6, e7, e8); +} + +template +inline internal::ElementsAreMatcher9 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) { + return internal::ElementsAreMatcher9(e1, + e2, e3, e4, e5, e6, e7, e8, e9); +} + +template +inline internal::ElementsAreMatcher10 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) { + return internal::ElementsAreMatcher10(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); +} + +// ElementsAreArray(array) and ElementAreArray(array, count) are like +// ElementsAre(), except that they take an array of values or +// matchers. The former form infers the size of 'array', which must +// be a static C-style array. In the latter form, 'array' can either +// be a static array or a pointer to a dynamically created array. + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const T* first, size_t count) { + return internal::ElementsAreArrayMatcher(first, count); +} + +template +inline internal::ElementsAreArrayMatcher +ElementsAreArray(const T (&array)[N]) { + return internal::ElementsAreArrayMatcher(array, N); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump new file mode 100644 index 00000000..b45028ae --- /dev/null +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -0,0 +1,303 @@ +$$ -*- mode: c++; -*- +$$ This is a Pump source file. Please use Pump to convert it to +$$ gmock-generated-variadic-actions.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. + +// 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 + +namespace testing { +namespace internal { + +// Implements ElementsAre() and ElementsAreArray(). +template +class ElementsAreMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + // Constructs the matcher from a sequence of element values or + // element matchers. + template + ElementsAreMatcherImpl(InputIter first, size_t count) { + matchers_.reserve(count); + InputIter it = first; + for (size_t i = 0; i != count; ++i, ++it) { + matchers_.push_back(MatcherCast(*it)); + } + } + + // Returns true iff 'container' matches. + virtual bool Matches(Container container) const { + if (container.size() != count()) + return false; + + typename RawContainer::const_iterator container_iter = container.begin(); + for (size_t i = 0; i != count(); ++container_iter, ++i) { + if (!matchers_[i].Matches(*container_iter)) + return false; + } + + return true; + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + if (count() == 0) { + *os << "is empty"; + } else if (count() == 1) { + *os << "has 1 element that "; + matchers_[0].DescribeTo(os); + } else { + *os << "has " << Elements(count()) << " where\n"; + for (size_t i = 0; i != count(); ++i) { + *os << "element " << i << " "; + matchers_[i].DescribeTo(os); + if (i + 1 < count()) { + *os << ",\n"; + } + } + } + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + if (count() == 0) { + *os << "is not empty"; + return; + } + + *os << "does not have " << Elements(count()) << ", or\n"; + for (size_t i = 0; i != count(); ++i) { + *os << "element " << i << " "; + matchers_[i].DescribeNegationTo(os); + if (i + 1 < count()) { + *os << ", or\n"; + } + } + } + + // Explains why 'container' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(Container container, + ::std::ostream* os) const { + if (Matches(container)) { + // We need to explain why *each* element matches (the obvious + // ones can be skipped). + + bool reason_printed = false; + typename RawContainer::const_iterator container_iter = container.begin(); + for (size_t i = 0; i != count(); ++container_iter, ++i) { + ::std::stringstream ss; + matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + + const string s = ss.str(); + if (!s.empty()) { + if (reason_printed) { + *os << ",\n"; + } + *os << "element " << i << " " << s; + reason_printed = true; + } + } + } else { + // We need to explain why the container doesn't match. + const size_t actual_count = container.size(); + if (actual_count != count()) { + // The element count doesn't match. If the container is + // empty, there's no need to explain anything as Google Mock + // already prints the empty container. Otherwise we just need + // to show how many elements there actually are. + if (actual_count != 0) { + *os << "has " << Elements(actual_count); + } + return; + } + + // The container has the right size but at least one element + // doesn't match expectation. We need to find this element and + // explain why it doesn't match. + typename RawContainer::const_iterator container_iter = container.begin(); + for (size_t i = 0; i != count(); ++container_iter, ++i) { + if (matchers_[i].Matches(*container_iter)) { + continue; + } + + *os << "element " << i << " doesn't match"; + + ::std::stringstream ss; + matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + const string s = ss.str(); + if (!s.empty()) { + *os << " (" << s << ")"; + } + return; + } + } + } + + private: + static Message Elements(size_t count) { + return Message() << count << (count == 1 ? " element" : " elements"); + } + + size_t count() const { return matchers_.size(); } + std::vector > matchers_; +}; + +// Implements ElementsAre() of 0-10 arguments. + +class ElementsAreMatcher0 { + public: + ElementsAreMatcher0() {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher* const matchers = NULL; + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); + } +}; + + +$range i 1..n +$for i [[ +$range j 1..i +template <$for j, [[typename T$j]]> +class ElementsAreMatcher$i { + public: + $if i==1 [[explicit ]]ElementsAreMatcher$i($for j, [[const T$j& e$j]])$if i > 0 [[ : ]] + $for j, [[e$j[[]]_(e$j)]] {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + const Matcher matchers[] = { + +$for j [[ + MatcherCast(e$j[[]]_), + +]] + }; + + return MakeMatcher(new ElementsAreMatcherImpl(matchers, $i)); + } + + private: + +$for j [[ + const T$j& e$j[[]]_; + +]] +}; + + +]] +// Implements ElementsAreArray(). +template +class ElementsAreArrayMatcher { + public: + ElementsAreArrayMatcher(const T* first, size_t count) : + first_(first), count_(count) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef typename RawContainer::value_type Element; + + return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); + } + + private: + const T* const first_; + const size_t count_; +}; + +} // namespace internal + +// ElementsAre(e0, e1, ..., e_n) matches an STL-style container with +// (n + 1) 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. +// +// 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::ElementsAreMatcher0 ElementsAre() { + return internal::ElementsAreMatcher0(); +} + +$for i [[ +$range j 1..i + +template <$for j, [[typename T$j]]> +inline internal::ElementsAreMatcher$i<$for j, [[T$j]]> ElementsAre($for j, [[const T$j& e$j]]) { + return internal::ElementsAreMatcher$i<$for j, [[T$j]]>($for j, [[e$j]]); +} + +]] + +// ElementsAreArray(array) and ElementAreArray(array, count) are like +// ElementsAre(), except that they take an array of values or +// matchers. The former form infers the size of 'array', which must +// be a static C-style array. In the latter form, 'array' can either +// be a static array or a pointer to a dynamically created array. + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const T* first, size_t count) { + return internal::ElementsAreArrayMatcher(first, count); +} + +template +inline internal::ElementsAreArrayMatcher +ElementsAreArray(const T (&array)[N]) { + return internal::ElementsAreArrayMatcher(array, N); +} + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-nice-strict.h b/include/gmock/gmock-generated-nice-strict.h new file mode 100644 index 00000000..f961d796 --- /dev/null +++ b/include/gmock/gmock-generated-nice-strict.h @@ -0,0 +1,244 @@ +// This file was GENERATED by a script. 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 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), and StrictMock is a subclass of +// MockFoo that treats all uninteresting calls as errors. +// +// NiceMock and StrictMock "inherits" 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 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 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 +#include + +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() { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + template + NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + + template + NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + + virtual ~NiceMock() { + Mock::UnregisterCallReaction(internal::implicit_cast(this)); + } +}; + +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() { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + template + explicit StrictMock(const A1& a1) : MockClass(a1) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + template + StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, + const A4& a4) : MockClass(a1, a2, a3, a4) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + template + StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, + const A5& a5) : MockClass(a1, a2, a3, a4, a5) { + Mock::FailUninterestingCalls(internal::implicit_cast(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) { + Mock::FailUninterestingCalls(internal::implicit_cast(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) { + Mock::FailUninterestingCalls(internal::implicit_cast(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) { + Mock::FailUninterestingCalls(internal::implicit_cast(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) { + Mock::FailUninterestingCalls(internal::implicit_cast(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) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + virtual ~StrictMock() { + Mock::UnregisterCallReaction(internal::implicit_cast(this)); + } +}; + +// 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 and +// StrictMock cannot be nested. +template +class NiceMock >; +template +class NiceMock >; +template +class StrictMock >; +template +class StrictMock >; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/include/gmock/gmock-generated-nice-strict.h.pump b/include/gmock/gmock-generated-nice-strict.h.pump new file mode 100644 index 00000000..580e79f0 --- /dev/null +++ b/include/gmock/gmock-generated-nice-strict.h.pump @@ -0,0 +1,146 @@ +$$ -*- 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 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), and StrictMock is a subclass of +// MockFoo that treats all uninteresting calls as errors. +// +// NiceMock and StrictMock "inherits" 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 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 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 +#include + +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() { + Mock::AllowUninterestingCalls(internal::implicit_cast(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) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + +$range i 2..n +$for i [[ +$range j 1..i + template <$for j, [[typename A$j]]> + NiceMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { + Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + } + + +]] + virtual ~NiceMock() { + Mock::UnregisterCallReaction(internal::implicit_cast(this)); + } +}; + +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() { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + template + explicit StrictMock(const A1& a1) : MockClass(a1) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + +$for i [[ +$range j 1..i + template <$for j, [[typename A$j]]> + StrictMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { + Mock::FailUninterestingCalls(internal::implicit_cast(this)); + } + + +]] + virtual ~StrictMock() { + Mock::UnregisterCallReaction(internal::implicit_cast(this)); + } +}; + +// 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 and +// StrictMock cannot be nested. +template +class NiceMock >; +template +class NiceMock >; +template +class StrictMock >; +template +class StrictMock >; + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h new file mode 100644 index 00000000..69879a48 --- /dev/null +++ b/include/gmock/gmock-matchers.h @@ -0,0 +1,2094 @@ +// 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 // NOLINT +#include +#include +#include + +#include +#include +#include +#include + +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. + +// The implementation of a matcher. +template +class MatcherInterface { + public: + virtual ~MatcherInterface() {} + + // Returns true iff the matcher matches x. + virtual bool Matches(T x) 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. 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 << ")"; + } + + // Explains why x matches, or doesn't match, the matcher. Override + // this to provide any additional information that helps a user + // understand the match result. + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + // By default, nothing more needs to be explained, as Google Mock + // has already printed the value of x when this function is + // called. + } +}; + +namespace internal { + +// 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 this matcher matches x. + bool Matches(T x) const { return impl_->Matches(x); } + + // 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 { + impl_->ExplainMatchResultTo(x, os); + } + 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_; +}; + +// The default implementation of ExplainMatchResultTo() for +// polymorphic matchers. +template +inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& impl, const T& x, + ::std::ostream* os) { + // By default, nothing more needs to be said, as Google Mock already + // prints the value of x elsewhere. +} + +} // 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. + Matcher() {} + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows ipeople 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 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 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 +}; + +// 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 first provides a Impl class +// that has a Matches() method, a DescribeTo() method, and a +// DescribeNegationTo() method. The Matches() method is usually a +// method template (such that it works with multiple types). Then the +// user creates the polymorphic matcher using +// MakePolymorphicMatcher(). To provide additional explanation to the +// match result, define a FREE function (or function template) +// +// void ExplainMatchResultTo(const Impl& matcher, const Value& value, +// ::std::ostream* os); +// +// in the SAME NAME SPACE where Impl is defined. See the definition +// of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& impl) : impl_(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 bool Matches(T x) const { return impl_.Matches(x); } + + virtual void DescribeTo(::std::ostream* os) const { + impl_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + using ::testing::internal::ExplainMatchResultTo; + + // C++ uses Argument-Dependent Look-up (aka Koenig Look-up) to + // resolve the call to ExplainMatchResultTo() here. This + // means that if there's a ExplainMatchResultTo() function + // defined in the name space where class Impl is defined, it + // will be picked by the compiler as the better match. + // Otherwise the default implementation of it in + // ::testing::internal will be picked. + // + // This look-up rule lets a writer of a polymorphic matcher + // customize the behavior of ExplainMatchResultTo() when he + // cares to. Nothing needs to be done by the writer if he + // doesn't need to customize it. + ExplainMatchResultTo(impl_, x, os); + } + private: + const Impl impl_; + }; + + const Impl impl_; +}; + +// 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); +} + +// 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 +Matcher MatcherCast(M m); + +// 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 { + +// Appends the explanation on the result of matcher.Matches(value) to +// os iff the explanation is not empty. +template +void ExplainMatchResultAsNeededTo(const Matcher& matcher, T value, + ::std::ostream* os) { + ::std::stringstream reason; + matcher.ExplainMatchResultTo(value, &reason); + const internal::string s = reason.str(); + if (s != "") { + *os << " (" << s << ")"; + } +} + +// 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) { + using ::std::tr1::get; + return TuplePrefix::Matches(matcher_tuple, value_tuple) + && get(matcher_tuple).Matches(get(value_tuple)); + } + + // TuplePrefix::DescribeMatchFailuresTo(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 DescribeMatchFailuresTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { + using ::std::tr1::tuple_element; + using ::std::tr1::get; + + // First, describes failures in the first N - 1 fields. + TuplePrefix::DescribeMatchFailuresTo(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); + if (!matcher.Matches(value)) { + // 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 ExplainMatchResultTo() method handles the case when + // the address is interesting. + internal::UniversalPrinter:: + Print(value, os); + ExplainMatchResultAsNeededTo(matcher, value, 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 DescribeMatchFailuresTo(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) { + using ::std::tr1::tuple_size; + // Makes sure that matcher_tuple and value_tuple have the same + // number of fields. + GMOCK_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 DescribeMatchFailureTupleTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { + using ::std::tr1::tuple_size; + TuplePrefix::value>::DescribeMatchFailuresTo( + matchers, values, os); +} + +// 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)). +template +class MatcherCastImpl { + public: + static Matcher Cast(M polymorphic_matcher) { + return Matcher(polymorphic_matcher); + } +}; + +// 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 Matches(T x) const { + return source_matcher_.Matches(static_cast(x)); + } + + virtual void DescribeTo(::std::ostream* os) const { + source_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + source_matcher_.DescribeNegationTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + source_matcher_.ExplainMatchResultTo(static_cast(x), os); + } + private: + const Matcher source_matcher_; + }; +}; + +// 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; } +}; + +// Implements A(). +template +class AnyMatcherImpl : public MatcherInterface { + public: + virtual bool Matches(T x) 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. +// +// We define this as a macro in order to eliminate duplicated source +// code. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +#define GMOCK_IMPLEMENT_COMPARISON_MATCHER(name, op, relation) \ + template class name##Matcher { \ + public: \ + explicit name##Matcher(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 Matches(Lhs lhs) const { return lhs op rhs_; } \ + virtual void DescribeTo(::std::ostream* os) const { \ + *os << "is " relation " "; \ + UniversalPrinter::Print(rhs_, os); \ + } \ + virtual void DescribeNegationTo(::std::ostream* os) const { \ + *os << "is not " relation " "; \ + UniversalPrinter::Print(rhs_, os); \ + } \ + private: \ + Rhs rhs_; \ + }; \ + Rhs rhs_; \ + } + +// Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v) +// respectively. +GMOCK_IMPLEMENT_COMPARISON_MATCHER(Eq, ==, "equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER(Ge, >=, "greater than or equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER(Gt, >, "greater than"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER(Le, <=, "less than or equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER(Lt, <, "less than"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER(Ne, !=, "not equal to"); + +#undef GMOCK_IMPLEMENT_COMPARISON_MATCHER + +// Implements the polymorphic NotNull() matcher, which matches any +// pointer that is not NULL. +class NotNullMatcher { + public: + template + bool Matches(T* p) const { return p != NULL; } + + void DescribeTo(::std::ostream* os) const { *os << "is not 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 + + // Matches() takes a Super& (as opposed to const Super&) in + // order to match the interface MatcherInterface. + virtual bool Matches(Super& x) const { return &x == &object_; } // NOLINT + + 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); + } + + virtual void ExplainMatchResultTo(Super& x, // NOLINT + ::std::ostream* os) const { + *os << "is located @" << static_cast(&x); + } + private: + const Super& object_; + }; + + T& object_; +}; + +// 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: + typedef typename StringType::const_pointer ConstCharPointer; + + StrEqualityMatcher(const StringType& str, bool expect_eq, + bool case_sensitive) + : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {} + + // When expect_eq_ is true, returns true iff s is equal to string_; + // otherwise returns true iff s is not equal to string_. + bool Matches(ConstCharPointer s) const { + if (s == NULL) { + return !expect_eq_; + } + return Matches(StringType(s)); + } + + bool Matches(const StringType& s) const { + const bool eq = case_sensitive_ ? s == string_ : + CaseInsensitiveStringEquals(s, 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 << "is "; + if (!expect_eq) { + *os << "not "; + } + *os << "equal to "; + if (!case_sensitive_) { + *os << "(ignoring case) "; + } + UniversalPrinter::Print(string_, os); + } + + const StringType string_; + const bool expect_eq_; + const bool case_sensitive_; +}; + +// 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: + typedef typename StringType::const_pointer ConstCharPointer; + + explicit HasSubstrMatcher(const StringType& substring) + : substring_(substring) {} + + // These overloaded methods allow HasSubstr(substring) to be used as a + // Matcher as long as T can be converted to string. Returns true + // iff s contains substring_ as a substring. + bool Matches(ConstCharPointer s) const { + return s != NULL && Matches(StringType(s)); + } + + bool Matches(const StringType& s) const { + return s.find(substring_) != StringType::npos; + } + + // Describes what this matcher matches. + void DescribeTo(::std::ostream* os) const { + *os << "has substring "; + UniversalPrinter::Print(substring_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "has no substring "; + UniversalPrinter::Print(substring_, os); + } + private: + const StringType substring_; +}; + +// 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: + typedef typename StringType::const_pointer ConstCharPointer; + + explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) { + } + + // These overloaded methods allow StartsWith(prefix) to be used as a + // Matcher as long as T can be converted to string. Returns true + // iff s starts with prefix_. + bool Matches(ConstCharPointer s) const { + return s != NULL && Matches(StringType(s)); + } + + bool Matches(const StringType& s) const { + return s.length() >= prefix_.length() && + s.substr(0, prefix_.length()) == prefix_; + } + + void DescribeTo(::std::ostream* os) const { + *os << "starts with "; + UniversalPrinter::Print(prefix_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't start with "; + UniversalPrinter::Print(prefix_, os); + } + private: + const StringType prefix_; +}; + +// 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: + typedef typename StringType::const_pointer ConstCharPointer; + + explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {} + + // These overloaded methods allow EndsWith(suffix) to be used as a + // Matcher as long as T can be converted to string. Returns true + // iff s ends with suffix_. + bool Matches(ConstCharPointer s) const { + return s != NULL && Matches(StringType(s)); + } + + bool Matches(const StringType& s) const { + return s.length() >= suffix_.length() && + s.substr(s.length() - suffix_.length()) == suffix_; + } + + void DescribeTo(::std::ostream* os) const { + *os << "ends with "; + UniversalPrinter::Print(suffix_, os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't end with "; + UniversalPrinter::Print(suffix_, os); + } + private: + const StringType suffix_; +}; + +#if GMOCK_HAS_REGEX + +// 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) {} + + // These overloaded methods allow MatchesRegex(regex) to be used as + // a Matcher as long as T can be converted to string. Returns + // true iff s matches regular expression regex. When full_match_ is + // true, a full match is done; otherwise a partial match is done. + bool Matches(const char* s) const { + return s != NULL && Matches(internal::string(s)); + } + + bool Matches(const internal::string& s) const { + return full_match_ ? RE::FullMatch(s, *regex_) : + RE::PartialMatch(s, *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_; +}; + +#endif // GMOCK_HAS_REGEX + +// 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. +// +// We define this as a macro in order to eliminate duplicated source +// code. +#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER(name, op, relation) \ + class name##2Matcher { \ + public: \ + template \ + operator Matcher&>() const { \ + return MakeMatcher(new Impl); \ + } \ + private: \ + template \ + class Impl : public MatcherInterface&> { \ + public: \ + virtual bool Matches(const ::std::tr1::tuple& args) const { \ + return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ + } \ + virtual void DescribeTo(::std::ostream* os) const { \ + *os << "argument #0 is " relation " argument #1"; \ + } \ + virtual void DescribeNegationTo(::std::ostream* os) const { \ + *os << "argument #0 is not " relation " argument #1"; \ + } \ + }; \ + } + +// Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. +GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Eq, ==, "equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Ge, >=, "greater than or equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Gt, >, "greater than"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Le, <=, "less than or equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Lt, <, "less than"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Ne, !=, "not equal to"); + +#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER + +// 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 Impl(matcher_)); + } + private: + // Implements the Not(...) matcher for a particular argument type T. + template + class Impl : public MatcherInterface { + public: + explicit Impl(const Matcher& matcher) : matcher_(matcher) {} + + virtual bool Matches(T x) const { + return !matcher_.Matches(x); + } + + virtual void DescribeTo(::std::ostream* os) const { + matcher_.DescribeNegationTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + matcher_.DescribeTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + matcher_.ExplainMatchResultTo(x, os); + } + private: + const Matcher matcher_; + }; + + InnerMatcher matcher_; +}; + +// Used for implementing the AllOf(m_1, ..., m_n) matcher, which +// matches a value that matches all of the matchers m_1, ..., and m_n. +template +class BothOfMatcher { + public: + BothOfMatcher(Matcher1 matcher1, Matcher2 matcher2) + : matcher1_(matcher1), matcher2_(matcher2) {} + + // This template type conversion operator allows a + // BothOfMatcher object to match any type that + // both Matcher1 and Matcher2 can match. + template + operator Matcher() const { + return Matcher(new Impl(matcher1_, matcher2_)); + } + private: + // Implements the AllOf(m1, m2) matcher for a particular argument + // type T. + template + class Impl : public MatcherInterface { + public: + Impl(const Matcher& matcher1, const Matcher& matcher2) + : matcher1_(matcher1), matcher2_(matcher2) {} + + virtual bool Matches(T x) const { + return matcher1_.Matches(x) && matcher2_.Matches(x); + } + + 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 << "not "; + DescribeTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + if (Matches(x)) { + // When both matcher1_ and matcher2_ match x, we need to + // explain why *both* of them match. + ::std::stringstream ss1; + matcher1_.ExplainMatchResultTo(x, &ss1); + const internal::string s1 = ss1.str(); + + ::std::stringstream ss2; + matcher2_.ExplainMatchResultTo(x, &ss2); + const internal::string s2 = ss2.str(); + + if (s1 == "") { + *os << s2; + } else { + *os << s1; + if (s2 != "") { + *os << "; " << s2; + } + } + } else { + // Otherwise we only need to explain why *one* of them fails + // to match. + if (!matcher1_.Matches(x)) { + matcher1_.ExplainMatchResultTo(x, os); + } else { + matcher2_.ExplainMatchResultTo(x, os); + } + } + } + private: + const Matcher matcher1_; + const Matcher matcher2_; + }; + + Matcher1 matcher1_; + Matcher2 matcher2_; +}; + +// Used for implementing the AnyOf(m_1, ..., m_n) matcher, which +// matches a value that matches at least one of the matchers m_1, ..., +// and m_n. +template +class EitherOfMatcher { + public: + EitherOfMatcher(Matcher1 matcher1, Matcher2 matcher2) + : matcher1_(matcher1), matcher2_(matcher2) {} + + // This template type conversion operator allows a + // EitherOfMatcher object to match any type that + // both Matcher1 and Matcher2 can match. + template + operator Matcher() const { + return Matcher(new Impl(matcher1_, matcher2_)); + } + private: + // Implements the AnyOf(m1, m2) matcher for a particular argument + // type T. + template + class Impl : public MatcherInterface { + public: + Impl(const Matcher& matcher1, const Matcher& matcher2) + : matcher1_(matcher1), matcher2_(matcher2) {} + + virtual bool Matches(T x) const { + return matcher1_.Matches(x) || matcher2_.Matches(x); + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeTo(os); + *os << ") or ("; + matcher2_.DescribeTo(os); + *os << ")"; + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not "; + DescribeTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + if (Matches(x)) { + // If either matcher1_ or matcher2_ matches x, we just need + // to explain why *one* of them matches. + if (matcher1_.Matches(x)) { + matcher1_.ExplainMatchResultTo(x, os); + } else { + matcher2_.ExplainMatchResultTo(x, os); + } + } else { + // Otherwise we need to explain why *neither* matches. + ::std::stringstream ss1; + matcher1_.ExplainMatchResultTo(x, &ss1); + const internal::string s1 = ss1.str(); + + ::std::stringstream ss2; + matcher2_.ExplainMatchResultTo(x, &ss2); + const internal::string s2 = ss2.str(); + + if (s1 == "") { + *os << s2; + } else { + *os << s1; + if (s2 != "") { + *os << "; " << s2; + } + } + } + } + private: + const Matcher matcher1_; + const Matcher matcher2_; + }; + + Matcher1 matcher1_; + Matcher2 matcher2_; +}; + +// Used for implementing Truly(pred), which turns a predicate into a +// matcher. +template +class TrulyMatcher { + public: + explicit TrulyMatcher(Predicate pred) : predicate_(pred) {} + + // This method template allows Truly(pred) to be used as a matcher + // for type T where T is the argument type of predicate 'pred'. The + // argument is passed by reference as the predicate may be + // interested in the address of the argument. + template + bool Matches(T& x) const { +#ifdef GTEST_OS_WINDOWS + // MSVC warns about converting a value into bool (warning 4800). +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4800) // Temporarily disables warning 4800. +#endif // GTEST_OS_WINDOWS + return predicate_(x); +#ifdef GTEST_OS_WINDOWS +#pragma warning(pop) // Restores the warning state. +#endif // GTEST_OS_WINDOWS + } + + void DescribeTo(::std::ostream* os) const { + *os << "satisfies the given predicate"; + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't satisfy the given predicate"; + } + private: + Predicate predicate_; +}; + +// Used for implementing Matches(matcher), which turns a matcher into +// a predicate. +template +class MatcherAsPredicate { + public: + explicit MatcherAsPredicate(M matcher) : matcher_(matcher) {} + + // This template operator() allows Matches(m) to be used as a + // predicate on type T where m is a matcher on type T. + // + // The argument x is passed by reference instead of by value, as + // some matcher may be interested in its address (e.g. as in + // Matches(Ref(n))(x)). + template + bool operator()(const T& x) const { + // We let matcher_ commit to a particular type here instead of + // when the MatcherAsPredicate object was constructed. This + // allows us to write Matches(m) where m is a polymorphic matcher + // (e.g. Eq(5)). + // + // If we write Matcher(matcher_).Matches(x) here, it won't + // compile when matcher_ has type Matcher; if we write + // Matcher(matcher_).Matches(x) here, it won't compile + // when matcher_ has type Matcher; if we just write + // matcher_.Matches(x), it won't compile when matcher_ is + // polymorphic, e.g. Eq(5). + // + // MatcherCast() is necessary for making the code work + // in all of the above situations. + return MatcherCast(matcher_).Matches(x); + } + private: + M matcher_; +}; + +// For implementing ASSERT_THAT() and EXPECT_THAT(). The template +// argument M must be a type that can be converted to a matcher. +template +class PredicateFormatterFromMatcher { + public: + explicit PredicateFormatterFromMatcher(const M& m) : matcher_(m) {} + + // This template () operator allows a PredicateFormatterFromMatcher + // object to act as a predicate-formatter suitable for using with + // Google Test's EXPECT_PRED_FORMAT1() macro. + template + AssertionResult operator()(const char* value_text, const T& x) const { + // We convert matcher_ to a Matcher *now* instead of + // when the PredicateFormatterFromMatcher object was constructed, + // as matcher_ may be polymorphic (e.g. NotNull()) and we won't + // know which type to instantiate it to until we actually see the + // type of x here. + // + // We write MatcherCast(matcher_) instead of + // Matcher(matcher_), as the latter won't compile when + // matcher_ has type Matcher (e.g. An()). + const Matcher matcher = MatcherCast(matcher_); + if (matcher.Matches(x)) { + return AssertionSuccess(); + } else { + ::std::stringstream ss; + ss << "Value of: " << value_text << "\n" + << "Expected: "; + matcher.DescribeTo(&ss); + ss << "\n Actual: "; + UniversalPrinter::Print(x, &ss); + ExplainMatchResultAsNeededTo(matcher, x, &ss); + return AssertionFailure(Message() << ss.str()); + } + } + private: + const M matcher_; +}; + +// A helper function for converting a matcher to a predicate-formatter +// without the user needing to explicitly write the type. This is +// used for implementing ASSERT_THAT() and EXPECT_THAT(). +template +inline PredicateFormatterFromMatcher +MakePredicateFormatterFromMatcher(const M& matcher) { + return PredicateFormatterFromMatcher(matcher); +} + +// Implements the polymorphic floating point equality matcher, which +// matches two float values using ULP-based approximation. The +// template is meant to be instantiated with FloatType being either +// float or double. +template +class FloatingEqMatcher { + public: + // Constructor for FloatingEqMatcher. + // The matcher's input will be compared with rhs. The matcher treats two + // NANs as equal if nan_eq_nan is true. Otherwise, under IEEE standards, + // equality comparisons between NANs will always return false. + FloatingEqMatcher(FloatType rhs, bool nan_eq_nan) : + rhs_(rhs), nan_eq_nan_(nan_eq_nan) {} + + // Implements floating point equality matcher as a Matcher. + template + class Impl : public MatcherInterface { + public: + Impl(FloatType rhs, bool nan_eq_nan) : + rhs_(rhs), nan_eq_nan_(nan_eq_nan) {} + + virtual bool Matches(T value) const { + const FloatingPoint lhs(value), rhs(rhs_); + + // Compares NaNs first, if nan_eq_nan_ is true. + if (nan_eq_nan_ && lhs.is_nan()) { + return rhs.is_nan(); + } + + return lhs.AlmostEquals(rhs); + } + + virtual void DescribeTo(::std::ostream* os) const { + // os->precision() returns the previously set precision, which we + // store to restore the ostream to its original configuration + // after outputting. + const ::std::streamsize old_precision = os->precision( + ::std::numeric_limits::digits10 + 2); + if (FloatingPoint(rhs_).is_nan()) { + if (nan_eq_nan_) { + *os << "is NaN"; + } else { + *os << "never matches"; + } + } else { + *os << "is approximately " << rhs_; + } + os->precision(old_precision); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + // As before, get original precision. + const ::std::streamsize old_precision = os->precision( + ::std::numeric_limits::digits10 + 2); + if (FloatingPoint(rhs_).is_nan()) { + if (nan_eq_nan_) { + *os << "is not NaN"; + } else { + *os << "is anything"; + } + } else { + *os << "is not approximately " << rhs_; + } + // Restore original precision. + os->precision(old_precision); + } + + private: + const FloatType rhs_; + const bool nan_eq_nan_; + }; + + // The following 3 type conversion operators allow FloatEq(rhs) and + // NanSensitiveFloatEq(rhs) to be used as a Matcher, a + // Matcher, or a Matcher, but nothing else. + // (While Google's C++ coding style doesn't allow arguments passed + // by non-const reference, we may see them in code not conforming to + // the style. Therefore Google Mock needs to support them.) + operator Matcher() const { + return MakeMatcher(new Impl(rhs_, nan_eq_nan_)); + } + + operator Matcher() const { + return MakeMatcher(new Impl(rhs_, nan_eq_nan_)); + } + + operator Matcher() const { + return MakeMatcher(new Impl(rhs_, nan_eq_nan_)); + } + private: + const FloatType rhs_; + const bool nan_eq_nan_; +}; + +// Implements the Pointee(m) matcher for matching a pointer whose +// pointee matches matcher m. The pointer can be either raw or smart. +template +class PointeeMatcher { + public: + explicit PointeeMatcher(const InnerMatcher& matcher) : matcher_(matcher) {} + + // This type conversion operator template allows Pointee(m) to be + // used as a matcher for any pointer type whose pointee type is + // compatible with the inner matcher, where type Pointer can be + // either a raw pointer or a smart pointer. + // + // The reason we do this instead of relying on + // MakePolymorphicMatcher() is that the latter is not flexible + // enough for implementing the DescribeTo() method of Pointee(). + template + operator Matcher() const { + return MakeMatcher(new Impl(matcher_)); + } + private: + // The monomorphic implementation that works for a particular pointer type. + template + class Impl : public MatcherInterface { + public: + typedef typename PointeeOf::type Pointee; + + explicit Impl(const InnerMatcher& matcher) + : matcher_(MatcherCast(matcher)) {} + + virtual bool Matches(Pointer p) const { + return GetRawPointer(p) != NULL && matcher_.Matches(*p); + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "points to a value that "; + matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "does not point to a value that "; + matcher_.DescribeTo(os); + } + + virtual void ExplainMatchResultTo(Pointer pointer, + ::std::ostream* os) const { + if (GetRawPointer(pointer) == NULL) + return; + + ::std::stringstream ss; + matcher_.ExplainMatchResultTo(*pointer, &ss); + const internal::string s = ss.str(); + if (s != "") { + *os << "points to a value that " << s; + } + } + private: + const Matcher matcher_; + }; + + const InnerMatcher matcher_; +}; + +// Implements the Field() matcher for matching a field (i.e. member +// variable) of an object. +template +class FieldMatcher { + public: + FieldMatcher(FieldType Class::*field, + const Matcher& matcher) + : field_(field), matcher_(matcher) {} + + // Returns true iff the inner matcher matches obj.field. + bool Matches(const Class& obj) const { + return matcher_.Matches(obj.*field_); + } + + // Returns true iff the inner matcher matches obj->field. + bool Matches(const Class* p) const { + return (p != NULL) && matcher_.Matches(p->*field_); + } + + void DescribeTo(::std::ostream* os) const { + *os << "the given field "; + matcher_.DescribeTo(os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "the given field "; + matcher_.DescribeNegationTo(os); + } + + void ExplainMatchResultTo(const Class& obj, ::std::ostream* os) const { + ::std::stringstream ss; + matcher_.ExplainMatchResultTo(obj.*field_, &ss); + const internal::string s = ss.str(); + if (s != "") { + *os << "the given field " << s; + } + } + + void ExplainMatchResultTo(const Class* p, ::std::ostream* os) const { + if (p != NULL) { + ExplainMatchResultTo(*p, os); + } + } + private: + const FieldType Class::*field_; + const Matcher matcher_; +}; + +// Explains the result of matching an object against a field matcher. +template +void ExplainMatchResultTo(const FieldMatcher& matcher, + const Class& obj, ::std::ostream* os) { + matcher.ExplainMatchResultTo(obj, os); +} + +// Explains the result of matching a pointer against a field matcher. +template +void ExplainMatchResultTo(const FieldMatcher& matcher, + const Class* p, ::std::ostream* os) { + matcher.ExplainMatchResultTo(p, os); +} + +// Implements the Property() matcher for matching a property +// (i.e. return value of a getter method) of an object. +template +class PropertyMatcher { + public: + // The property may have a reference type, so 'const PropertyType&' + // may cause double references and fail to compile. That's why we + // need GMOCK_REFERENCE_TO_CONST, which works regardless of + // PropertyType being a reference or not. + typedef GMOCK_REFERENCE_TO_CONST(PropertyType) RefToConstProperty; + + PropertyMatcher(PropertyType (Class::*property)() const, + const Matcher& matcher) + : property_(property), matcher_(matcher) {} + + // Returns true iff obj.property() matches the inner matcher. + bool Matches(const Class& obj) const { + return matcher_.Matches((obj.*property_)()); + } + + // Returns true iff p->property() matches the inner matcher. + bool Matches(const Class* p) const { + return (p != NULL) && matcher_.Matches((p->*property_)()); + } + + void DescribeTo(::std::ostream* os) const { + *os << "the given property "; + matcher_.DescribeTo(os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "the given property "; + matcher_.DescribeNegationTo(os); + } + + void ExplainMatchResultTo(const Class& obj, ::std::ostream* os) const { + ::std::stringstream ss; + matcher_.ExplainMatchResultTo((obj.*property_)(), &ss); + const internal::string s = ss.str(); + if (s != "") { + *os << "the given property " << s; + } + } + + void ExplainMatchResultTo(const Class* p, ::std::ostream* os) const { + if (p != NULL) { + ExplainMatchResultTo(*p, os); + } + } + private: + PropertyType (Class::*property_)() const; + const Matcher matcher_; +}; + +// Explains the result of matching an object against a property matcher. +template +void ExplainMatchResultTo(const PropertyMatcher& matcher, + const Class& obj, ::std::ostream* os) { + matcher.ExplainMatchResultTo(obj, os); +} + +// Explains the result of matching a pointer against a property matcher. +template +void ExplainMatchResultTo(const PropertyMatcher& matcher, + const Class* p, ::std::ostream* os) { + matcher.ExplainMatchResultTo(p, os); +} + +// Type traits specifying various features of different functors for ResultOf. +// The default template specifies features for functor objects. +// Functor classes have to typedef argument_type and result_type +// to be compatible with ResultOf. +template +struct CallableTraits { + typedef typename Functor::result_type ResultType; + typedef Functor StorageType; + + static void CheckIsValid(Functor functor) {} + template + static ResultType Invoke(Functor f, T arg) { return f(arg); } +}; + +// Specialization for function pointers. +template +struct CallableTraits { + typedef ResType ResultType; + typedef ResType(*StorageType)(ArgType); + + static void CheckIsValid(ResType(*f)(ArgType)) { + GMOCK_CHECK_(f != NULL) + << "NULL function pointer is passed into ResultOf()."; + } + template + static ResType Invoke(ResType(*f)(ArgType), T arg) { + return (*f)(arg); + } +}; + +// Implements the ResultOf() matcher for matching a return value of a +// unary function of an object. +template +class ResultOfMatcher { + public: + typedef typename CallableTraits::ResultType ResultType; + + ResultOfMatcher(Callable callable, const Matcher& matcher) + : callable_(callable), matcher_(matcher) { + CallableTraits::CheckIsValid(callable_); + } + + template + operator Matcher() const { + return Matcher(new Impl(callable_, matcher_)); + } + + private: + typedef typename CallableTraits::StorageType CallableStorageType; + + template + class Impl : public MatcherInterface { + public: + Impl(CallableStorageType callable, const Matcher& matcher) + : callable_(callable), matcher_(matcher) {} + // Returns true iff callable_(obj) matches the inner matcher. + // The calling syntax is different for different types of callables + // so we abstract it in CallableTraits::Invoke(). + virtual bool Matches(T obj) const { + return matcher_.Matches( + CallableTraits::template Invoke(callable_, obj)); + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "result of the given callable "; + matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "result of the given callable "; + matcher_.DescribeNegationTo(os); + } + + virtual void ExplainMatchResultTo(T obj, ::std::ostream* os) const { + ::std::stringstream ss; + matcher_.ExplainMatchResultTo( + CallableTraits::template Invoke(callable_, obj), + &ss); + const internal::string s = ss.str(); + if (s != "") + *os << "result of the given callable " << s; + } + private: + // Functors often define operator() as non-const method even though + // they are actualy stateless. But we need to use them even when + // 'this' is a const pointer. It's the user's responsibility not to + // use stateful callables with ResultOf(), which does't guarantee + // how many times the callable will be invoked. + mutable CallableStorageType callable_; + const Matcher matcher_; + }; // class Impl + + const CallableStorageType callable_; + const Matcher matcher_; +}; + +// Explains the result of matching a value against a functor matcher. +template +void ExplainMatchResultTo(const ResultOfMatcher& matcher, + T obj, ::std::ostream* os) { + matcher.ExplainMatchResultTo(obj, os); +} + +} // namespace internal + +// Implements MatcherCast(). +template +inline Matcher MatcherCast(M matcher) { + return internal::MatcherCastImpl::Cast(matcher); +} + +// _ is a matcher that matches anything of any type. +// +// This definition is fine as: +// +// 1. The C++ standard permits using the name _ in a namespace that +// is not the global namespace or ::std. +// 2. The AnythingMatcher class has no data member or constructor, +// so it's OK to create global variables of this type. +// 3. c-style has approved of using _ in this case. +const internal::AnythingMatcher _ = {}; +// Creates a matcher that matches any value of the given type T. +template +inline Matcher A() { return MakeMatcher(new internal::AnyMatcherImpl()); } + +// Creates a matcher that matches any value of the given type T. +template +inline Matcher An() { return A(); } + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template +inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } + +// Constructs a Matcher from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template +Matcher::Matcher(T value) { *this = Eq(value); } + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) +// or Matcher(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher(Lt(5)) to be explicit about the type, +// for example. +template +inline Matcher TypedEq(const Rhs& rhs) { return Eq(rhs); } + +// Creates a polymorphic matcher that matches anything >= x. +template +inline internal::GeMatcher Ge(Rhs x) { + return internal::GeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template +inline internal::GtMatcher Gt(Rhs x) { + return internal::GtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template +inline internal::LeMatcher Le(Rhs x) { + return internal::LeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template +inline internal::LtMatcher Lt(Rhs x) { + return internal::LtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template +inline internal::NeMatcher Ne(Rhs x) { + return internal::NeMatcher(x); +} + +// Creates a polymorphic matcher that matches any non-NULL pointer. +// This is convenient as Not(NULL) doesn't compile (the compiler +// thinks that that expression is comparing a pointer with an integer). +inline PolymorphicMatcher NotNull() { + return MakePolymorphicMatcher(internal::NotNullMatcher()); +} + +// Creates a polymorphic matcher that matches any argument that +// references variable x. +template +inline internal::RefMatcher Ref(T& x) { // NOLINT + return internal::RefMatcher(x); +} + +// Creates a matcher that matches any double argument approximately +// equal to rhs, where two NANs are considered unequal. +inline internal::FloatingEqMatcher DoubleEq(double rhs) { + return internal::FloatingEqMatcher(rhs, false); +} + +// Creates a matcher that matches any double argument approximately +// equal to rhs, including NaN values when rhs is NaN. +inline internal::FloatingEqMatcher NanSensitiveDoubleEq(double rhs) { + return internal::FloatingEqMatcher(rhs, true); +} + +// Creates a matcher that matches any float argument approximately +// equal to rhs, where two NANs are considered unequal. +inline internal::FloatingEqMatcher FloatEq(float rhs) { + return internal::FloatingEqMatcher(rhs, false); +} + +// Creates a matcher that matches any double argument approximately +// equal to rhs, including NaN values when rhs is NaN. +inline internal::FloatingEqMatcher NanSensitiveFloatEq(float rhs) { + return internal::FloatingEqMatcher(rhs, true); +} + +// Creates a matcher that matches a pointer (raw or smart) that points +// to a value that matches inner_matcher. +template +inline internal::PointeeMatcher Pointee( + const InnerMatcher& inner_matcher) { + return internal::PointeeMatcher(inner_matcher); +} + +// Creates a matcher that matches an object whose given field matches +// 'matcher'. For example, +// Field(&Foo::number, Ge(5)) +// matches a Foo object x iff x.number >= 5. +template +inline PolymorphicMatcher< + internal::FieldMatcher > Field( + FieldType Class::*field, const FieldMatcher& matcher) { + return MakePolymorphicMatcher( + internal::FieldMatcher( + field, MatcherCast(matcher))); + // The call to MatcherCast() is required for supporting inner + // matchers of compatible types. For example, it allows + // Field(&Foo::bar, m) + // to compile where bar is an int32 and m is a matcher for int64. +} + +// Creates a matcher that matches an object whose given property +// matches 'matcher'. For example, +// Property(&Foo::str, StartsWith("hi")) +// matches a Foo object x iff x.str() starts with "hi". +template +inline PolymorphicMatcher< + internal::PropertyMatcher > Property( + PropertyType (Class::*property)() const, const PropertyMatcher& matcher) { + return MakePolymorphicMatcher( + internal::PropertyMatcher( + property, + MatcherCast(matcher))); + // The call to MatcherCast() is required for supporting inner + // matchers of compatible types. For example, it allows + // Property(&Foo::bar, m) + // to compile where bar() returns an int32 and m is a matcher for int64. +} + +// Creates a matcher that matches an object iff the result of applying +// a callable to x matches 'matcher'. +// For example, +// ResultOf(f, StartsWith("hi")) +// matches a Foo object x iff f(x) starts with "hi". +// callable parameter can be a function, function pointer, or a functor. +// Callable has to satisfy the following conditions: +// * It is required to keep no state affecting the results of +// the calls on it and make no assumptions about how many calls +// will be made. Any state it keeps must be protected from the +// concurrent access. +// * If it is a function object, it has to define type result_type. +// We recommend deriving your functor classes from std::unary_function. +template +internal::ResultOfMatcher ResultOf( + Callable callable, const ResultOfMatcher& matcher) { + return internal::ResultOfMatcher( + callable, + MatcherCast::ResultType>( + matcher)); + // The call to MatcherCast() is required for supporting inner + // matchers of compatible types. For example, it allows + // ResultOf(Function, m) + // to compile where Function() returns an int32 and m is a matcher for int64. +} + +// String matchers. + +// Matches a string equal to str. +inline PolymorphicMatcher > + StrEq(const internal::string& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, true, true)); +} + +// Matches a string not equal to str. +inline PolymorphicMatcher > + StrNe(const internal::string& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, false, true)); +} + +// Matches a string equal to str, ignoring case. +inline PolymorphicMatcher > + StrCaseEq(const internal::string& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, true, false)); +} + +// Matches a string not equal to str, ignoring case. +inline PolymorphicMatcher > + StrCaseNe(const internal::string& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, false, false)); +} + +// Creates a matcher that matches any string, std::string, or C string +// that contains the given substring. +inline PolymorphicMatcher > + HasSubstr(const internal::string& substring) { + return MakePolymorphicMatcher(internal::HasSubstrMatcher( + substring)); +} + +// Matches a string that starts with 'prefix' (case-sensitive). +inline PolymorphicMatcher > + StartsWith(const internal::string& prefix) { + return MakePolymorphicMatcher(internal::StartsWithMatcher( + prefix)); +} + +// Matches a string that ends with 'suffix' (case-sensitive). +inline PolymorphicMatcher > + EndsWith(const internal::string& suffix) { + return MakePolymorphicMatcher(internal::EndsWithMatcher( + suffix)); +} + +#ifdef GMOCK_HAS_REGEX + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher MatchesRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +inline PolymorphicMatcher MatchesRegex( + const internal::string& regex) { + return MatchesRegex(new internal::RE(regex)); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher ContainsRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +inline PolymorphicMatcher ContainsRegex( + const internal::string& regex) { + return ContainsRegex(new internal::RE(regex)); +} + +#endif // GMOCK_HAS_REGEX + +#if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING +// Wide string matchers. + +// Matches a string equal to str. +inline PolymorphicMatcher > + StrEq(const internal::wstring& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, true, true)); +} + +// Matches a string not equal to str. +inline PolymorphicMatcher > + StrNe(const internal::wstring& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, false, true)); +} + +// Matches a string equal to str, ignoring case. +inline PolymorphicMatcher > + StrCaseEq(const internal::wstring& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, true, false)); +} + +// Matches a string not equal to str, ignoring case. +inline PolymorphicMatcher > + StrCaseNe(const internal::wstring& str) { + return MakePolymorphicMatcher(internal::StrEqualityMatcher( + str, false, false)); +} + +// Creates a matcher that matches any wstring, std::wstring, or C wide string +// that contains the given substring. +inline PolymorphicMatcher > + HasSubstr(const internal::wstring& substring) { + return MakePolymorphicMatcher(internal::HasSubstrMatcher( + substring)); +} + +// Matches a string that starts with 'prefix' (case-sensitive). +inline PolymorphicMatcher > + StartsWith(const internal::wstring& prefix) { + return MakePolymorphicMatcher(internal::StartsWithMatcher( + prefix)); +} + +// Matches a string that ends with 'suffix' (case-sensitive). +inline PolymorphicMatcher > + EndsWith(const internal::wstring& suffix) { + return MakePolymorphicMatcher(internal::EndsWithMatcher( + suffix)); +} + +#endif // GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING + +// Creates a polymorphic matcher that matches a 2-tuple where the +// first field == the second field. +inline internal::Eq2Matcher Eq() { return internal::Eq2Matcher(); } + +// Creates a polymorphic matcher that matches a 2-tuple where the +// first field >= the second field. +inline internal::Ge2Matcher Ge() { return internal::Ge2Matcher(); } + +// Creates a polymorphic matcher that matches a 2-tuple where the +// first field > the second field. +inline internal::Gt2Matcher Gt() { return internal::Gt2Matcher(); } + +// Creates a polymorphic matcher that matches a 2-tuple where the +// first field <= the second field. +inline internal::Le2Matcher Le() { return internal::Le2Matcher(); } + +// Creates a polymorphic matcher that matches a 2-tuple where the +// first field < the second field. +inline internal::Lt2Matcher Lt() { return internal::Lt2Matcher(); } + +// Creates a polymorphic matcher that matches a 2-tuple where the +// first field != the second field. +inline internal::Ne2Matcher Ne() { return internal::Ne2Matcher(); } + +// Creates a matcher that matches any value of type T that m doesn't +// match. +template +inline internal::NotMatcher Not(InnerMatcher m) { + return internal::NotMatcher(m); +} + +// Creates a matcher that matches any value that matches all of the +// given matchers. +// +// For now we only support up to 5 matchers. Support for more +// matchers can be added as needed, or the user can use nested +// AllOf()s. +template +inline internal::BothOfMatcher +AllOf(Matcher1 m1, Matcher2 m2) { + return internal::BothOfMatcher(m1, m2); +} + +template +inline internal::BothOfMatcher > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { + return AllOf(m1, AllOf(m2, m3)); +} + +template +inline internal::BothOfMatcher > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { + return AllOf(m1, AllOf(m2, m3, m4)); +} + +template +inline internal::BothOfMatcher > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { + return AllOf(m1, AllOf(m2, m3, m4, m5)); +} + +// Creates a matcher that matches any value that matches at least one +// of the given matchers. +// +// For now we only support up to 5 matchers. Support for more +// matchers can be added as needed, or the user can use nested +// AnyOf()s. +template +inline internal::EitherOfMatcher +AnyOf(Matcher1 m1, Matcher2 m2) { + return internal::EitherOfMatcher(m1, m2); +} + +template +inline internal::EitherOfMatcher > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { + return AnyOf(m1, AnyOf(m2, m3)); +} + +template +inline internal::EitherOfMatcher > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { + return AnyOf(m1, AnyOf(m2, m3, m4)); +} + +template +inline internal::EitherOfMatcher > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5)); +} + +// Returns a matcher that matches anything that satisfies the given +// predicate. The predicate can be any unary function or functor +// whose return type can be implicitly converted to bool. +template +inline PolymorphicMatcher > +Truly(Predicate pred) { + return MakePolymorphicMatcher(internal::TrulyMatcher(pred)); +} + +// Returns a predicate that is satisfied by anything that matches the +// given matcher. +template +inline internal::MatcherAsPredicate Matches(M matcher) { + return internal::MatcherAsPredicate(matcher); +} + +// These macros allow using matchers to check values in Google Test +// tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher) +// succeed iff the value matches the matcher. If the assertion fails, +// the value and the description of the matcher will be printed. +#define ASSERT_THAT(value, matcher) ASSERT_PRED_FORMAT1(\ + ::testing::internal::MakePredicateFormatterFromMatcher(matcher), value) +#define EXPECT_THAT(value, matcher) EXPECT_PRED_FORMAT1(\ + ::testing::internal::MakePredicateFormatterFromMatcher(matcher), value) + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h new file mode 100644 index 00000000..628fc744 --- /dev/null +++ b/include/gmock/gmock-printers.h @@ -0,0 +1,514 @@ +// 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 a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. If both are defined, PrintTo() takes precedence. +// When T is a reference type, the address of the value is also +// printed. +// +// We also provide a convenient wrapper +// +// string ::testing::internal::UniversalPrinter::PrintAsString(value); + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ + +#include // NOLINT +#include +#include + +#include +#include +#include + +// Makes sure there is at least one << operator declared in the global +// namespace. This has no implementation and won't be called +// anywhere. We just need the declaration such that we can say "using +// ::operator <<;" in the definition of PrintTo() below. +void operator<<(::testing::internal::Unused, int); + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for type T. When T is +// ProtocolMessage, proto2::Message, or a subclass of those, kIsProto +// will be true and the short debug string of the protocol message +// value will be printed; otherwise kIsProto will be false and the +// bytes in the value will be printed. +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast(&value), + sizeof(value), os); + } +}; +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + // Both ProtocolMessage and proto2::Message have the + // ShortDebugString() method, so the same implementation works for + // both. + ::std::operator<<(*os, "<" + value.ShortDebugString() + ">"); + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its short debug string is printed; otherwise the +// bytes in the value are printed. This is what +// UniversalPrinter::Print() does when it knows nothing about type +// T and T has no << operator. +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +template +::std::ostream& operator<<(::std::ostream& os, const T& x) { + TypeWithoutFormatter::value>:: + PrintValue(x, &os); + return os; +} + +} // namespace internal2 + +namespace internal { + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(IsContainer, const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + PrintTo(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a value when the user doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer, const T& value, ::std::ostream* os) { + // If T has its << operator defined in the global namespace, which + // is not recommended but sometimes unavoidable (as in + // util/gtl/stl_logging-inl.h), the following statement makes it + // visible in this function. + // + // Without the statement, << in the global namespace would be hidden + // by the one in ::testing::internal2, due to the next using + // statement. + using ::operator <<; + + // When T doesn't come with a << operator, we want to fall back to + // the one defined in ::testing::internal2, which prints the bytes in + // the value. + using ::testing::internal2::operator <<; + + // Thanks to Koenig look-up, if type T has its own << operator + // defined in its namespace, which is the recommended way, that + // operator will be visible here. Since it is more specific than + // the generic one, it will be picked by the compiler in the + // following statement - exactly what we want. + *os << value; +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. If T is an STL-style + // container, the version for container will be called. Otherwise + // the generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, we believe the Google Mock's + // format is superior to what util/gtl/stl-logging.h offers. + // Therefore we don't want it to be accidentally overridden by the + // latter (even if the user includes stl-logging.h through other + // headers indirectly, Google Mock's format will still be used). + DefaultPrintTo(IsContainerTest(0), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +void PrintCharTo(char c, int char_code, ::std::ostream* os); +inline void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharTo(c, c, os); +} +inline void PrintTo(signed char c, ::std::ostream* os) { + PrintCharTo(c, c, os); +} +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(implicit_cast(s), os); +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(implicit_cast(s), os); +} +#endif + +// Overload for pointers that are neither char pointers nor member +// pointers. (A member variable pointer or member function pointer +// doesn't really points to a location in the address space. Their +// representation is implementation-defined. Therefore they will be +// printed as raw bytes.) +template +void PrintTo(T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // We cannot use implicit_cast or static_cast here, as they don't + // work when p is a function pointer. + *os << reinterpret_cast(p); + } +} + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrinter::Print(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrinter::Print(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_STD_STRING +void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_STD_STRING + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +// Overload for ::std::tr1::tuple. Needed for printing function +// arguments, which are packed as tuples. + +// This helper template allows PrintTo() for tuples to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. +template +struct TuplePrefixPrinter { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } +}; +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} +}; +template <> +struct TuplePrefixPrinter<1> { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); + } +}; + +// We support tuples of up-to 10 fields. Note that an N-tuple type is +// just an (N + 1)-tuple type where the last field has a special, +// unused type. +template +void PrintTo( + const ::std::tr1::tuple& t, + ::std::ostream* os) { + typedef ::std::tr1::tuple Tuple; + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + + // A convenient wrapper for Print() that returns the print-out as a + // string. + static string PrintAsString(const T& value) { + ::std::stringstream ss; + Print(value, &ss); + return ss.str(); + } + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + // Prints a char array as a C string. Note that we compare 'const + // T' with 'const char' instead of comparing T with char, in case + // that T is already a const type. + if (internal::type_equals::value) { + UniversalPrinter::Print(a, os); + return; + } + + if (N == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan): let the user control the threshold using a flag. + if (N <= kThreshold) { + PrintRawArrayTo(a, N, os); + } else { + PrintRawArrayTo(a, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(a + N - kChunkSize, kChunkSize, os); + } + *os << " }"; + } + } + + // A convenient wrapper for Print() that returns the print-out as a + // string. + static string PrintAsString(const T (&a)[N]) { + ::std::stringstream ss; + Print(a, &ss); + return ss.str(); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrinter::Print(value, os); + } + + // A convenient wrapper for Print() that returns the print-out as a + // string. + static string PrintAsString(const T& value) { + ::std::stringstream ss; + Print(value, &ss); + return ss.str(); + } + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +} // namespace internal +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h new file mode 100644 index 00000000..84e0b513 --- /dev/null +++ b/include/gmock/gmock-spec-builders.h @@ -0,0 +1,1568 @@ +// 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 the ON_CALL() and EXPECT_CALL() macros. +// +// A user can use the ON_CALL() macro to specify the default action of +// a mock method. The syntax is: +// +// ON_CALL(mock_object, Method(argument-matchers)) +// .WithArguments(multi-argument-matcher) +// .WillByDefault(action); +// +// where the .WithArguments() clause is optional. +// +// A user can use the EXPECT_CALL() macro to specify an expectation on +// a mock method. The syntax is: +// +// EXPECT_CALL(mock_object, Method(argument-matchers)) +// .WithArguments(multi-argument-matchers) +// .Times(cardinality) +// .InSequence(sequences) +// .WillOnce(action) +// .WillRepeatedly(action) +// .RetiresOnSaturation(); +// +// where all clauses are optional, .InSequence() and .WillOnce() can +// appear any number of times, and .Times() can be omitted only if +// .WillOnce() or .WillRepeatedly() is present. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace testing { + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +template +class FunctionMocker; + +// Base class for expectations. +class ExpectationBase; + +// Helper class for testing the Expectation class template. +class ExpectationTester; + +// Base class for function mockers. +template +class FunctionMockerBase; + +// Helper class for implementing FunctionMockerBase::InvokeWith(). +template +class InvokeWithHelper; + +// Protects the mock object registry (in class Mock), all function +// mockers, and all expectations. +// +// The reason we don't use more fine-grained protection is: when a +// mock function Foo() is called, it needs to consult its expectations +// to see which one should be picked. If another thread is allowed to +// call a mock function (either Foo() or a different one) at the same +// time, it could affect the "retired" attributes of Foo()'s +// expectations when InSequence() is used, and thus affect which +// expectation gets picked. Therefore, we sequence all mock function +// calls to ensure the integrity of the mock objects' states. +extern Mutex g_gmock_mutex; + +// Abstract base class of FunctionMockerBase. This is the +// type-agnostic part of the function mocker interface. Its pure +// virtual methods are implemented by FunctionMockerBase. +class UntypedFunctionMockerBase { + public: + virtual ~UntypedFunctionMockerBase() {} + + // Verifies that all expectations on this mock function have been + // satisfied. Reports one or more Google Test non-fatal failures + // and returns false if not. + // L >= g_gmock_mutex + virtual bool VerifyAndClearExpectationsLocked() = 0; + + // Clears the ON_CALL()s set on this mock function. + // L >= g_gmock_mutex + virtual void ClearDefaultActionsLocked() = 0; +}; // class UntypedFunctionMockerBase + +// This template class implements a default action spec (i.e. an +// ON_CALL() statement). +template +class DefaultActionSpec { + public: + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; + + // Constructs a DefaultActionSpec object from the information inside + // the parenthesis of an ON_CALL() statement. + DefaultActionSpec(const char* file, int line, + const ArgumentMatcherTuple& matchers) + : file_(file), + line_(line), + matchers_(matchers), + extra_matcher_(_), + last_clause_(NONE) { + } + + // Where in the source file was the default action spec defined? + const char* file() const { return file_; } + int line() const { return line_; } + + // Implements the .WithArguments() clause. + DefaultActionSpec& WithArguments(const Matcher& m) { + // Makes sure this is called at most once. + ExpectSpecProperty(last_clause_ < WITH_ARGUMENTS, + ".WithArguments() cannot appear " + "more than once in an ON_CALL()."); + last_clause_ = WITH_ARGUMENTS; + + extra_matcher_ = m; + return *this; + } + + // Implements the .WillByDefault() clause. + DefaultActionSpec& WillByDefault(const Action& action) { + ExpectSpecProperty(last_clause_ < WILL_BY_DEFAULT, + ".WillByDefault() must appear " + "exactly once in an ON_CALL()."); + last_clause_ = WILL_BY_DEFAULT; + + ExpectSpecProperty(!action.IsDoDefault(), + "DoDefault() cannot be used in ON_CALL()."); + action_ = action; + return *this; + } + + // Returns true iff the given arguments match the matchers. + bool Matches(const ArgumentTuple& args) const { + return TupleMatches(matchers_, args) && extra_matcher_.Matches(args); + } + + // Returns the action specified by the user. + const Action& GetAction() const { + AssertSpecProperty(last_clause_ == WILL_BY_DEFAULT, + ".WillByDefault() must appear exactly " + "once in an ON_CALL()."); + return action_; + } + private: + // Gives each clause in the ON_CALL() statement a name. + enum Clause { + // Do not change the order of the enum members! The run-time + // syntax checking relies on it. + NONE, + WITH_ARGUMENTS, + WILL_BY_DEFAULT, + }; + + // Asserts that the ON_CALL() statement has a certain property. + void AssertSpecProperty(bool property, const string& failure_message) const { + Assert(property, file_, line_, failure_message); + } + + // Expects that the ON_CALL() statement has a certain property. + void ExpectSpecProperty(bool property, const string& failure_message) const { + Expect(property, file_, line_, failure_message); + } + + // The information in statement + // + // ON_CALL(mock_object, Method(matchers)) + // .WithArguments(multi-argument-matcher) + // .WillByDefault(action); + // + // is recorded in the data members like this: + // + // source file that contains the statement => file_ + // line number of the statement => line_ + // matchers => matchers_ + // multi-argument-matcher => extra_matcher_ + // action => action_ + const char* file_; + int line_; + ArgumentMatcherTuple matchers_; + Matcher extra_matcher_; + Action action_; + + // The last clause in the ON_CALL() statement as seen so far. + // Initially NONE and changes as the statement is parsed. + Clause last_clause_; +}; // class DefaultActionSpec + +// Possible reactions on uninteresting calls. +enum CallReaction { + ALLOW, + WARN, + FAIL, +}; + +} // namespace internal + +// Utilities for manipulating mock objects. +class Mock { + public: + // The following public methods can be called concurrently. + + // Verifies and clears all expectations on the given mock object. + // If the expectations aren't satisfied, generates one or more + // Google Test non-fatal failures and returns false. + static bool VerifyAndClearExpectations(void* mock_obj); + + // Verifies all expectations on the given mock object and clears its + // default actions and expectations. Returns true iff the + // verification was successful. + static bool VerifyAndClear(void* mock_obj); + private: + // Needed for a function mocker to register itself (so that we know + // how to clear a mock object). + template + friend class internal::FunctionMockerBase; + + template + friend class internal::InvokeWithHelper; + + template + friend class NiceMock; + + template + friend class StrictMock; + + // Tells Google Mock to allow uninteresting calls on the given mock + // object. + // L < g_gmock_mutex + static void AllowUninterestingCalls(const void* mock_obj); + + // Tells Google Mock to warn the user about uninteresting calls on + // the given mock object. + // L < g_gmock_mutex + static void WarnUninterestingCalls(const void* mock_obj); + + // Tells Google Mock to fail uninteresting calls on the given mock + // object. + // L < g_gmock_mutex + static void FailUninterestingCalls(const void* mock_obj); + + // Tells Google Mock the given mock object is being destroyed and + // its entry in the call-reaction table should be removed. + // L < g_gmock_mutex + static void UnregisterCallReaction(const void* mock_obj); + + // Returns the reaction Google Mock will have on uninteresting calls + // made on the given mock object. + // L < g_gmock_mutex + static internal::CallReaction GetReactionOnUninterestingCalls( + const void* mock_obj); + + // Verifies that all expectations on the given mock object have been + // satisfied. Reports one or more Google Test non-fatal failures + // and returns false if not. + // L >= g_gmock_mutex + static bool VerifyAndClearExpectationsLocked(void* mock_obj); + + // Clears all ON_CALL()s set on the given mock object. + // L >= g_gmock_mutex + static void ClearDefaultActionsLocked(void* mock_obj); + + // Registers a mock object and a mock method it owns. + // L < g_gmock_mutex + static void Register(const void* mock_obj, + internal::UntypedFunctionMockerBase* mocker); + + // Unregisters a mock method; removes the owning mock object from + // the registry when the last mock method associated with it has + // been unregistered. This is called only in the destructor of + // FunctionMockerBase. + // L >= g_gmock_mutex + static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker); +}; // class Mock + +// Sequence objects are used by a user to specify the relative order +// in which the expectations should match. They are copyable (we rely +// on the compiler-defined copy constructor and assignment operator). +class Sequence { + public: + // Constructs an empty sequence. + Sequence() + : last_expectation_( + new internal::linked_ptr(NULL)) {} + + // Adds an expectation to this sequence. The caller must ensure + // that no other thread is accessing this Sequence object. + void AddExpectation( + const internal::linked_ptr& expectation) const; + private: + // The last expectation in this sequence. We use a nested + // linked_ptr here because: + // - Sequence objects are copyable, and we want the copies to act + // as aliases. The outer linked_ptr allows the copies to co-own + // and share the same state. + // - An Expectation object is co-owned (via linked_ptr) by its + // FunctionMocker and its successors (other Expectation objects). + // Hence the inner linked_ptr. + internal::linked_ptr > + last_expectation_; +}; // class Sequence + +// An object of this type causes all EXPECT_CALL() statements +// encountered in its scope to be put in an anonymous sequence. The +// work is done in the constructor and destructor. You should only +// create an InSequence object on the stack. +// +// The sole purpose for this class is to support easy definition of +// sequential expectations, e.g. +// +// { +// InSequence dummy; // The name of the object doesn't matter. +// +// // The following expectations must match in the order they appear. +// EXPECT_CALL(a, Bar())...; +// EXPECT_CALL(a, Baz())...; +// ... +// EXPECT_CALL(b, Xyz())...; +// } +// +// You can create InSequence objects in multiple threads, as long as +// they are used to affect different mock objects. The idea is that +// each thread can create and set up its own mocks as if it's the only +// thread. However, for clarity of your tests we recommend you to set +// up mocks in the main thread unless you have a good reason not to do +// so. +class InSequence { + public: + InSequence(); + ~InSequence(); + private: + bool sequence_created_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InSequence); // NOLINT +} GMOCK_ATTRIBUTE_UNUSED; + +namespace internal { + +// Points to the implicit sequence introduced by a living InSequence +// object (if any) in the current thread or NULL. +extern ThreadLocal g_gmock_implicit_sequence; + +// Base class for implementing expectations. +// +// There are two reasons for having a type-agnostic base class for +// Expectation: +// +// 1. We need to store collections of expectations of different +// types (e.g. all pre-requisites of a particular expectation, all +// expectations in a sequence). Therefore these expectation objects +// must share a common base class. +// +// 2. We can avoid binary code bloat by moving methods not depending +// on the template argument of Expectation to the base class. +// +// This class is internal and mustn't be used by user code directly. +class ExpectationBase { + public: + ExpectationBase(const char* file, int line); + + virtual ~ExpectationBase(); + + // Where in the source file was the expectation spec defined? + const char* file() const { return file_; } + int line() const { return line_; } + + // Returns the cardinality specified in the expectation spec. + const Cardinality& cardinality() const { return cardinality_; } + + // Describes the source file location of this expectation. + void DescribeLocationTo(::std::ostream* os) const { + *os << file() << ":" << line() << ": "; + } + + // Describes how many times a function call matching this + // expectation has occurred. + // L >= g_gmock_mutex + virtual void DescribeCallCountTo(::std::ostream* os) const = 0; + protected: + typedef std::set, + LinkedPtrLessThan > + ExpectationBaseSet; + + enum Clause { + // Don't change the order of the enum members! + NONE, + WITH_ARGUMENTS, + TIMES, + IN_SEQUENCE, + WILL_ONCE, + WILL_REPEATEDLY, + RETIRES_ON_SATURATION, + }; + + // Asserts that the EXPECT_CALL() statement has the given property. + void AssertSpecProperty(bool property, const string& failure_message) const { + Assert(property, file_, line_, failure_message); + } + + // Expects that the EXPECT_CALL() statement has the given property. + void ExpectSpecProperty(bool property, const string& failure_message) const { + Expect(property, file_, line_, failure_message); + } + + // Explicitly specifies the cardinality of this expectation. Used + // by the subclasses to implement the .Times() clause. + void SpecifyCardinality(const Cardinality& cardinality); + + // Returns true iff the user specified the cardinality explicitly + // using a .Times(). + bool cardinality_specified() const { return cardinality_specified_; } + + // Sets the cardinality of this expectation spec. + void set_cardinality(const Cardinality& cardinality) { + cardinality_ = cardinality; + } + + // The following group of methods should only be called after the + // EXPECT_CALL() statement, and only when g_gmock_mutex is held by + // the current thread. + + // Retires all pre-requisites of this expectation. + // L >= g_gmock_mutex + void RetireAllPreRequisites(); + + // Returns true iff this expectation is retired. + // L >= g_gmock_mutex + bool is_retired() const { + g_gmock_mutex.AssertHeld(); + return retired_; + } + + // Retires this expectation. + // L >= g_gmock_mutex + void Retire() { + g_gmock_mutex.AssertHeld(); + retired_ = true; + } + + // Returns true iff this expectation is satisfied. + // L >= g_gmock_mutex + bool IsSatisfied() const { + g_gmock_mutex.AssertHeld(); + return cardinality().IsSatisfiedByCallCount(call_count_); + } + + // Returns true iff this expectation is saturated. + // L >= g_gmock_mutex + bool IsSaturated() const { + g_gmock_mutex.AssertHeld(); + return cardinality().IsSaturatedByCallCount(call_count_); + } + + // Returns true iff this expectation is over-saturated. + // L >= g_gmock_mutex + bool IsOverSaturated() const { + g_gmock_mutex.AssertHeld(); + return cardinality().IsOverSaturatedByCallCount(call_count_); + } + + // Returns true iff all pre-requisites of this expectation are satisfied. + // L >= g_gmock_mutex + bool AllPrerequisitesAreSatisfied() const; + + // Adds unsatisfied pre-requisites of this expectation to 'result'. + // L >= g_gmock_mutex + void FindUnsatisfiedPrerequisites(ExpectationBaseSet* result) const; + + // Returns the number this expectation has been invoked. + // L >= g_gmock_mutex + int call_count() const { + g_gmock_mutex.AssertHeld(); + return call_count_; + } + + // Increments the number this expectation has been invoked. + // L >= g_gmock_mutex + void IncrementCallCount() { + g_gmock_mutex.AssertHeld(); + call_count_++; + } + + private: + friend class ::testing::Sequence; + friend class ::testing::internal::ExpectationTester; + + template + friend class Expectation; + + // This group of fields are part of the spec and won't change after + // an EXPECT_CALL() statement finishes. + const char* file_; // The file that contains the expectation. + int line_; // The line number of the expectation. + // True iff the cardinality is specified explicitly. + bool cardinality_specified_; + Cardinality cardinality_; // The cardinality of the expectation. + // The immediate pre-requisites of this expectation. We use + // linked_ptr in the set because we want an Expectation object to be + // co-owned by its FunctionMocker and its successors. This allows + // multiple mock objects to be deleted at different times. + ExpectationBaseSet immediate_prerequisites_; + + // This group of fields are the current state of the expectation, + // and can change as the mock function is called. + int call_count_; // How many times this expectation has been invoked. + bool retired_; // True iff this expectation has retired. +}; // class ExpectationBase + +// Impements an expectation for the given function type. +template +class Expectation : public ExpectationBase { + public: + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; + typedef typename Function::Result Result; + + Expectation(FunctionMockerBase* owner, const char* file, int line, + const ArgumentMatcherTuple& m) + : ExpectationBase(file, line), + owner_(owner), + matchers_(m), + extra_matcher_(_), + repeated_action_specified_(false), + repeated_action_(DoDefault()), + retires_on_saturation_(false), + last_clause_(NONE), + action_count_checked_(false) {} + + virtual ~Expectation() { + // Check the validity of the action count if it hasn't been done + // yet (for example, if the expectation was never used). + CheckActionCountIfNotDone(); + } + + // Implements the .WithArguments() clause. + Expectation& WithArguments(const Matcher& m) { + if (last_clause_ == WITH_ARGUMENTS) { + ExpectSpecProperty(false, + ".WithArguments() cannot appear " + "more than once in an EXPECT_CALL()."); + } else { + ExpectSpecProperty(last_clause_ < WITH_ARGUMENTS, + ".WithArguments() must be the first " + "clause in an EXPECT_CALL()."); + } + last_clause_ = WITH_ARGUMENTS; + + extra_matcher_ = m; + return *this; + } + + // Implements the .Times() clause. + Expectation& Times(const Cardinality& cardinality) { + if (last_clause_ ==TIMES) { + ExpectSpecProperty(false, + ".Times() cannot appear " + "more than once in an EXPECT_CALL()."); + } else { + ExpectSpecProperty(last_clause_ < TIMES, + ".Times() cannot appear after " + ".InSequence(), .WillOnce(), .WillRepeatedly(), " + "or .RetiresOnSaturation()."); + } + last_clause_ = TIMES; + + ExpectationBase::SpecifyCardinality(cardinality); + return *this; + } + + // Implements the .Times() clause. + Expectation& Times(int n) { + return Times(Exactly(n)); + } + + // Implements the .InSequence() clause. + Expectation& InSequence(const Sequence& s) { + ExpectSpecProperty(last_clause_ <= IN_SEQUENCE, + ".InSequence() cannot appear after .WillOnce()," + " .WillRepeatedly(), or " + ".RetiresOnSaturation()."); + last_clause_ = IN_SEQUENCE; + + s.AddExpectation(owner_->GetLinkedExpectationBase(this)); + return *this; + } + Expectation& InSequence(const Sequence& s1, const Sequence& s2) { + return InSequence(s1).InSequence(s2); + } + Expectation& InSequence(const Sequence& s1, const Sequence& s2, + const Sequence& s3) { + return InSequence(s1, s2).InSequence(s3); + } + Expectation& InSequence(const Sequence& s1, const Sequence& s2, + const Sequence& s3, const Sequence& s4) { + return InSequence(s1, s2, s3).InSequence(s4); + } + Expectation& InSequence(const Sequence& s1, const Sequence& s2, + const Sequence& s3, const Sequence& s4, + const Sequence& s5) { + return InSequence(s1, s2, s3, s4).InSequence(s5); + } + + // Implements the .WillOnce() clause. + Expectation& WillOnce(const Action& action) { + ExpectSpecProperty(last_clause_ <= WILL_ONCE, + ".WillOnce() cannot appear after " + ".WillRepeatedly() or .RetiresOnSaturation()."); + last_clause_ = WILL_ONCE; + + actions_.push_back(action); + if (!cardinality_specified()) { + set_cardinality(Exactly(static_cast(actions_.size()))); + } + return *this; + } + + // Implements the .WillRepeatedly() clause. + Expectation& WillRepeatedly(const Action& action) { + if (last_clause_ == WILL_REPEATEDLY) { + ExpectSpecProperty(false, + ".WillRepeatedly() cannot appear " + "more than once in an EXPECT_CALL()."); + } else { + ExpectSpecProperty(last_clause_ < WILL_REPEATEDLY, + ".WillRepeatedly() cannot appear " + "after .RetiresOnSaturation()."); + } + last_clause_ = WILL_REPEATEDLY; + repeated_action_specified_ = true; + + repeated_action_ = action; + if (!cardinality_specified()) { + set_cardinality(AtLeast(static_cast(actions_.size()))); + } + + // Now that no more action clauses can be specified, we check + // whether their count makes sense. + CheckActionCountIfNotDone(); + return *this; + } + + // Implements the .RetiresOnSaturation() clause. + Expectation& RetiresOnSaturation() { + ExpectSpecProperty(last_clause_ < RETIRES_ON_SATURATION, + ".RetiresOnSaturation() cannot appear " + "more than once."); + last_clause_ = RETIRES_ON_SATURATION; + retires_on_saturation_ = true; + + // Now that no more action clauses can be specified, we check + // whether their count makes sense. + CheckActionCountIfNotDone(); + return *this; + } + + // Returns the matchers for the arguments as specified inside the + // EXPECT_CALL() macro. + const ArgumentMatcherTuple& matchers() const { + return matchers_; + } + + // Returns the matcher specified by the .WithArguments() clause. + const Matcher& extra_matcher() const { + return extra_matcher_; + } + + // Returns the sequence of actions specified by the .WillOnce() clause. + const std::vector >& actions() const { return actions_; } + + // Returns the action specified by the .WillRepeatedly() clause. + const Action& repeated_action() const { return repeated_action_; } + + // Returns true iff the .RetiresOnSaturation() clause was specified. + bool retires_on_saturation() const { return retires_on_saturation_; } + + // Describes how many times a function call matching this + // expectation has occurred (implements + // ExpectationBase::DescribeCallCountTo()). + // L >= g_gmock_mutex + virtual void DescribeCallCountTo(::std::ostream* os) const { + g_gmock_mutex.AssertHeld(); + + // Describes how many times the function is expected to be called. + *os << " Expected: to be "; + cardinality().DescribeTo(os); + *os << "\n Actual: "; + Cardinality::DescribeActualCallCountTo(call_count(), os); + + // Describes the state of the expectation (e.g. is it satisfied? + // is it active?). + *os << " - " << (IsOverSaturated() ? "over-saturated" : + IsSaturated() ? "saturated" : + IsSatisfied() ? "satisfied" : "unsatisfied") + << " and " + << (is_retired() ? "retired" : "active"); + } + private: + template + friend class FunctionMockerBase; + + template + friend class InvokeWithHelper; + + // The following methods will be called only after the EXPECT_CALL() + // statement finishes and when the current thread holds + // g_gmock_mutex. + + // Returns true iff this expectation matches the given arguments. + // L >= g_gmock_mutex + bool Matches(const ArgumentTuple& args) const { + g_gmock_mutex.AssertHeld(); + return TupleMatches(matchers_, args) && extra_matcher_.Matches(args); + } + + // Returns true iff this expectation should handle the given arguments. + // L >= g_gmock_mutex + bool ShouldHandleArguments(const ArgumentTuple& args) const { + g_gmock_mutex.AssertHeld(); + + // In case the action count wasn't checked when the expectation + // was defined (e.g. if this expectation has no WillRepeatedly() + // or RetiresOnSaturation() clause), we check it when the + // expectation is used for the first time. + CheckActionCountIfNotDone(); + return !is_retired() && AllPrerequisitesAreSatisfied() && Matches(args); + } + + // Describes the result of matching the arguments against this + // expectation to the given ostream. + // L >= g_gmock_mutex + void DescribeMatchResultTo(const ArgumentTuple& args, + ::std::ostream* os) const { + g_gmock_mutex.AssertHeld(); + + if (is_retired()) { + *os << " Expected: the expectation is active\n" + << " Actual: it is retired\n"; + } else if (!Matches(args)) { + if (!TupleMatches(matchers_, args)) { + DescribeMatchFailureTupleTo(matchers_, args, os); + } + if (!extra_matcher_.Matches(args)) { + *os << " Expected: "; + extra_matcher_.DescribeTo(os); + *os << "\n Actual: false"; + + internal::ExplainMatchResultAsNeededTo( + extra_matcher_, args, os); + *os << "\n"; + } + } else if (!AllPrerequisitesAreSatisfied()) { + *os << " Expected: all pre-requisites are satisfied\n" + << " Actual: the following immediate pre-requisites " + << "are not satisfied:\n"; + ExpectationBaseSet unsatisfied_prereqs; + FindUnsatisfiedPrerequisites(&unsatisfied_prereqs); + int i = 0; + for (ExpectationBaseSet::const_iterator it = unsatisfied_prereqs.begin(); + it != unsatisfied_prereqs.end(); ++it) { + (*it)->DescribeLocationTo(os); + *os << "pre-requisite #" << i++ << "\n"; + } + *os << " (end of pre-requisites)\n"; + } else { + // This line is here just for completeness' sake. It will never + // be executed as currently the DescribeMatchResultTo() function + // is called only when the mock function call does NOT match the + // expectation. + *os << "The call matches the expectation.\n"; + } + } + + // Returns the action that should be taken for the current invocation. + // L >= g_gmock_mutex + const Action& GetCurrentAction(const FunctionMockerBase* mocker, + const ArgumentTuple& args) const { + g_gmock_mutex.AssertHeld(); + const int count = call_count(); + Assert(count >= 1, __FILE__, __LINE__, + "call_count() is <= 0 when GetCurrentAction() is " + "called - this should never happen."); + + const int action_count = static_cast(actions().size()); + if (action_count > 0 && !repeated_action_specified_ && + count > action_count) { + // If there is at least one WillOnce() and no WillRepeatedly(), + // we warn the user when the WillOnce() clauses ran out. + ::std::stringstream ss; + DescribeLocationTo(&ss); + ss << "Actions ran out.\n" + << "Called " << count << " times, but only " + << action_count << " WillOnce()" + << (action_count == 1 ? " is" : "s are") << " specified - "; + mocker->DescribeDefaultActionTo(args, &ss); + Log(WARNING, ss.str(), 1); + } + + return count <= action_count ? actions()[count - 1] : repeated_action(); + } + + // Given the arguments of a mock function call, if the call will + // over-saturate this expectation, returns the default action; + // otherwise, returns the next action in this expectation. Also + // describes *what* happened to 'what', and explains *why* Google + // Mock does it to 'why'. This method is not const as it calls + // IncrementCallCount(). + // L >= g_gmock_mutex + Action GetActionForArguments(const FunctionMockerBase* mocker, + const ArgumentTuple& args, + ::std::ostream* what, + ::std::ostream* why) { + g_gmock_mutex.AssertHeld(); + if (IsSaturated()) { + // We have an excessive call. + IncrementCallCount(); + *what << "Mock function called more times than expected - "; + mocker->DescribeDefaultActionTo(args, what); + DescribeCallCountTo(why); + + // TODO(wan): allow the user to control whether unexpected calls + // should fail immediately or continue using a flag + // --gmock_unexpected_calls_are_fatal. + return DoDefault(); + } + + IncrementCallCount(); + RetireAllPreRequisites(); + + if (retires_on_saturation() && IsSaturated()) { + Retire(); + } + + // Must be done after IncrementCount()! + *what << "Expected mock function call.\n"; + return GetCurrentAction(mocker, args); + } + + // Checks the action count (i.e. the number of WillOnce() and + // WillRepeatedly() clauses) against the cardinality if this hasn't + // been done before. Prints a warning if there are too many or too + // few actions. + // L < mutex_ + void CheckActionCountIfNotDone() const { + bool should_check = false; + { + MutexLock l(&mutex_); + if (!action_count_checked_) { + action_count_checked_ = true; + should_check = true; + } + } + + if (should_check) { + if (!cardinality_specified_) { + // The cardinality was inferred - no need to check the action + // count against it. + return; + } + + // The cardinality was explicitly specified. + const int action_count = static_cast(actions_.size()); + const int upper_bound = cardinality().ConservativeUpperBound(); + const int lower_bound = cardinality().ConservativeLowerBound(); + bool too_many; // True if there are too many actions, or false + // if there are too few. + if (action_count > upper_bound || + (action_count == upper_bound && repeated_action_specified_)) { + too_many = true; + } else if (0 < action_count && action_count < lower_bound && + !repeated_action_specified_) { + too_many = false; + } else { + return; + } + + ::std::stringstream ss; + DescribeLocationTo(&ss); + ss << "Too " << (too_many ? "many" : "few") + << " actions specified.\n" + << "Expected to be "; + cardinality().DescribeTo(&ss); + ss << ", but has " << (too_many ? "" : "only ") + << action_count << " WillOnce()" + << (action_count == 1 ? "" : "s"); + if (repeated_action_specified_) { + ss << " and a WillRepeatedly()"; + } + ss << "."; + Log(WARNING, ss.str(), -1); // -1 means "don't print stack trace". + } + } + + // All the fields below won't change once the EXPECT_CALL() + // statement finishes. + FunctionMockerBase* const owner_; + ArgumentMatcherTuple matchers_; + Matcher extra_matcher_; + std::vector > actions_; + bool repeated_action_specified_; // True if a WillRepeatedly() was specified. + Action repeated_action_; + bool retires_on_saturation_; + Clause last_clause_; + mutable bool action_count_checked_; // Under mutex_. + mutable Mutex mutex_; // Protects action_count_checked_. +}; // class Expectation + +// A MockSpec object is used by ON_CALL() or EXPECT_CALL() for +// specifying the default behavior of, or expectation on, a mock +// function. + +// Note: class MockSpec 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 MockSpec in +// ::testing::internal and import it into ::testing. + +template +class MockSpec { + public: + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + typedef typename internal::Function::ArgumentMatcherTuple + ArgumentMatcherTuple; + + // Constructs a MockSpec object, given the function mocker object + // that the spec is associated with. + explicit MockSpec(internal::FunctionMockerBase* function_mocker) + : function_mocker_(function_mocker) {} + + // Adds a new default action spec to the function mocker and returns + // the newly created spec. + internal::DefaultActionSpec& InternalDefaultActionSetAt( + const char* file, int line, const char* obj, const char* call) { + LogWithLocation(internal::INFO, file, line, + string("ON_CALL(") + obj + ", " + call + ") invoked"); + return function_mocker_->AddNewDefaultActionSpec(file, line, matchers_); + } + + // Adds a new expectation spec to the function mocker and returns + // the newly created spec. + internal::Expectation& InternalExpectedAt( + const char* file, int line, const char* obj, const char* call) { + LogWithLocation(internal::INFO, file, line, + string("EXPECT_CALL(") + obj + ", " + call + ") invoked"); + return function_mocker_->AddNewExpectation(file, line, matchers_); + } + + private: + template + friend class internal::FunctionMocker; + + void SetMatchers(const ArgumentMatcherTuple& matchers) { + matchers_ = matchers; + } + + // Logs a message including file and line number information. + void LogWithLocation(testing::internal::LogSeverity severity, + const char* file, int line, + const string& message) { + ::std::ostringstream s; + s << file << ":" << line << ": " << message << ::std::endl; + Log(severity, s.str(), 0); + } + + // The function mocker that owns this spec. + internal::FunctionMockerBase* const function_mocker_; + // The argument matchers specified in the spec. + ArgumentMatcherTuple matchers_; +}; // class MockSpec + +// MSVC warns about using 'this' in base member initializer list, so +// we need to temporarily disable the warning. We have to do it for +// the entire class to suppress the warning, even though it's about +// the constructor only. + +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4355) // Temporarily disables warning 4355. +#endif // _MSV_VER + +// The base of the function mocker class for the given function type. +// We put the methods in this class instead of its child to avoid code +// bloat. +template +class FunctionMockerBase : public UntypedFunctionMockerBase { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; + + FunctionMockerBase() : mock_obj_(NULL), name_(""), current_spec_(this) {} + + // The destructor verifies that all expectations on this mock + // function have been satisfied. If not, it will report Google Test + // non-fatal failures for the violations. + // L < g_gmock_mutex + virtual ~FunctionMockerBase() { + MutexLock l(&g_gmock_mutex); + VerifyAndClearExpectationsLocked(); + Mock::UnregisterLocked(this); + } + + // Returns the ON_CALL spec that matches this mock function with the + // given arguments; returns NULL if no matching ON_CALL is found. + // L = * + const DefaultActionSpec* FindDefaultActionSpec( + const ArgumentTuple& args) const { + for (typename std::vector >::const_reverse_iterator it + = default_actions_.rbegin(); + it != default_actions_.rend(); ++it) { + const DefaultActionSpec& spec = *it; + if (spec.Matches(args)) + return &spec; + } + + return NULL; + } + + // Performs the default action of this mock function on the given + // arguments and returns the result. This method doesn't depend on + // the mutable state of this object, and thus can be called + // concurrently without locking. + // L = * + Result PerformDefaultAction(const ArgumentTuple& args) const { + const DefaultActionSpec* const spec = FindDefaultActionSpec(args); + return (spec != NULL) ? spec->GetAction().Perform(args) + : DefaultValue::Get(); + } + + // Registers this function mocker and the mock object owning it; + // returns a reference to the function mocker object. This is only + // called by the ON_CALL() and EXPECT_CALL() macros. + FunctionMocker& RegisterOwner(const void* mock_obj) { + Mock::Register(mock_obj, this); + return *down_cast*>(this); + } + + // The following two functions are from UntypedFunctionMockerBase. + + // Verifies that all expectations on this mock function have been + // satisfied. Reports one or more Google Test non-fatal failures + // and returns false if not. + // L >= g_gmock_mutex + virtual bool VerifyAndClearExpectationsLocked(); + + // Clears the ON_CALL()s set on this mock function. + // L >= g_gmock_mutex + virtual void ClearDefaultActionsLocked() { + g_gmock_mutex.AssertHeld(); + default_actions_.clear(); + } + + // Sets the name of the function being mocked. Will be called upon + // each invocation of this mock function. + // L < g_gmock_mutex + void SetOwnerAndName(const void* mock_obj, const char* name) { + // We protect name_ under g_gmock_mutex in case this mock function + // is called from two threads concurrently. + MutexLock l(&g_gmock_mutex); + mock_obj_ = mock_obj; + name_ = name; + } + + // Returns the address of the mock object this method belongs to. + // Must be called after SetOwnerAndName() has been called. + // L < g_gmock_mutex + const void* MockObject() const { + const void* mock_obj; + { + // We protect mock_obj_ under g_gmock_mutex in case this mock + // function is called from two threads concurrently. + MutexLock l(&g_gmock_mutex); + mock_obj = mock_obj_; + } + return mock_obj; + } + + // Returns the name of the function being mocked. Must be called + // after SetOwnerAndName() has been called. + // L < g_gmock_mutex + const char* Name() const { + const char* name; + { + // We protect name_ under g_gmock_mutex in case this mock + // function is called from two threads concurrently. + MutexLock l(&g_gmock_mutex); + name = name_; + } + return name; + } + protected: + template + friend class MockSpec; + + template + friend class InvokeWithHelper; + + // Returns the result of invoking this mock function with the given + // arguments. This function can be safely called from multiple + // threads concurrently. + // L < g_gmock_mutex + Result InvokeWith(const ArgumentTuple& args) { + return InvokeWithHelper::InvokeAndPrintResult(this, args); + } + + // Adds and returns a default action spec for this mock function. + DefaultActionSpec& AddNewDefaultActionSpec( + const char* file, int line, + const ArgumentMatcherTuple& m) { + default_actions_.push_back(DefaultActionSpec(file, line, m)); + return default_actions_.back(); + } + + // Adds and returns an expectation spec for this mock function. + Expectation& AddNewExpectation( + const char* file, int line, + const ArgumentMatcherTuple& m) { + const linked_ptr > expectation( + new Expectation(this, file, line, m)); + expectations_.push_back(expectation); + + // Adds this expectation into the implicit sequence if there is one. + Sequence* const implicit_sequence = g_gmock_implicit_sequence.get(); + if (implicit_sequence != NULL) { + implicit_sequence->AddExpectation(expectation); + } + + return *expectation; + } + + // The current spec (either default action spec or expectation spec) + // being described on this function mocker. + MockSpec& current_spec() { return current_spec_; } + private: + template friend class Expectation; + + typedef std::vector > > Expectations; + + // Gets the internal::linked_ptr object that co-owns 'exp'. + internal::linked_ptr GetLinkedExpectationBase( + Expectation* exp) { + for (typename Expectations::const_iterator it = expectations_.begin(); + it != expectations_.end(); ++it) { + if (it->get() == exp) { + return *it; + } + } + + Assert(false, __FILE__, __LINE__, "Cannot find expectation."); + return internal::linked_ptr(NULL); + // The above statement is just to make the code compile, and will + // never be executed. + } + + // Some utilities needed for implementing InvokeWith(). + + // Describes what default action will be performed for the given + // arguments. + // L = * + void DescribeDefaultActionTo(const ArgumentTuple& args, + ::std::ostream* os) const { + const DefaultActionSpec* const spec = FindDefaultActionSpec(args); + + if (spec == NULL) { + *os << (internal::type_equals::value ? + "returning directly.\n" : + "returning default value.\n"); + } else { + *os << "taking default action specified at:\n" + << spec->file() << ":" << spec->line() << ":\n"; + } + } + + // Writes a message that the call is uninteresting (i.e. neither + // explicitly expected nor explicitly unexpected) to the given + // ostream. + // L < g_gmock_mutex + void DescribeUninterestingCall(const ArgumentTuple& args, + ::std::ostream* os) const { + *os << "Uninteresting mock function call - "; + DescribeDefaultActionTo(args, os); + *os << " Function call: " << Name(); + UniversalPrinter::Print(args, os); + } + + // Critical section: We must find the matching expectation and the + // corresponding action that needs to be taken in an ATOMIC + // transaction. Otherwise another thread may call this mock + // method in the middle and mess up the state. + // + // However, performing the action has to be left out of the critical + // section. The reason is that we have no control on what the + // action does (it can invoke an arbitrary user function or even a + // mock function) and excessive locking could cause a dead lock. + // L < g_gmock_mutex + bool FindMatchingExpectationAndAction( + const ArgumentTuple& args, Expectation** exp, Action* action, + bool* is_excessive, ::std::ostream* what, ::std::ostream* why) { + MutexLock l(&g_gmock_mutex); + *exp = this->FindMatchingExpectationLocked(args); + if (*exp == NULL) { // A match wasn't found. + *action = DoDefault(); + this->FormatUnexpectedCallMessageLocked(args, what, why); + return false; + } + + // This line must be done before calling GetActionForArguments(), + // which will increment the call count for *exp and thus affect + // its saturation status. + *is_excessive = (*exp)->IsSaturated(); + *action = (*exp)->GetActionForArguments(this, args, what, why); + return true; + } + + // Returns the expectation that matches the arguments, or NULL if no + // expectation matches them. + // L >= g_gmock_mutex + Expectation* FindMatchingExpectationLocked( + const ArgumentTuple& args) const { + g_gmock_mutex.AssertHeld(); + for (typename Expectations::const_reverse_iterator it = + expectations_.rbegin(); + it != expectations_.rend(); ++it) { + Expectation* const exp = it->get(); + if (exp->ShouldHandleArguments(args)) { + return exp; + } + } + return NULL; + } + + // Returns a message that the arguments don't match any expectation. + // L >= g_gmock_mutex + void FormatUnexpectedCallMessageLocked(const ArgumentTuple& args, + ::std::ostream* os, + ::std::ostream* why) const { + g_gmock_mutex.AssertHeld(); + *os << "\nUnexpected mock function call - "; + DescribeDefaultActionTo(args, os); + PrintTriedExpectationsLocked(args, why); + } + + // Prints a list of expectations that have been tried against the + // current mock function call. + // L >= g_gmock_mutex + void PrintTriedExpectationsLocked(const ArgumentTuple& args, + ::std::ostream* why) const { + g_gmock_mutex.AssertHeld(); + const int count = static_cast(expectations_.size()); + *why << "Google Mock tried the following " << count << " " + << (count == 1 ? "expectation, but it didn't match" : + "expectations, but none matched") + << ":\n"; + for (int i = 0; i < count; i++) { + *why << "\n"; + expectations_[i]->DescribeLocationTo(why); + if (count > 1) { + *why << "tried expectation #" << i; + } + *why << "\n"; + expectations_[i]->DescribeMatchResultTo(args, why); + expectations_[i]->DescribeCallCountTo(why); + } + } + + // Address of the mock object this mock method belongs to. + const void* mock_obj_; // Protected by g_gmock_mutex. + + // Name of the function being mocked. + const char* name_; // Protected by g_gmock_mutex. + + // The current spec (either default action spec or expectation spec) + // being described on this function mocker. + MockSpec current_spec_; + + // All default action specs for this function mocker. + std::vector > default_actions_; + // All expectations for this function mocker. + Expectations expectations_; +}; // class FunctionMockerBase + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif // _MSV_VER + +// Implements methods of FunctionMockerBase. + +// Verifies that all expectations on this mock function have been +// satisfied. Reports one or more Google Test non-fatal failures and +// returns false if not. +// L >= g_gmock_mutex +template +bool FunctionMockerBase::VerifyAndClearExpectationsLocked() { + g_gmock_mutex.AssertHeld(); + bool expectations_met = true; + for (typename Expectations::const_iterator it = expectations_.begin(); + it != expectations_.end(); ++it) { + Expectation* const exp = it->get(); + + if (exp->IsOverSaturated()) { + // There was an upper-bound violation. Since the error was + // already reported when it occurred, there is no need to do + // anything here. + expectations_met = false; + } else if (!exp->IsSatisfied()) { + expectations_met = false; + ::std::stringstream ss; + ss << "Actual function call count doesn't match this expectation.\n"; + // No need to show the source file location of the expectation + // in the description, as the Expect() call that follows already + // takes care of it. + exp->DescribeCallCountTo(&ss); + Expect(false, exp->file(), exp->line(), ss.str()); + } + } + expectations_.clear(); + return expectations_met; +} + +// Reports an uninteresting call (whose description is in msg) in the +// manner specified by 'reaction'. +void ReportUninterestingCall(CallReaction reaction, const string& msg); + +// When an uninteresting or unexpected mock function is called, we +// want to print its return value to assist the user debugging. Since +// there's nothing to print when the function returns void, we need to +// specialize the logic of FunctionMockerBase::InvokeWith() for +// void return values. +// +// C++ doesn't allow us to specialize a member function template +// unless we also specialize its enclosing class, so we had to let +// InvokeWith() delegate its work to a helper class InvokeWithHelper, +// which can then be specialized. +// +// Note that InvokeWithHelper must be a class template (as opposed to +// a function template), as only class templates can be partially +// specialized. +template +class InvokeWithHelper { + public: + typedef typename Function::ArgumentTuple ArgumentTuple; + + // Calculates the result of invoking the function mocked by mocker + // with the given arguments, prints it, and returns it. + // L < g_gmock_mutex + static Result InvokeAndPrintResult( + FunctionMockerBase* mocker, + const ArgumentTuple& args) { + if (mocker->expectations_.size() == 0) { + // No expectation is set on this mock method - we have an + // uninteresting call. + + // Warns about the uninteresting call. + ::std::stringstream ss; + mocker->DescribeUninterestingCall(args, &ss); + + // We must get Google Mock's reaction on uninteresting calls + // made on this mock object BEFORE performing the action, + // because the action may DELETE the mock object and make the + // following expression meaningless. + const CallReaction reaction = + Mock::GetReactionOnUninterestingCalls(mocker->MockObject()); + + // Calculates the function result. + Result result = mocker->PerformDefaultAction(args); + + // Prints the function result. + ss << "\n Returns: "; + UniversalPrinter::Print(result, &ss); + ReportUninterestingCall(reaction, ss.str()); + + return result; + } + + bool is_excessive = false; + ::std::stringstream ss; + ::std::stringstream why; + Action action; + Expectation* exp; + + // The FindMatchingExpectationAndAction() function acquires and + // releases g_gmock_mutex. + const bool found = mocker->FindMatchingExpectationAndAction( + args, &exp, &action, &is_excessive, &ss, &why); + ss << " Function call: " << mocker->Name(); + UniversalPrinter::Print(args, &ss); + Result result = + action.IsDoDefault() ? mocker->PerformDefaultAction(args) + : action.Perform(args); + ss << "\n Returns: "; + UniversalPrinter::Print(result, &ss); + ss << "\n" << why.str(); + + if (found) { + if (is_excessive) { + // We had an upper-bound violation and the failure message is in ss. + Expect(false, exp->file(), exp->line(), ss.str()); + } else { + // We had an expected call and the matching expectation is + // described in ss. + ::std::stringstream loc; + exp->DescribeLocationTo(&loc); + Log(INFO, loc.str() + ss.str(), 3); + } + } else { + // No expectation matches this call - reports a failure. + Expect(false, NULL, -1, ss.str()); + } + return result; + } +}; // class InvokeWithHelper + +// This specialization helps to implement +// FunctionMockerBase::InvokeWith() for void-returning functions. +template +class InvokeWithHelper { + public: + typedef typename Function::ArgumentTuple ArgumentTuple; + + // Invokes the function mocked by mocker with the given arguments. + // L < g_gmock_mutex + static void InvokeAndPrintResult(FunctionMockerBase* mocker, + const ArgumentTuple& args) { + const int count = static_cast(mocker->expectations_.size()); + if (count == 0) { + // No expectation is set on this mock method - we have an + // uninteresting call. + ::std::stringstream ss; + mocker->DescribeUninterestingCall(args, &ss); + + // We must get Google Mock's reaction on uninteresting calls + // made on this mock object BEFORE performing the action, + // because the action may DELETE the mock object and make the + // following expression meaningless. + const CallReaction reaction = + Mock::GetReactionOnUninterestingCalls(mocker->MockObject()); + + mocker->PerformDefaultAction(args); + ReportUninterestingCall(reaction, ss.str()); + return; + } + + bool is_excessive = false; + ::std::stringstream ss; + ::std::stringstream why; + Action action; + Expectation* exp; + + // The FindMatchingExpectationAndAction() function acquires and + // releases g_gmock_mutex. + const bool found = mocker->FindMatchingExpectationAndAction( + args, &exp, &action, &is_excessive, &ss, &why); + ss << " Function call: " << mocker->Name(); + UniversalPrinter::Print(args, &ss); + ss << "\n" << why.str(); + if (action.IsDoDefault()) { + mocker->PerformDefaultAction(args); + } else { + action.Perform(args); + } + + if (found) { + // A matching expectation and corresponding action were found. + if (is_excessive) { + // We had an upper-bound violation and the failure message is in ss. + Expect(false, exp->file(), exp->line(), ss.str()); + } else { + // We had an expected call and the matching expectation is + // described in ss. + ::std::stringstream loc; + exp->DescribeLocationTo(&loc); + Log(INFO, loc.str() + ss.str(), 3); + } + } else { + // No matching expectation was found - reports an error. + Expect(false, NULL, -1, ss.str()); + } + } +}; // class InvokeWithHelper + +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the MockSpec 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 MockSpec in ::testing. +using internal::MockSpec; + +// Const(x) is a convenient function for obtaining a const reference +// to x. This is useful for setting expectations on an overloaded +// const mock method, e.g. +// +// class MockFoo : public FooInterface { +// public: +// MOCK_METHOD0(Bar, int()); +// MOCK_CONST_METHOD0(Bar, int&()); +// }; +// +// MockFoo foo; +// // Expects a call to non-const MockFoo::Bar(). +// EXPECT_CALL(foo, Bar()); +// // Expects a call to const MockFoo::Bar(). +// EXPECT_CALL(Const(foo), Bar()); +template +inline const T& Const(const T& x) { return x; } + +} // namespace testing + +// A separate macro is required to avoid compile errors when the name +// of the method used in call is a result of macro expansion. +// See CompilesWithMethodNameExpandedFromMacro tests in +// internal/gmock-spec-builders_test.cc for more details. +#define ON_CALL_IMPL_(obj, call) \ + ((obj).gmock_##call).InternalDefaultActionSetAt(__FILE__, __LINE__, \ + #obj, #call) +#define ON_CALL(obj, call) ON_CALL_IMPL_(obj, call) + +#define EXPECT_CALL_IMPL_(obj, call) \ + ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call) +#define EXPECT_CALL(obj, call) EXPECT_CALL_IMPL_(obj, call) + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h new file mode 100644 index 00000000..9c9cdd91 --- /dev/null +++ b/include/gmock/gmock.h @@ -0,0 +1,92 @@ +// 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 is the main header file a user should include. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_H_ + +// This file implements the following syntax: +// +// ON_CALL(mock_object.Method(...)) +// .WithArguments(...) ? +// .WillByDefault(...); +// +// where WithArguments() is optional and WillByDefault() must appear +// exactly once. +// +// EXPECT_CALL(mock_object.Method(...)) +// .WithArguments(...) ? +// .Times(...) ? +// .InSequence(...) * +// .WillOnce(...) * +// .WillRepeatedly(...) ? +// .RetiresOnSaturation() ? ; +// +// where all clauses are optional and WillOnce() can be repeated. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace testing { + +// Declares Google Mock flags that we want a user to use programmatically. +GMOCK_DECLARE_string(verbose); + +// Initializes Google Mock. This must be called before running the +// tests. In particular, it parses the command line for the flags +// that Google Mock recognizes. Whenever a Google Mock flag is seen, +// it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Mock flag variables are +// updated. +// +// Since Google Test is needed for Google Mock to work, this function +// also initializes Google Test and parses its flags, if that hasn't +// been done. +void InitGoogleMock(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleMock(int* argc, wchar_t** argv); + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_H_ diff --git a/include/gmock/internal/gmock-generated-internal-utils.h b/include/gmock/internal/gmock-generated-internal-utils.h new file mode 100644 index 00000000..6386b05a --- /dev/null +++ b/include/gmock/internal/gmock-generated-internal-utils.h @@ -0,0 +1,277 @@ +// 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 contains template meta-programming utility classes needed +// for implementing Google Mock. + +#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ +#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ + +#include + +namespace testing { + +template +class Matcher; + +namespace internal { + +// An IgnoredValue object can be implicitly constructed from ANY value. +// This is used in implementing the IgnoreResult(a) action. +class IgnoredValue { + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + template + IgnoredValue(const T&) {} +}; + +// MatcherTuple::type is a tuple type where each field is a Matcher +// for the corresponding field in tuple type T. +template +struct MatcherTuple; + +template <> +struct MatcherTuple< ::std::tr1::tuple<> > { + typedef ::std::tr1::tuple< > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, + Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, Matcher, + Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, Matcher, + Matcher, Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, Matcher, + Matcher, Matcher, Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, Matcher, + Matcher, Matcher, Matcher, Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, Matcher, + Matcher, Matcher, Matcher, Matcher, Matcher > type; +}; + +template +struct MatcherTuple< ::std::tr1::tuple > { + typedef ::std::tr1::tuple, Matcher, Matcher, Matcher, + Matcher, Matcher, Matcher, Matcher, Matcher, + Matcher > type; +}; + +// Template struct Function, where F must be a function type, contains +// the following typedefs: +// +// Result: the function's return type. +// ArgumentN: the type of the N-th argument, where N starts with 1. +// ArgumentTuple: the tuple type consisting of all parameters of F. +// ArgumentMatcherTuple: the tuple type consisting of Matchers for all +// parameters of F. +// MakeResultVoid: the function type obtained by substituting void +// for the return type of F. +// MakeResultIgnoredValue: +// the function type obtained by substituting Something +// for the return type of F. +template +struct Function; + +template +struct Function { + typedef R Result; + typedef ::std::tr1::tuple<> ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(); + typedef IgnoredValue MakeResultIgnoredValue(); +}; + +template +struct Function + : Function { + typedef A1 Argument1; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1); + typedef IgnoredValue MakeResultIgnoredValue(A1); +}; + +template +struct Function + : Function { + typedef A2 Argument2; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2); +}; + +template +struct Function + : Function { + typedef A3 Argument3; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3); +}; + +template +struct Function + : Function { + typedef A4 Argument4; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4); +}; + +template +struct Function + : Function { + typedef A5 Argument5; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4, A5); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5); +}; + +template +struct Function + : Function { + typedef A6 Argument6; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6); +}; + +template +struct Function + : Function { + typedef A7 Argument7; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7); +}; + +template +struct Function + : Function { + typedef A8 Argument8; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8); +}; + +template +struct Function + : Function { + typedef A9 Argument9; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8, A9); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8, + A9); +}; + +template +struct Function + : Function { + typedef A10 Argument10; + typedef ::std::tr1::tuple ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); + typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8, + A9, A10); +}; + +} // namespace internal + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ diff --git a/include/gmock/internal/gmock-generated-internal-utils.h.pump b/include/gmock/internal/gmock-generated-internal-utils.h.pump new file mode 100644 index 00000000..f3128b04 --- /dev/null +++ b/include/gmock/internal/gmock-generated-internal-utils.h.pump @@ -0,0 +1,136 @@ +$$ -*- 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 contains template meta-programming utility classes needed +// for implementing Google Mock. + +#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ +#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ + +#include + +namespace testing { + +template +class Matcher; + +namespace internal { + +// An IgnoredValue object can be implicitly constructed from ANY value. +// This is used in implementing the IgnoreResult(a) action. +class IgnoredValue { + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + template + IgnoredValue(const T&) {} +}; + +// MatcherTuple::type is a tuple type where each field is a Matcher +// for the corresponding field in tuple type T. +template +struct MatcherTuple; + + +$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 matcher_As = [[$for j, [[Matcher]]]] +template <$typename_As> +struct MatcherTuple< ::std::tr1::tuple<$As> > { + typedef ::std::tr1::tuple<$matcher_As > type; +}; + + +]] +// Template struct Function, where F must be a function type, contains +// the following typedefs: +// +// Result: the function's return type. +// ArgumentN: the type of the N-th argument, where N starts with 1. +// ArgumentTuple: the tuple type consisting of all parameters of F. +// ArgumentMatcherTuple: the tuple type consisting of Matchers for all +// parameters of F. +// MakeResultVoid: the function type obtained by substituting void +// for the return type of F. +// MakeResultIgnoredValue: +// the function type obtained by substituting Something +// for the return type of F. +template +struct Function; + +template +struct Function { + typedef R Result; + typedef ::std::tr1::tuple<> ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid(); + typedef IgnoredValue MakeResultIgnoredValue(); +}; + + +$range i 1..n +$for i [[ +$range j 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var As = [[$for j, [[A$j]]]] +$var matcher_As = [[$for j, [[Matcher]]]] +$range k 1..i-1 +$var prev_As = [[$for k, [[A$k]]]] +template +struct Function + : Function { + typedef A$i Argument$i; + typedef ::std::tr1::tuple<$As> ArgumentTuple; + typedef typename MatcherTuple::type ArgumentMatcherTuple; + typedef void MakeResultVoid($As); + typedef IgnoredValue MakeResultIgnoredValue($As); +}; + + +]] +} // namespace internal + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h new file mode 100644 index 00000000..bdc82882 --- /dev/null +++ b/include/gmock/internal/gmock-internal-utils.h @@ -0,0 +1,339 @@ +// 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 defines some utilities useful for implementing Google +// Mock. They are subject to change without notice, so please DO NOT +// USE THEM IN USER CODE. + +#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_ +#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_ + +#include +#include // NOLINT +#include + +#include +#include +#include + +// Concatenates two pre-processor symbols; works for concatenating +// built-in macros like __FILE__ and __LINE__. +#define GMOCK_CONCAT_TOKEN_IMPL(foo, bar) foo##bar +#define GMOCK_CONCAT_TOKEN(foo, bar) GMOCK_CONCAT_TOKEN_IMPL(foo, bar) + +#ifdef __GNUC__ +#define GMOCK_ATTRIBUTE_UNUSED __attribute__ ((unused)) +#else +#define GMOCK_ATTRIBUTE_UNUSED +#endif // __GNUC__ + +class ProtocolMessage; +namespace proto2 { class Message; } + +namespace testing { +namespace internal { + +// Defining a variable of type CompileAssertTypesEqual will cause a +// compiler error iff T1 and T2 are different types. +template +struct CompileAssertTypesEqual; + +template +struct CompileAssertTypesEqual { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template +struct RemoveReference { typedef T type; }; // NOLINT +template +struct RemoveReference { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GMOCK_REMOVE_REFERENCE(T) \ + typename ::testing::internal::RemoveReference::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template +struct RemoveConst { typedef T type; }; // NOLINT +template +struct RemoveConst { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GMOCK_REMOVE_CONST(T) \ + typename ::testing::internal::RemoveConst::type + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GMOCK_ADD_REFERENCE(T) \ + typename ::testing::internal::AddReference::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GMOCK_REFERENCE_TO_CONST(T) \ + GMOCK_ADD_REFERENCE(const GMOCK_REMOVE_REFERENCE(T)) + +// PointeeOf::type is the type of a value pointed to by a +// Pointer, which can be either a smart pointer or a raw pointer. The +// following default implementation is for the case where Pointer is a +// smart pointer. +template +struct PointeeOf { + // Smart pointer classes define type element_type as the type of + // their pointees. + typedef typename Pointer::element_type type; +}; +// This specialization is for the raw pointer case. +template +struct PointeeOf { typedef T type; }; // NOLINT + +// GetRawPointer(p) returns the raw pointer underlying p when p is a +// smart pointer, or returns p itself when p is already a raw pointer. +// The following default implementation is for the smart pointer case. +template +inline typename Pointer::element_type* GetRawPointer(const Pointer& p) { + return p.get(); +} +// This overloaded version is for the raw pointer case. +template +inline Element* GetRawPointer(Element* p) { return p; } + +// This comparator allows linked_ptr to be stored in sets. +template +struct LinkedPtrLessThan { + bool operator()(const ::testing::internal::linked_ptr& lhs, + const ::testing::internal::linked_ptr& rhs) const { + return lhs.get() < rhs.get(); + } +}; + +// ImplicitlyConvertible::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4244) // Temporarily disables warning 4244. + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#pragma warning(pop) // Restores the warning state. +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template +const bool ImplicitlyConvertible::value; + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template +struct IsAProtocolMessage { + static const bool value = + ImplicitlyConvertible::value || + ImplicitlyConvertible::value; +}; +template +const bool IsAProtocolMessage::value; + +// When the compiler sees expression IsContainerTest(0), the first +// overload of IsContainerTest will be picked if C is an STL-style +// container class (since C::const_iterator* is a valid type and 0 can +// be converted to it), while the second overload will be picked +// otherwise (since C::const_iterator will be an invalid type in this +// case). Therefore, we can determine whether C is a container class +// by checking the type of IsContainerTest(0). The value of the +// expression is insignificant. +typedef int IsContainer; +template +IsContainer IsContainerTest(typename C::const_iterator*) { return 0; } + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(...) { return '\0'; } + +// This interface knows how to report a Google Mock failure (either +// non-fatal or fatal). +class FailureReporterInterface { + public: + // The type of a failure (either non-fatal or fatal). + enum FailureType { + NONFATAL, FATAL + }; + + virtual ~FailureReporterInterface() {} + + // Reports a failure that occurred at the given source file location. + virtual void ReportFailure(FailureType type, const char* file, int line, + const string& message) = 0; +}; + +// Returns the failure reporter used by Google Mock. +FailureReporterInterface* GetFailureReporter(); + +// Asserts that condition is true; aborts the process with the given +// message if condition is false. We cannot use LOG(FATAL) or CHECK() +// as Google Mock might be used to mock the log sink itself. We +// inline this function to prevent it from showing up in the stack +// trace. +inline void Assert(bool condition, const char* file, int line, + const string& msg) { + if (!condition) { + GetFailureReporter()->ReportFailure(FailureReporterInterface::FATAL, + file, line, msg); + } +} +inline void Assert(bool condition, const char* file, int line) { + Assert(condition, file, line, "Assertion failed."); +} + +// Verifies that condition is true; generates a non-fatal failure if +// condition is false. +inline void Expect(bool condition, const char* file, int line, + const string& msg) { + if (!condition) { + GetFailureReporter()->ReportFailure(FailureReporterInterface::NONFATAL, + file, line, msg); + } +} +inline void Expect(bool condition, const char* file, int line) { + Expect(condition, file, line, "Expectation failed."); +} + +// Severity level of a log. +enum LogSeverity { + INFO = 0, + WARNING = 1, +}; + +// Valid values for the --gmock_verbose flag. + +// All logs (informational and warnings) are printed. +const char kInfoVerbosity[] = "info"; +// Only warnings are printed. +const char kWarningVerbosity[] = "warning"; +// No logs are printed. +const char kErrorVerbosity[] = "error"; + +// Prints the given message to stdout iff 'severity' >= the level +// specified by the --gmock_verbose flag. If stack_frames_to_skip >= +// 0, also prints the stack trace excluding the top +// stack_frames_to_skip frames. In opt mode, any positive +// stack_frames_to_skip is treated as 0, since we don't know which +// function calls will be inlined by the compiler and need to be +// conservative. +void Log(LogSeverity severity, const string& message, int stack_frames_to_skip); + +// The universal value printer (public/gmock-printers.h) needs this +// to declare an unused << operator in the global namespace. +struct Unused {}; + +// Type traits. + +// is_reference::value is non-zero iff T is a reference type. +template struct is_reference : public false_type {}; +template struct is_reference : public true_type {}; + +// type_equals::value is non-zero iff T1 and T2 are the same type. +template struct type_equals : public false_type {}; +template struct type_equals : public true_type {}; + +// remove_reference::type removes the reference from type T, if any. +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +// Invalid() returns an invalid value of type T. This is useful +// when a value of type T is needed for compilation, but the statement +// will not really be executed (or we don't care if the statement +// crashes). +template +inline T Invalid() { + return *static_cast::type*>(NULL); +} +template <> +inline void Invalid() {} + +} // namespace internal +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_ diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h new file mode 100644 index 00000000..a39f77bc --- /dev/null +++ b/include/gmock/internal/gmock-port.h @@ -0,0 +1,314 @@ +// 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: vadimb@google.com (Vadim Berman) +// +// Low-level types and utilities for porting Google Mock to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. + +#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ +#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ + +#include +#include +#include + +// Most of the types needed for porting Google Mock are also required +// for Google Test and are defined in gtest-port.h. +#include +#include + +// To avoid conditional compilation everywhere, we make it +// gmock-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if defined(__GNUC__) +// GCC implements tr1/tuple in the header. This does not +// conform to the TR1 spec, which requires the header to be . +#include +#else +// If the compiler is not GCC, we assume the user is using a +// spec-conforming TR1 implementation. +#include +#endif // __GNUC__ + +#ifdef GTEST_OS_LINUX + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +#include // NOLINT + +// Defines this iff Google Mock uses the enhanced POSIX regular +// expression syntax. This is public as it affects how a user uses +// regular expression matchers. +#define GMOCK_USES_POSIX_RE 1 + +#endif // GTEST_OS_LINUX + +#if defined(GMOCK_USES_PCRE) || defined(GMOCK_USES_POSIX_RE) +// Defines this iff regular expression matchers are supported. This +// is public as it tells a user whether he can use regular expression +// matchers. +#define GMOCK_HAS_REGEX 1 +#endif // defined(GMOCK_USES_PCRE) || defined(GMOCK_USES_POSIX_RE) + +namespace testing { +namespace internal { + +// For Windows, check the compiler version. At least VS 2005 SP1 is +// required to compile Google Mock. +#ifdef GTEST_OS_WINDOWS + +#if _MSC_VER < 1400 +#error "At least Visual Studio 2005 SP1 is required to compile Google Mock." +#elif _MSC_VER == 1400 + +// Unfortunately there is no unique _MSC_VER number for SP1. So for VS 2005 +// we have to check if it has SP1 by checking whether a bug fixed in SP1 +// is present. The bug in question is +// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101702 +// where the compiler incorrectly reports sizeof(poiter to an array). + +class TestForSP1 { + private: // GCC complains if x_ is used by sizeof before defining it. + static char x_[100]; + // VS 2005 RTM incorrectly reports sizeof(&x) as 100, and that value + // is used to trigger 'invalid negative array size' error. If you + // see this error, upgrade to VS 2005 SP1 since Google Mock will not + // compile in VS 2005 RTM. + static char Google_Mock_requires_Visual_Studio_2005_SP1_or_later_to_compile_[ + sizeof(&x_) != 100 ? 1 : -1]; +}; + +#endif // _MSC_VER +#endif // GTEST_OS_WINDOWS + +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) { + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +template // use like this: down_cast(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + implicit_cast(0); + } + + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! + return static_cast(f); +} + +// The GMOCK_COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GMOCK_COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GMOCK_COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template +struct CompileAssert { +}; + +#define GMOCK_COMPILE_ASSERT(expr, msg) \ + typedef ::testing::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + +// Implementation details of GMOCK_COMPILE_ASSERT: +// +// - GMOCK_COMPILE_ASSERT works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GMOCK_COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GMOCK_COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// GMOCK_COMPILE_ASSERT(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#elif GTEST_HAS_STD_STRING +typedef ::std::string string; +#else +#error "Google Mock requires ::std::string to compile." +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GMOCK_CHECK_(boolean_condition); +// or +// GMOCK_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. + +class GMockCheckProvider { + public: + GMockCheckProvider(const char* condition, const char* file, int line) { + FormatFileLocation(file, line); + ::std::cerr << " ERROR: Condition " << condition << " failed. "; + } + ~GMockCheckProvider() { + ::std::cerr << ::std::endl; + abort(); + } + void FormatFileLocation(const char* file, int line) { + if (file == NULL) + file = "unknown file"; + if (line < 0) { + ::std::cerr << file << ":"; + } else { +#if _MSC_VER + ::std::cerr << file << "(" << line << "):"; +#else + ::std::cerr << file << ":" << line << ":"; +#endif + } + } + ::std::ostream& GetStream() { return ::std::cerr; } +}; +#define GMOCK_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (condition) \ + ; \ + else \ + ::testing::internal::GMockCheckProvider(\ + #condition, __FILE__, __LINE__).GetStream() + +} // namespace internal +} // namespace testing + +// Macro for referencing flags. +#define GMOCK_FLAG(name) FLAGS_gmock_##name + +// Macros for declaring flags. +#define GMOCK_DECLARE_bool(name) extern bool GMOCK_FLAG(name) +#define GMOCK_DECLARE_int32(name) \ + extern ::testing::internal::Int32 GMOCK_FLAG(name) +#define GMOCK_DECLARE_string(name) \ + extern ::testing::internal::String GMOCK_FLAG(name) + +// Macros for defining flags. +#define GMOCK_DEFINE_bool(name, default_val, doc) \ + bool GMOCK_FLAG(name) = (default_val) +#define GMOCK_DEFINE_int32(name, default_val, doc) \ + ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val) +#define GMOCK_DEFINE_string(name, default_val, doc) \ + ::testing::internal::String GMOCK_FLAG(name) = (default_val) + +#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ diff --git a/make/Makefile b/make/Makefile new file mode 100644 index 00000000..557eb1e1 --- /dev/null +++ b/make/Makefile @@ -0,0 +1,109 @@ +# A sample Makefile for building both Google Mock and Google Test and +# using them in user tests. This file is self-contained, so you don't +# need to use the Makefile in Google Test's source tree. Please tweak +# it to suit your environment and project. You may want to move it to +# your project's root directory. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. + +# Please tweak the following variable definitions as needed by your +# project, except GMOCK_HEADERS and GTEST_HEADERS, which you can use +# in your own targets but shouldn't modify. + +# Points to the root of Google Test, relative to where this file is. +# Remember to tweak this if you move this file, or if you want to use +# a copy of Google Test at a different location. +GTEST_DIR = ../gtest + +# Points to the root of Google Mock, relative to where this file is. +# Remember to tweak this if you move this file. +GMOCK_DIR = .. + +# Where to find user code. +USER_DIR = ../test + +# Flags passed to the preprocessor. +CPPFLAGS += -I$(GMOCK_DIR) -I$(GMOCK_DIR)/include \ + -I$(GTEST_DIR) -I$(GTEST_DIR)/include + +# Flags passed to the C++ compiler. +CXXFLAGS += -g + +# All tests produced by this Makefile. Remember to add new tests you +# created to the list. +TESTS = gmock_link_test gmock_test + +# All Google Test headers. Usually you shouldn't change this +# definition. +GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ + $(GTEST_DIR)/include/gtest/internal/*.h + +# All Google Mock headers. Note that all Google Test headers are +# included here too, as they are #included by Google Mock headers. +# Usually you shouldn't change this definition. +GMOCK_HEADERS = $(GMOCK_DIR)/include/gmock/*.h \ + $(GMOCK_DIR)/include/gmock/internal/*.h \ + $(GTEST_HEADERS) + +# House-keeping build targets. + +all : $(TESTS) + +clean : + rm -f $(TESTS) gmock.a gmock_main.a *.o + +# Builds gmock.a and gmock_main.a. These libraries contain both +# Google Mock and Google Test. A test should link with either gmock.a +# or gmock_main.a, depending on whether it defines its own main() +# function. It's fine if your test only uses features from Google +# Test (and not Google Mock). + +# Usually you shouldn't tweak such internal variables, indicated by a +# trailing _. +GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) +GMOCK_SRCS_ = $(GMOCK_DIR)/src/*.cc $(GMOCK_HEADERS) + +# For simplicity and to avoid depending on implementation details of +# Google Mock and Google Test, the dependencies specified below are +# conservative and not optimized. This is fine as Google Mock and +# Google Test compile fast and for ordinary users their source rarely +# changes. +gtest-all.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest-all.cc + +gmock-all.o : $(GMOCK_SRCS_) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_DIR)/src/gmock-all.cc + +gmock_main.o : $(GMOCK_SRCS_) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_DIR)/src/gmock_main.cc + +gmock.a : gmock-all.o gtest-all.o + $(AR) $(ARFLAGS) $@ $^ + +gmock_main.a : gmock-all.o gtest-all.o gmock_main.o + $(AR) $(ARFLAGS) $@ $^ + +# Builds a sample test. + +gmock-sample.o : $(USER_DIR)/gmock-sample.cc $(USER_DIR)/gmock-sample.h \ + $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock-sample.cc + +gmock_link_test.o : $(USER_DIR)/gmock_link_test.cc \ + $(USER_DIR)/gmock-sample.h $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link_test.cc + +gmock_link_test : gmock-sample.o gmock_link_test.o gmock_main.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ + +# Builds another sample test. + +gmock_test.o : $(USER_DIR)/gmock_test.cc $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_test.cc + +gmock_test : gmock_test.o gmock_main.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ diff --git a/scripts/generator/COPYING b/scripts/generator/COPYING new file mode 100644 index 00000000..87ea0636 --- /dev/null +++ b/scripts/generator/COPYING @@ -0,0 +1,203 @@ + + 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 [2007] Neal Norwitz + Portions Copyright [2007] Google Inc. + + 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/scripts/generator/README b/scripts/generator/README new file mode 100644 index 00000000..a3ba784b --- /dev/null +++ b/scripts/generator/README @@ -0,0 +1,33 @@ + +The Google Mock class generator is an application that is part of cppclean. +For more information about cppclean, see the README.cppclean file or +visit http://code.google.com/p/cppclean/ + +cppclean requires Python 2.4 or later. If you don't have Python installed +on your system, you will also need to install it. You can download Python +from: http://www.python.org/download/releases/ + +To use the Google Mock class generator, you need to call it +on the command line passing the header file and class for which you want +to generate a Google Mock class. + +Make sure to install the scripts somewhere in your path. Then you can +run the program. + + gmock_gen.py header-file.h ClassName + +To change the indentation from the default of 2, set INDENT in +the environment. For example to use an indent of 4 spaces: + +INDENT=4 gmock_gen.py header-file.h ClassName + +This version was made from SVN revision 279 in the cppclean repository. + +Known Limitations +----------------- +Not all code will be generated properly. For example, when mocking templated +classes, the template information is lost. You will need to add the template +information manually. + +Not all permutations of using multiple pointers/references will be rendered +properly. These will also have to be fixed manually. diff --git a/scripts/generator/README.cppclean b/scripts/generator/README.cppclean new file mode 100644 index 00000000..65431b61 --- /dev/null +++ b/scripts/generator/README.cppclean @@ -0,0 +1,115 @@ +Goal: +----- + CppClean attempts to find problems in C++ source that slow development + in large code bases, for example various forms of unused code. + Unused code can be unused functions, methods, data members, types, etc + to unnecessary #include directives. Unnecessary #includes can cause + considerable extra compiles increasing the edit-compile-run cycle. + + The project home page is: http://code.google.com/p/cppclean/ + + +Features: +--------- + * Find and print C++ language constructs: classes, methods, functions, etc. + * Find classes with virtual methods, no virtual destructor, and no bases + * Find global/static data that are potential problems when using threads + * Unnecessary forward class declarations + * Unnecessary function declarations + * Undeclared function definitions + * (planned) Find unnecessary header files #included + - No direct reference to anything in the header + - Header is unnecessary if classes were forward declared instead + * (planned) Source files that reference headers not directly #included, + ie, files that rely on a transitive #include from another header + * (planned) Unused members (private, protected, & public) methods and data + * (planned) Store AST in a SQL database so relationships can be queried + +AST is Abstract Syntax Tree, a representation of parsed source code. +http://en.wikipedia.org/wiki/Abstract_syntax_tree + + +System Requirements: +-------------------- + * Python 2.4 or later (2.3 probably works too) + * Works on Windows (untested), Mac OS X, and Unix + + +How to Run: +----------- + For all examples, it is assumed that cppclean resides in a directory called + /cppclean. + + To print warnings for classes with virtual methods, no virtual destructor and + no base classes: + + /cppclean/run.sh nonvirtual_dtors.py file1.h file2.h file3.cc ... + + To print all the functions defined in header file(s): + + /cppclean/run.sh functions.py file1.h file2.h ... + + All the commands take multiple files on the command line. Other programs + include: find_warnings, headers, methods, and types. Some other programs + are available, but used primarily for debugging. + + run.sh is a simple wrapper that sets PYTHONPATH to /cppclean and then + runs the program in /cppclean/cpp/PROGRAM.py. There is currently + no equivalent for Windows. Contributions for a run.bat file + would be greatly appreciated. + + +How to Configure: +----------------- + You can add a siteheaders.py file in /cppclean/cpp to configure where + to look for other headers (typically -I options passed to a compiler). + Currently two values are supported: _TRANSITIVE and GetIncludeDirs. + _TRANSITIVE should be set to a boolean value (True or False) indicating + whether to transitively process all header files. The default is False. + + GetIncludeDirs is a function that takes a single argument and returns + a sequence of directories to include. This can be a generator or + return a static list. + + def GetIncludeDirs(filename): + return ['/some/path/with/other/headers'] + + # Here is a more complicated example. + def GetIncludeDirs(filename): + yield '/path1' + yield os.path.join('/path2', os.path.dirname(filename)) + yield '/path3' + + +How to Test: +------------ + For all examples, it is assumed that cppclean resides in a directory called + /cppclean. The tests require + + cd /cppclean + make test + # To generate expected results after a change: + make expected + + +Current Status: +--------------- + The parser works pretty well for header files, parsing about 99% of Google's + header files. Anything which inspects structure of C++ source files should + work reasonably well. Function bodies are not transformed to an AST, + but left as tokens. Much work is still needed on finding unused header files + and storing an AST in a database. + + +Non-goals: +---------- + * Parsing all valid C++ source + * Handling invalid C++ source gracefully + * Compiling to machine code (or anything beyond an AST) + + +Contact: +-------- + If you used cppclean, I would love to hear about your experiences + cppclean@googlegroups.com. Even if you don't use cppclean, I'd like to + hear from you. :-) (You can contact me directly at: nnorwitz@gmail.com) diff --git a/scripts/generator/cpp/__init__.py b/scripts/generator/cpp/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/scripts/generator/cpp/ast.py b/scripts/generator/cpp/ast.py new file mode 100755 index 00000000..6d1c8d3e --- /dev/null +++ b/scripts/generator/cpp/ast.py @@ -0,0 +1,1713 @@ +#!/usr/bin/env python +# +# Copyright 2007 Neal Norwitz +# Portions Copyright 2007 Google Inc. +# +# 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. + +"""Generate an Abstract Syntax Tree (AST) for C++.""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + + +# TODO: +# * Tokens should never be exported, need to convert to Nodes +# (return types, parameters, etc.) +# * Handle static class data for templatized classes +# * Handle casts (both C++ and C-style) +# * Handle conditions and loops (if/else, switch, for, while/do) +# +# TODO much, much later: +# * Handle #define +# * exceptions + + +try: + # Python 3.x + import builtins +except ImportError: + # Python 2.x + import __builtin__ as builtins + +import sys +import traceback + +from cpp import keywords +from cpp import tokenize +from cpp import utils + + +if not hasattr(builtins, 'reversed'): + # Support Python 2.3 and earlier. + def reversed(seq): + for i in range(len(seq)-1, -1, -1): + yield seq[i] + +if not hasattr(builtins, 'next'): + # Support Python 2.5 and earlier. + def next(obj): + return obj.next() + + +VISIBILITY_PUBLIC, VISIBILITY_PROTECTED, VISIBILITY_PRIVATE = range(3) + +FUNCTION_NONE = 0x00 +FUNCTION_CONST = 0x01 +FUNCTION_VIRTUAL = 0x02 +FUNCTION_PURE_VIRTUAL = 0x04 +FUNCTION_CTOR = 0x08 +FUNCTION_DTOR = 0x10 +FUNCTION_ATTRIBUTE = 0x20 +FUNCTION_UNKNOWN_ANNOTATION = 0x40 +FUNCTION_THROW = 0x80 + +""" +These are currently unused. Should really handle these properly at some point. + +TYPE_MODIFIER_INLINE = 0x010000 +TYPE_MODIFIER_EXTERN = 0x020000 +TYPE_MODIFIER_STATIC = 0x040000 +TYPE_MODIFIER_CONST = 0x080000 +TYPE_MODIFIER_REGISTER = 0x100000 +TYPE_MODIFIER_VOLATILE = 0x200000 +TYPE_MODIFIER_MUTABLE = 0x400000 + +TYPE_MODIFIER_MAP = { + 'inline': TYPE_MODIFIER_INLINE, + 'extern': TYPE_MODIFIER_EXTERN, + 'static': TYPE_MODIFIER_STATIC, + 'const': TYPE_MODIFIER_CONST, + 'register': TYPE_MODIFIER_REGISTER, + 'volatile': TYPE_MODIFIER_VOLATILE, + 'mutable': TYPE_MODIFIER_MUTABLE, + } +""" + +_INTERNAL_TOKEN = 'internal' +_NAMESPACE_POP = 'ns-pop' + + +# TODO(nnorwitz): use this as a singleton for templated_types, etc +# where we don't want to create a new empty dict each time. It is also const. +class _NullDict(object): + __contains__ = lambda self: False + keys = values = items = iterkeys = itervalues = iteritems = lambda self: () + + +# TODO(nnorwitz): move AST nodes into a separate module. +class Node(object): + """Base AST node.""" + + def __init__(self, start, end): + self.start = start + self.end = end + + def IsDeclaration(self): + """Returns bool if this node is a declaration.""" + return False + + def IsDefinition(self): + """Returns bool if this node is a definition.""" + return False + + def IsExportable(self): + """Returns bool if this node exportable from a header file.""" + return False + + def Requires(self, node): + """Does this AST node require the definition of the node passed in?""" + return False + + def XXX__str__(self): + return self._StringHelper(self.__class__.__name__, '') + + def _StringHelper(self, name, suffix): + if not utils.DEBUG: + return '%s(%s)' % (name, suffix) + return '%s(%d, %d, %s)' % (name, self.start, self.end, suffix) + + def __repr__(self): + return str(self) + + +class Define(Node): + def __init__(self, start, end, name, definition): + Node.__init__(self, start, end) + self.name = name + self.definition = definition + + def __str__(self): + value = '%s %s' % (self.name, self.definition) + return self._StringHelper(self.__class__.__name__, value) + + +class Include(Node): + def __init__(self, start, end, filename, system): + Node.__init__(self, start, end) + self.filename = filename + self.system = system + + def __str__(self): + fmt = '"%s"' + if self.system: + fmt = '<%s>' + return self._StringHelper(self.__class__.__name__, fmt % self.filename) + + +class Goto(Node): + def __init__(self, start, end, label): + Node.__init__(self, start, end) + self.label = label + + def __str__(self): + return self._StringHelper(self.__class__.__name__, str(self.label)) + + +class Expr(Node): + def __init__(self, start, end, expr): + Node.__init__(self, start, end) + self.expr = expr + + def Requires(self, node): + # TODO(nnorwitz): impl. + return False + + def __str__(self): + return self._StringHelper(self.__class__.__name__, str(self.expr)) + + +class Return(Expr): + pass + + +class Delete(Expr): + pass + + +class Friend(Expr): + def __init__(self, start, end, expr, namespace): + Expr.__init__(self, start, end, expr) + self.namespace = namespace[:] + + +class Using(Node): + def __init__(self, start, end, names): + Node.__init__(self, start, end) + self.names = names + + def __str__(self): + return self._StringHelper(self.__class__.__name__, str(self.names)) + + +class Parameter(Node): + def __init__(self, start, end, name, parameter_type, default): + Node.__init__(self, start, end) + self.name = name + self.type = parameter_type + self.default = default + + def Requires(self, node): + # TODO(nnorwitz): handle namespaces, etc. + return self.type.name == node.name + + def __str__(self): + name = str(self.type) + suffix = '%s %s' % (name, self.name) + if self.default: + suffix += ' = ' + ''.join([d.name for d in self.default]) + return self._StringHelper(self.__class__.__name__, suffix) + + +class _GenericDeclaration(Node): + def __init__(self, start, end, name, namespace): + Node.__init__(self, start, end) + self.name = name + self.namespace = namespace[:] + + def FullName(self): + prefix = '' + if self.namespace and self.namespace[-1]: + prefix = '::'.join(self.namespace) + '::' + return prefix + self.name + + def _TypeStringHelper(self, suffix): + if self.namespace: + names = [n or '' for n in self.namespace] + suffix += ' in ' + '::'.join(names) + return self._StringHelper(self.__class__.__name__, suffix) + + +# TODO(nnorwitz): merge with Parameter in some way? +class VariableDeclaration(_GenericDeclaration): + def __init__(self, start, end, name, var_type, initial_value, namespace): + _GenericDeclaration.__init__(self, start, end, name, namespace) + self.type = var_type + self.initial_value = initial_value + + def Requires(self, node): + # TODO(nnorwitz): handle namespaces, etc. + return self.type.name == node.name + + def ToString(self): + """Return a string that tries to reconstitute the variable decl.""" + suffix = '%s %s' % (self.type, self.name) + if self.initial_value: + suffix += ' = ' + self.initial_value + return suffix + + def __str__(self): + return self._StringHelper(self.__class__.__name__, self.ToString()) + + +class Typedef(_GenericDeclaration): + def __init__(self, start, end, name, alias, namespace): + _GenericDeclaration.__init__(self, start, end, name, namespace) + self.alias = alias + + def IsDefinition(self): + return True + + def IsExportable(self): + return True + + def Requires(self, node): + # TODO(nnorwitz): handle namespaces, etc. + name = node.name + for token in self.alias: + if token is not None and name == token.name: + return True + return False + + def __str__(self): + suffix = '%s, %s' % (self.name, self.alias) + return self._TypeStringHelper(suffix) + + +class _NestedType(_GenericDeclaration): + def __init__(self, start, end, name, fields, namespace): + _GenericDeclaration.__init__(self, start, end, name, namespace) + self.fields = fields + + def IsDefinition(self): + return True + + def IsExportable(self): + return True + + def __str__(self): + suffix = '%s, {%s}' % (self.name, self.fields) + return self._TypeStringHelper(suffix) + + +class Union(_NestedType): + pass + + +class Enum(_NestedType): + pass + + +class Class(_GenericDeclaration): + def __init__(self, start, end, name, bases, templated_types, body, namespace): + _GenericDeclaration.__init__(self, start, end, name, namespace) + self.bases = bases + self.body = body + self.templated_types = templated_types + + def IsDeclaration(self): + return self.bases is None and self.body is None + + def IsDefinition(self): + return not self.IsDeclaration() + + def IsExportable(self): + return not self.IsDeclaration() + + def Requires(self, node): + # TODO(nnorwitz): handle namespaces, etc. + if self.bases: + for token_list in self.bases: + # TODO(nnorwitz): bases are tokens, do name comparision. + for token in token_list: + if token.name == node.name: + return True + # TODO(nnorwitz): search in body too. + return False + + def __str__(self): + name = self.name + if self.templated_types: + name += '<%s>' % self.templated_types + suffix = '%s, %s, %s' % (name, self.bases, self.body) + return self._TypeStringHelper(suffix) + + +class Struct(Class): + pass + + +class Function(_GenericDeclaration): + def __init__(self, start, end, name, return_type, parameters, + modifiers, templated_types, body, namespace): + _GenericDeclaration.__init__(self, start, end, name, namespace) + converter = TypeConverter(namespace) + self.return_type = converter.CreateReturnType(return_type) + self.parameters = converter.ToParameters(parameters) + self.modifiers = modifiers + self.body = body + self.templated_types = templated_types + + def IsDeclaration(self): + return self.body is None + + def IsDefinition(self): + return self.body is not None + + def IsExportable(self): + if self.return_type and 'static' in self.return_type.modifiers: + return False + return None not in self.namespace + + def Requires(self, node): + if self.parameters: + # TODO(nnorwitz): parameters are tokens, do name comparision. + for p in self.parameters: + if p.name == node.name: + return True + # TODO(nnorwitz): search in body too. + return False + + def __str__(self): + # TODO(nnorwitz): add templated_types. + suffix = ('%s %s(%s), 0x%02x, %s' % + (self.return_type, self.name, self.parameters, + self.modifiers, self.body)) + return self._TypeStringHelper(suffix) + + +class Method(Function): + def __init__(self, start, end, name, in_class, return_type, parameters, + modifiers, templated_types, body, namespace): + Function.__init__(self, start, end, name, return_type, parameters, + modifiers, templated_types, body, namespace) + # TODO(nnorwitz): in_class could also be a namespace which can + # mess up finding functions properly. + self.in_class = in_class + + +class Type(_GenericDeclaration): + """Type used for any variable (eg class, primitive, struct, etc).""" + + def __init__(self, start, end, name, templated_types, modifiers, + reference, pointer, array): + """ + Args: + name: str name of main type + templated_types: [Class (Type?)] template type info between <> + modifiers: [str] type modifiers (keywords) eg, const, mutable, etc. + reference, pointer, array: bools + """ + _GenericDeclaration.__init__(self, start, end, name, []) + self.templated_types = templated_types + if not name and modifiers: + self.name = modifiers.pop() + self.modifiers = modifiers + self.reference = reference + self.pointer = pointer + self.array = array + + def __str__(self): + prefix = '' + if self.modifiers: + prefix = ' '.join(self.modifiers) + ' ' + name = str(self.name) + if self.templated_types: + name += '<%s>' % self.templated_types + suffix = prefix + name + if self.reference: + suffix += '&' + if self.pointer: + suffix += '*' + if self.array: + suffix += '[]' + return self._TypeStringHelper(suffix) + + # By definition, Is* are always False. A Type can only exist in + # some sort of variable declaration, parameter, or return value. + def IsDeclaration(self): + return False + + def IsDefinition(self): + return False + + def IsExportable(self): + return False + + +class TypeConverter(object): + + def __init__(self, namespace_stack): + self.namespace_stack = namespace_stack + + def _GetTemplateEnd(self, tokens, start): + count = 1 + end = start + while 1: + token = tokens[end] + end += 1 + if token.name == '<': + count += 1 + elif token.name == '>': + count -= 1 + if count == 0: + break + return tokens[start:end-1], end + + def ToType(self, tokens): + """Convert [Token,...] to [Class(...), ] useful for base classes. + For example, code like class Foo : public Bar { ... }; + the "Bar" portion gets converted to an AST. + + Returns: + [Class(...), ...] + """ + result = [] + name_tokens = [] + reference = pointer = array = False + + def AddType(templated_types): + # Partition tokens into name and modifier tokens. + names = [] + modifiers = [] + for t in name_tokens: + if keywords.IsKeyword(t.name): + modifiers.append(t.name) + else: + names.append(t.name) + name = ''.join(names) + result.append(Type(name_tokens[0].start, name_tokens[-1].end, + name, templated_types, modifiers, + reference, pointer, array)) + del name_tokens[:] + + i = 0 + end = len(tokens) + while i < end: + token = tokens[i] + if token.name == '<': + new_tokens, new_end = self._GetTemplateEnd(tokens, i+1) + AddType(self.ToType(new_tokens)) + # If there is a comma after the template, we need to consume + # that here otherwise it becomes part of the name. + i = new_end + reference = pointer = array = False + elif token.name == ',': + AddType([]) + reference = pointer = array = False + elif token.name == '*': + pointer = True + elif token.name == '&': + reference = True + elif token.name == '[': + pointer = True + elif token.name == ']': + pass + else: + name_tokens.append(token) + i += 1 + + if name_tokens: + # No '<' in the tokens, just a simple name and no template. + AddType([]) + return result + + def DeclarationToParts(self, parts, needs_name_removed): + name = None + default = [] + if needs_name_removed: + # Handle default (initial) values properly. + for i, t in enumerate(parts): + if t.name == '=': + default = parts[i+1:] + name = parts[i-1].name + if name == ']' and parts[i-2].name == '[': + name = parts[i-3].name + i -= 1 + parts = parts[:i-1] + break + else: + if parts[-1].token_type == tokenize.NAME: + name = parts.pop().name + else: + # TODO(nnorwitz): this is a hack that happens for code like + # Register(Foo); where it thinks this is a function call + # but it's actually a declaration. + name = '???' + modifiers = [] + type_name = [] + other_tokens = [] + templated_types = [] + i = 0 + end = len(parts) + while i < end: + p = parts[i] + if keywords.IsKeyword(p.name): + modifiers.append(p.name) + elif p.name == '<': + templated_tokens, new_end = self._GetTemplateEnd(parts, i+1) + templated_types = self.ToType(templated_tokens) + i = new_end - 1 + # Don't add a spurious :: to data members being initialized. + next_index = i + 1 + if next_index < end and parts[next_index].name == '::': + i += 1 + elif p.name in ('[', ']', '='): + # These are handled elsewhere. + other_tokens.append(p) + elif p.name not in ('*', '&', '>'): + # Ensure that names have a space between them. + if (type_name and type_name[-1].token_type == tokenize.NAME and + p.token_type == tokenize.NAME): + type_name.append(tokenize.Token(tokenize.SYNTAX, ' ', 0, 0)) + type_name.append(p) + else: + other_tokens.append(p) + i += 1 + type_name = ''.join([t.name for t in type_name]) + return name, type_name, templated_types, modifiers, default, other_tokens + + def ToParameters(self, tokens): + if not tokens: + return [] + + result = [] + name = type_name = '' + type_modifiers = [] + pointer = reference = array = False + first_token = None + default = [] + + def AddParameter(): + if default: + del default[0] # Remove flag. + end = type_modifiers[-1].end + parts = self.DeclarationToParts(type_modifiers, True) + (name, type_name, templated_types, modifiers, + unused_default, unused_other_tokens) = parts + parameter_type = Type(first_token.start, first_token.end, + type_name, templated_types, modifiers, + reference, pointer, array) + p = Parameter(first_token.start, end, name, + parameter_type, default) + result.append(p) + + template_count = 0 + for s in tokens: + if not first_token: + first_token = s + if s.name == '<': + template_count += 1 + elif s.name == '>': + template_count -= 1 + if template_count > 0: + type_modifiers.append(s) + continue + + if s.name == ',': + AddParameter() + name = type_name = '' + type_modifiers = [] + pointer = reference = array = False + first_token = None + default = [] + elif s.name == '*': + pointer = True + elif s.name == '&': + reference = True + elif s.name == '[': + array = True + elif s.name == ']': + pass # Just don't add to type_modifiers. + elif s.name == '=': + # Got a default value. Add any value (None) as a flag. + default.append(None) + elif default: + default.append(s) + else: + type_modifiers.append(s) + AddParameter() + return result + + def CreateReturnType(self, return_type_seq): + if not return_type_seq: + return None + start = return_type_seq[0].start + end = return_type_seq[-1].end + _, name, templated_types, modifiers, default, other_tokens = \ + self.DeclarationToParts(return_type_seq, False) + names = [n.name for n in other_tokens] + reference = '&' in names + pointer = '*' in names + array = '[' in names + return Type(start, end, name, templated_types, modifiers, + reference, pointer, array) + + def GetTemplateIndices(self, names): + # names is a list of strings. + start = names.index('<') + end = len(names) - 1 + while end > 0: + if names[end] == '>': + break + end -= 1 + return start, end+1 + +class AstBuilder(object): + def __init__(self, token_stream, filename, in_class='', visibility=None, + namespace_stack=[]): + self.tokens = token_stream + self.filename = filename + # TODO(nnorwitz): use a better data structure (deque) for the queue. + # Switching directions of the "queue" improved perf by about 25%. + # Using a deque should be even better since we access from both sides. + self.token_queue = [] + self.namespace_stack = namespace_stack[:] + self.in_class = in_class + if in_class is None: + self.in_class_name_only = None + else: + self.in_class_name_only = in_class.split('::')[-1] + self.visibility = visibility + self.in_function = False + self.current_token = None + # Keep the state whether we are currently handling a typedef or not. + self._handling_typedef = False + + self.converter = TypeConverter(self.namespace_stack) + + def HandleError(self, msg, token): + printable_queue = list(reversed(self.token_queue[-20:])) + sys.stderr.write('Got %s in %s @ %s %s\n' % + (msg, self.filename, token, printable_queue)) + + def Generate(self): + while 1: + token = self._GetNextToken() + if not token: + break + + # Get the next token. + self.current_token = token + + # Dispatch on the next token type. + if token.token_type == _INTERNAL_TOKEN: + if token.name == _NAMESPACE_POP: + self.namespace_stack.pop() + continue + + try: + result = self._GenerateOne(token) + if result is not None: + yield result + except: + self.HandleError('exception', token) + raise + + def _CreateVariable(self, pos_token, name, type_name, type_modifiers, + ref_pointer_name_seq, templated_types, value=None): + reference = '&' in ref_pointer_name_seq + pointer = '*' in ref_pointer_name_seq + array = '[' in ref_pointer_name_seq + var_type = Type(pos_token.start, pos_token.end, type_name, + templated_types, type_modifiers, + reference, pointer, array) + return VariableDeclaration(pos_token.start, pos_token.end, + name, var_type, value, self.namespace_stack) + + def _GenerateOne(self, token): + if token.token_type == tokenize.NAME: + if (keywords.IsKeyword(token.name) and + not keywords.IsBuiltinType(token.name)): + method = getattr(self, 'handle_' + token.name) + return method() + elif token.name == self.in_class_name_only: + # The token name is the same as the class, must be a ctor if + # there is a paren. Otherwise, it's the return type. + # Peek ahead to get the next token to figure out which. + next = self._GetNextToken() + self._AddBackToken(next) + if next.token_type == tokenize.SYNTAX and next.name == '(': + return self._GetMethod([token], FUNCTION_CTOR, None, True) + # Fall through--handle like any other method. + + # Handle data or function declaration/definition. + syntax = tokenize.SYNTAX + temp_tokens, last_token = \ + self._GetVarTokensUpTo(syntax, '(', ';', '{', '[') + temp_tokens.insert(0, token) + if last_token.name == '(': + # If there is an assignment before the paren, + # this is an expression, not a method. + expr = bool([e for e in temp_tokens if e.name == '=']) + if expr: + new_temp = self._GetTokensUpTo(tokenize.SYNTAX, ';') + temp_tokens.append(last_token) + temp_tokens.extend(new_temp) + last_token = tokenize.Token(tokenize.SYNTAX, ';', 0, 0) + + if last_token.name == '[': + # Handle array, this isn't a method, unless it's an operator. + # TODO(nnorwitz): keep the size somewhere. + # unused_size = self._GetTokensUpTo(tokenize.SYNTAX, ']') + temp_tokens.append(last_token) + if temp_tokens[-2].name == 'operator': + temp_tokens.append(self._GetNextToken()) + else: + temp_tokens2, last_token = \ + self._GetVarTokensUpTo(tokenize.SYNTAX, ';') + temp_tokens.extend(temp_tokens2) + + if last_token.name == ';': + # Handle data, this isn't a method. + parts = self.converter.DeclarationToParts(temp_tokens, True) + (name, type_name, templated_types, modifiers, default, + unused_other_tokens) = parts + + t0 = temp_tokens[0] + names = [t.name for t in temp_tokens] + if templated_types: + start, end = self.converter.GetTemplateIndices(names) + names = names[:start] + names[end:] + default = ''.join([t.name for t in default]) + return self._CreateVariable(t0, name, type_name, modifiers, + names, templated_types, default) + if last_token.name == '{': + self._AddBackTokens(temp_tokens[1:]) + self._AddBackToken(last_token) + method_name = temp_tokens[0].name + method = getattr(self, 'handle_' + method_name, None) + if not method: + # Must be declaring a variable. + # TODO(nnorwitz): handle the declaration. + return None + return method() + return self._GetMethod(temp_tokens, 0, None, False) + elif token.token_type == tokenize.SYNTAX: + if token.name == '~' and self.in_class: + # Must be a dtor (probably not in method body). + token = self._GetNextToken() + # self.in_class can contain A::Name, but the dtor will only + # be Name. Make sure to compare against the right value. + if (token.token_type == tokenize.NAME and + token.name == self.in_class_name_only): + return self._GetMethod([token], FUNCTION_DTOR, None, True) + # TODO(nnorwitz): handle a lot more syntax. + elif token.token_type == tokenize.PREPROCESSOR: + # TODO(nnorwitz): handle more preprocessor directives. + # token starts with a #, so remove it and strip whitespace. + name = token.name[1:].lstrip() + if name.startswith('include'): + # Remove "include". + name = name[7:].strip() + assert name + # Handle #include \ "header-on-second-line.h". + if name.startswith('\\'): + name = name[1:].strip() + assert name[0] in '<"', token + assert name[-1] in '>"', token + system = name[0] == '<' + filename = name[1:-1] + return Include(token.start, token.end, filename, system) + if name.startswith('define'): + # Remove "define". + name = name[6:].strip() + assert name + value = '' + for i, c in enumerate(name): + if c.isspace(): + value = name[i:].lstrip() + name = name[:i] + break + return Define(token.start, token.end, name, value) + if name.startswith('if') and name[2:3].isspace(): + condition = name[3:].strip() + if condition.startswith('0') or condition.startswith('(0)'): + self._SkipIf0Blocks() + return None + + def _GetTokensUpTo(self, expected_token_type, expected_token): + return self._GetVarTokensUpTo(expected_token_type, expected_token)[0] + + def _GetVarTokensUpTo(self, expected_token_type, *expected_tokens): + last_token = self._GetNextToken() + tokens = [] + while (last_token.token_type != expected_token_type or + last_token.name not in expected_tokens): + tokens.append(last_token) + last_token = self._GetNextToken() + return tokens, last_token + + # TODO(nnorwitz): remove _IgnoreUpTo() it shouldn't be necesary. + def _IgnoreUpTo(self, token_type, token): + unused_tokens = self._GetTokensUpTo(token_type, token) + + def _SkipIf0Blocks(self): + count = 1 + while 1: + token = self._GetNextToken() + if token.token_type != tokenize.PREPROCESSOR: + continue + + name = token.name[1:].lstrip() + if name.startswith('endif'): + count -= 1 + if count == 0: + break + elif name.startswith('if'): + count += 1 + + def _GetMatchingChar(self, open_paren, close_paren, GetNextToken=None): + if GetNextToken is None: + GetNextToken = self._GetNextToken + # Assumes the current token is open_paren and we will consume + # and return up to the close_paren. + count = 1 + token = GetNextToken() + while 1: + if token.token_type == tokenize.SYNTAX: + if token.name == open_paren: + count += 1 + elif token.name == close_paren: + count -= 1 + if count == 0: + break + yield token + token = GetNextToken() + yield token + + def _GetParameters(self): + return self._GetMatchingChar('(', ')') + + def GetScope(self): + return self._GetMatchingChar('{', '}') + + def _GetNextToken(self): + if self.token_queue: + return self.token_queue.pop() + return next(self.tokens) + + def _AddBackToken(self, token): + if token.whence == tokenize.WHENCE_STREAM: + token.whence = tokenize.WHENCE_QUEUE + self.token_queue.insert(0, token) + else: + assert token.whence == tokenize.WHENCE_QUEUE, token + self.token_queue.append(token) + + def _AddBackTokens(self, tokens): + if tokens: + if tokens[-1].whence == tokenize.WHENCE_STREAM: + for token in tokens: + token.whence = tokenize.WHENCE_QUEUE + self.token_queue[:0] = reversed(tokens) + else: + assert tokens[-1].whence == tokenize.WHENCE_QUEUE, tokens + self.token_queue.extend(reversed(tokens)) + + def GetName(self, seq=None): + """Returns ([tokens], next_token_info).""" + GetNextToken = self._GetNextToken + if seq is not None: + it = iter(seq) + GetNextToken = lambda: next(it) + next_token = GetNextToken() + tokens = [] + last_token_was_name = False + while (next_token.token_type == tokenize.NAME or + (next_token.token_type == tokenize.SYNTAX and + next_token.name in ('::', '<'))): + # Two NAMEs in a row means the identifier should terminate. + # It's probably some sort of variable declaration. + if last_token_was_name and next_token.token_type == tokenize.NAME: + break + last_token_was_name = next_token.token_type == tokenize.NAME + tokens.append(next_token) + # Handle templated names. + if next_token.name == '<': + tokens.extend(self._GetMatchingChar('<', '>', GetNextToken)) + last_token_was_name = True + next_token = GetNextToken() + return tokens, next_token + + def GetMethod(self, modifiers, templated_types): + return_type_and_name = self._GetTokensUpTo(tokenize.SYNTAX, '(') + assert len(return_type_and_name) >= 1 + return self._GetMethod(return_type_and_name, modifiers, templated_types, + False) + + def _GetMethod(self, return_type_and_name, modifiers, templated_types, + get_paren): + template_portion = None + if get_paren: + token = self._GetNextToken() + assert token.token_type == tokenize.SYNTAX, token + if token.name == '<': + # Handle templatized dtors. + template_portion = [token] + template_portion.extend(self._GetMatchingChar('<', '>')) + token = self._GetNextToken() + assert token.token_type == tokenize.SYNTAX, token + assert token.name == '(', token + + name = return_type_and_name.pop() + # Handle templatized ctors. + if name.name == '>': + index = 1 + while return_type_and_name[index].name != '<': + index += 1 + template_portion = return_type_and_name[index:] + [name] + del return_type_and_name[index:] + name = return_type_and_name.pop() + elif name.name == ']': + rt = return_type_and_name + assert rt[-1].name == '[', return_type_and_name + assert rt[-2].name == 'operator', return_type_and_name + name_seq = return_type_and_name[-2:] + del return_type_and_name[-2:] + name = tokenize.Token(tokenize.NAME, 'operator[]', + name_seq[0].start, name.end) + # Get the open paren so _GetParameters() below works. + unused_open_paren = self._GetNextToken() + + # TODO(nnorwitz): store template_portion. + return_type = return_type_and_name + indices = name + if return_type: + indices = return_type[0] + + # Force ctor for templatized ctors. + if name.name == self.in_class and not modifiers: + modifiers |= FUNCTION_CTOR + parameters = list(self._GetParameters()) + del parameters[-1] # Remove trailing ')'. + + # Handling operator() is especially weird. + if name.name == 'operator' and not parameters: + token = self._GetNextToken() + assert token.name == '(', token + parameters = list(self._GetParameters()) + del parameters[-1] # Remove trailing ')'. + + token = self._GetNextToken() + while token.token_type == tokenize.NAME: + modifier_token = token + token = self._GetNextToken() + if modifier_token.name == 'const': + modifiers |= FUNCTION_CONST + elif modifier_token.name == '__attribute__': + # TODO(nnorwitz): handle more __attribute__ details. + modifiers |= FUNCTION_ATTRIBUTE + assert token.name == '(', token + # Consume everything between the (parens). + unused_tokens = list(self._GetMatchingChar('(', ')')) + token = self._GetNextToken() + elif modifier_token.name == 'throw': + modifiers |= FUNCTION_THROW + assert token.name == '(', token + # Consume everything between the (parens). + unused_tokens = list(self._GetMatchingChar('(', ')')) + token = self._GetNextToken() + elif modifier_token.name == modifier_token.name.upper(): + # HACK(nnorwitz): assume that all upper-case names + # are some macro we aren't expanding. + modifiers |= FUNCTION_UNKNOWN_ANNOTATION + else: + self.HandleError('unexpected token', modifier_token) + + assert token.token_type == tokenize.SYNTAX, token + # Handle ctor initializers. + if token.name == ':': + # TODO(nnorwitz): anything else to handle for initializer list? + while token.name != ';' and token.name != '{': + token = self._GetNextToken() + + # Handle pointer to functions that are really data but look + # like method declarations. + if token.name == '(': + if parameters[0].name == '*': + # name contains the return type. + name = parameters.pop() + # parameters contains the name of the data. + modifiers = [p.name for p in parameters] + # Already at the ( to open the parameter list. + function_parameters = list(self._GetMatchingChar('(', ')')) + del function_parameters[-1] # Remove trailing ')'. + # TODO(nnorwitz): store the function_parameters. + token = self._GetNextToken() + assert token.token_type == tokenize.SYNTAX, token + assert token.name == ';', token + return self._CreateVariable(indices, name.name, indices.name, + modifiers, '', None) + # At this point, we got something like: + # return_type (type::*name_)(params); + # This is a data member called name_ that is a function pointer. + # With this code: void (sq_type::*field_)(string&); + # We get: name=void return_type=[] parameters=sq_type ... field_ + # TODO(nnorwitz): is return_type always empty? + # TODO(nnorwitz): this isn't even close to being correct. + # Just put in something so we don't crash and can move on. + real_name = parameters[-1] + modifiers = [p.name for p in self._GetParameters()] + del modifiers[-1] # Remove trailing ')'. + return self._CreateVariable(indices, real_name.name, indices.name, + modifiers, '', None) + + if token.name == '{': + body = list(self.GetScope()) + del body[-1] # Remove trailing '}'. + else: + body = None + if token.name == '=': + token = self._GetNextToken() + assert token.token_type == tokenize.CONSTANT, token + assert token.name == '0', token + modifiers |= FUNCTION_PURE_VIRTUAL + token = self._GetNextToken() + + if token.name == '[': + # TODO(nnorwitz): store tokens and improve parsing. + # template char (&ASH(T (&seq)[N]))[N]; + tokens = list(self._GetMatchingChar('[', ']')) + token = self._GetNextToken() + + assert token.name == ';', (token, return_type_and_name, parameters) + + # Looks like we got a method, not a function. + if len(return_type) > 2 and return_type[-1].name == '::': + return_type, in_class = \ + self._GetReturnTypeAndClassName(return_type) + return Method(indices.start, indices.end, name.name, in_class, + return_type, parameters, modifiers, templated_types, + body, self.namespace_stack) + return Function(indices.start, indices.end, name.name, return_type, + parameters, modifiers, templated_types, body, + self.namespace_stack) + + def _GetReturnTypeAndClassName(self, token_seq): + # Splitting the return type from the class name in a method + # can be tricky. For example, Return::Type::Is::Hard::To::Find(). + # Where is the return type and where is the class name? + # The heuristic used is to pull the last name as the class name. + # This includes all the templated type info. + # TODO(nnorwitz): if there is only One name like in the + # example above, punt and assume the last bit is the class name. + + # Ignore a :: prefix, if exists so we can find the first real name. + i = 0 + if token_seq[0].name == '::': + i = 1 + # Ignore a :: suffix, if exists. + end = len(token_seq) - 1 + if token_seq[end-1].name == '::': + end -= 1 + + # Make a copy of the sequence so we can append a sentinel + # value. This is required for GetName will has to have some + # terminating condition beyond the last name. + seq_copy = token_seq[i:end] + seq_copy.append(tokenize.Token(tokenize.SYNTAX, '', 0, 0)) + names = [] + while i < end: + # Iterate through the sequence parsing out each name. + new_name, next = self.GetName(seq_copy[i:]) + assert new_name, 'Got empty new_name, next=%s' % next + # We got a pointer or ref. Add it to the name. + if next and next.token_type == tokenize.SYNTAX: + new_name.append(next) + names.append(new_name) + i += len(new_name) + + # Now that we have the names, it's time to undo what we did. + + # Remove the sentinel value. + names[-1].pop() + # Flatten the token sequence for the return type. + return_type = [e for seq in names[:-1] for e in seq] + # The class name is the last name. + class_name = names[-1] + return return_type, class_name + + def handle_bool(self): + pass + + def handle_char(self): + pass + + def handle_int(self): + pass + + def handle_long(self): + pass + + def handle_short(self): + pass + + def handle_double(self): + pass + + def handle_float(self): + pass + + def handle_void(self): + pass + + def handle_wchar_t(self): + pass + + def handle_unsigned(self): + pass + + def handle_signed(self): + pass + + def _GetNestedType(self, ctor): + name = None + name_tokens, token = self.GetName() + if name_tokens: + name = ''.join([t.name for t in name_tokens]) + + # Handle forward declarations. + if token.token_type == tokenize.SYNTAX and token.name == ';': + return ctor(token.start, token.end, name, None, + self.namespace_stack) + + if token.token_type == tokenize.NAME and self._handling_typedef: + self._AddBackToken(token) + return ctor(token.start, token.end, name, None, + self.namespace_stack) + + # Must be the type declaration. + fields = list(self._GetMatchingChar('{', '}')) + del fields[-1] # Remove trailing '}'. + if token.token_type == tokenize.SYNTAX and token.name == '{': + next = self._GetNextToken() + new_type = ctor(token.start, token.end, name, fields, + self.namespace_stack) + # A name means this is an anonymous type and the name + # is the variable declaration. + if next.token_type != tokenize.NAME: + return new_type + name = new_type + token = next + + # Must be variable declaration using the type prefixed with keyword. + assert token.token_type == tokenize.NAME, token + return self._CreateVariable(token, token.name, name, [], '', None) + + def handle_struct(self): + # Special case the handling typedef/aliasing of structs here. + # It would be a pain to handle in the class code. + name_tokens, var_token = self.GetName() + if name_tokens: + next_token = self._GetNextToken() + is_syntax = (var_token.token_type == tokenize.SYNTAX and + var_token.name[0] in '*&') + is_variable = (var_token.token_type == tokenize.NAME and + next_token.name == ';') + variable = var_token + if is_syntax and not is_variable: + variable = next_token + temp = self._GetNextToken() + if temp.token_type == tokenize.SYNTAX and temp.name == '(': + # Handle methods declared to return a struct. + t0 = name_tokens[0] + struct = tokenize.Token(tokenize.NAME, 'struct', + t0.start-7, t0.start-2) + type_and_name = [struct] + type_and_name.extend(name_tokens) + type_and_name.extend((var_token, next_token)) + return self._GetMethod(type_and_name, 0, None, False) + assert temp.name == ';', (temp, name_tokens, var_token) + if is_syntax or (is_variable and not self._handling_typedef): + modifiers = ['struct'] + type_name = ''.join([t.name for t in name_tokens]) + position = name_tokens[0] + return self._CreateVariable(position, variable.name, type_name, + modifiers, var_token.name, None) + name_tokens.extend((var_token, next_token)) + self._AddBackTokens(name_tokens) + else: + self._AddBackToken(var_token) + return self._GetClass(Struct, VISIBILITY_PUBLIC, None) + + def handle_union(self): + return self._GetNestedType(Union) + + def handle_enum(self): + return self._GetNestedType(Enum) + + def handle_auto(self): + # TODO(nnorwitz): warn about using auto? Probably not since it + # will be reclaimed and useful for C++0x. + pass + + def handle_register(self): + pass + + def handle_const(self): + pass + + def handle_inline(self): + pass + + def handle_extern(self): + pass + + def handle_static(self): + pass + + def handle_virtual(self): + # What follows must be a method. + token = token2 = self._GetNextToken() + if token.name == 'inline': + # HACK(nnorwitz): handle inline dtors by ignoring 'inline'. + token2 = self._GetNextToken() + if token2.token_type == tokenize.SYNTAX and token2.name == '~': + return self.GetMethod(FUNCTION_VIRTUAL + FUNCTION_DTOR, None) + assert token.token_type == tokenize.NAME or token.name == '::', token + return_type_and_name = self._GetTokensUpTo(tokenize.SYNTAX, '(') + return_type_and_name.insert(0, token) + if token2 is not token: + return_type_and_name.insert(1, token2) + return self._GetMethod(return_type_and_name, FUNCTION_VIRTUAL, + None, False) + + def handle_volatile(self): + pass + + def handle_mutable(self): + pass + + def handle_public(self): + assert self.in_class + self.visibility = VISIBILITY_PUBLIC + + def handle_protected(self): + assert self.in_class + self.visibility = VISIBILITY_PROTECTED + + def handle_private(self): + assert self.in_class + self.visibility = VISIBILITY_PRIVATE + + def handle_friend(self): + tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') + assert tokens + t0 = tokens[0] + return Friend(t0.start, t0.end, tokens, self.namespace_stack) + + def handle_static_cast(self): + pass + + def handle_const_cast(self): + pass + + def handle_dynamic_cast(self): + pass + + def handle_reinterpret_cast(self): + pass + + def handle_new(self): + pass + + def handle_delete(self): + tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') + assert tokens + return Delete(tokens[0].start, tokens[0].end, tokens) + + def handle_typedef(self): + token = self._GetNextToken() + if (token.token_type == tokenize.NAME and + keywords.IsKeyword(token.name)): + # Token must be struct/enum/union/class. + method = getattr(self, 'handle_' + token.name) + self._handling_typedef = True + tokens = [method()] + self._handling_typedef = False + else: + tokens = [token] + + # Get the remainder of the typedef up to the semi-colon. + tokens.extend(self._GetTokensUpTo(tokenize.SYNTAX, ';')) + + # TODO(nnorwitz): clean all this up. + assert tokens + name = tokens.pop() + indices = name + if tokens: + indices = tokens[0] + if not indices: + indices = token + if name.name == ')': + # HACK(nnorwitz): Handle pointers to functions "properly". + if (len(tokens) >= 4 and + tokens[1].name == '(' and tokens[2].name == '*'): + tokens.append(name) + name = tokens[3] + elif name.name == ']': + # HACK(nnorwitz): Handle arrays properly. + if len(tokens) >= 2: + tokens.append(name) + name = tokens[1] + new_type = tokens + if tokens and isinstance(tokens[0], tokenize.Token): + new_type = self.converter.ToType(tokens)[0] + return Typedef(indices.start, indices.end, name.name, + new_type, self.namespace_stack) + + def handle_typeid(self): + pass # Not needed yet. + + def handle_typename(self): + pass # Not needed yet. + + def _GetTemplatedTypes(self): + result = {} + tokens = list(self._GetMatchingChar('<', '>')) + len_tokens = len(tokens) - 1 # Ignore trailing '>'. + i = 0 + while i < len_tokens: + key = tokens[i].name + i += 1 + if keywords.IsKeyword(key) or key == ',': + continue + type_name = default = None + if i < len_tokens: + i += 1 + if tokens[i-1].name == '=': + assert i < len_tokens, '%s %s' % (i, tokens) + default, unused_next_token = self.GetName(tokens[i:]) + i += len(default) + else: + if tokens[i-1].name != ',': + # We got something like: Type variable. + # Re-adjust the key (variable) and type_name (Type). + key = tokens[i-1].name + type_name = tokens[i-2] + + result[key] = (type_name, default) + return result + + def handle_template(self): + token = self._GetNextToken() + assert token.token_type == tokenize.SYNTAX, token + assert token.name == '<', token + templated_types = self._GetTemplatedTypes() + # TODO(nnorwitz): for now, just ignore the template params. + token = self._GetNextToken() + if token.token_type == tokenize.NAME: + if token.name == 'class': + return self._GetClass(Class, VISIBILITY_PRIVATE, templated_types) + elif token.name == 'struct': + return self._GetClass(Struct, VISIBILITY_PUBLIC, templated_types) + elif token.name == 'friend': + return self.handle_friend() + self._AddBackToken(token) + tokens, last = self._GetVarTokensUpTo(tokenize.SYNTAX, '(', ';') + tokens.append(last) + self._AddBackTokens(tokens) + if last.name == '(': + return self.GetMethod(FUNCTION_NONE, templated_types) + # Must be a variable definition. + return None + + def handle_true(self): + pass # Nothing to do. + + def handle_false(self): + pass # Nothing to do. + + def handle_asm(self): + pass # Not needed yet. + + def handle_class(self): + return self._GetClass(Class, VISIBILITY_PRIVATE, None) + + def _GetBases(self): + # Get base classes. + bases = [] + while 1: + token = self._GetNextToken() + assert token.token_type == tokenize.NAME, token + # TODO(nnorwitz): store kind of inheritance...maybe. + if token.name not in ('public', 'protected', 'private'): + # If inheritance type is not specified, it is private. + # Just put the token back so we can form a name. + # TODO(nnorwitz): it would be good to warn about this. + self._AddBackToken(token) + else: + # Check for virtual inheritance. + token = self._GetNextToken() + if token.name != 'virtual': + self._AddBackToken(token) + else: + # TODO(nnorwitz): store that we got virtual for this base. + pass + base, next_token = self.GetName() + bases_ast = self.converter.ToType(base) + assert len(bases_ast) == 1, bases_ast + bases.append(bases_ast[0]) + assert next_token.token_type == tokenize.SYNTAX, next_token + if next_token.name == '{': + token = next_token + break + # Support multiple inheritance. + assert next_token.name == ',', next_token + return bases, token + + def _GetClass(self, class_type, visibility, templated_types): + class_name = None + class_token = self._GetNextToken() + if class_token.token_type != tokenize.NAME: + assert class_token.token_type == tokenize.SYNTAX, class_token + token = class_token + else: + self._AddBackToken(class_token) + name_tokens, token = self.GetName() + class_name = ''.join([t.name for t in name_tokens]) + bases = None + if token.token_type == tokenize.SYNTAX: + if token.name == ';': + # Forward declaration. + return class_type(class_token.start, class_token.end, + class_name, None, templated_types, None, + self.namespace_stack) + if token.name in '*&': + # Inline forward declaration. Could be method or data. + name_token = self._GetNextToken() + next_token = self._GetNextToken() + if next_token.name == ';': + # Handle data + modifiers = ['class'] + return self._CreateVariable(class_token, name_token.name, + class_name, + modifiers, token.name, None) + else: + # Assume this is a method. + tokens = (class_token, token, name_token, next_token) + self._AddBackTokens(tokens) + return self.GetMethod(FUNCTION_NONE, None) + if token.name == ':': + bases, token = self._GetBases() + + body = None + if token.token_type == tokenize.SYNTAX and token.name == '{': + assert token.token_type == tokenize.SYNTAX, token + assert token.name == '{', token + + ast = AstBuilder(self.GetScope(), self.filename, class_name, + visibility, self.namespace_stack) + body = list(ast.Generate()) + + if not self._handling_typedef: + token = self._GetNextToken() + if token.token_type != tokenize.NAME: + assert token.token_type == tokenize.SYNTAX, token + assert token.name == ';', token + else: + new_class = class_type(class_token.start, class_token.end, + class_name, bases, None, + body, self.namespace_stack) + + modifiers = [] + return self._CreateVariable(class_token, + token.name, new_class, + modifiers, token.name, None) + else: + if not self._handling_typedef: + self.HandleError('non-typedef token', token) + self._AddBackToken(token) + + return class_type(class_token.start, class_token.end, class_name, + bases, None, body, self.namespace_stack) + + def handle_namespace(self): + token = self._GetNextToken() + # Support anonymous namespaces. + name = None + if token.token_type == tokenize.NAME: + name = token.name + token = self._GetNextToken() + self.namespace_stack.append(name) + assert token.token_type == tokenize.SYNTAX, token + if token.name == '=': + # TODO(nnorwitz): handle aliasing namespaces. + name, next_token = self.GetName() + assert next_token.name == ';', next_token + else: + assert token.name == '{', token + tokens = list(self.GetScope()) + del tokens[-1] # Remove trailing '}'. + # Handle namespace with nothing in it. + self._AddBackTokens(tokens) + token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP, None, None) + self._AddBackToken(token) + return None + + def handle_using(self): + tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') + assert tokens + return Using(tokens[0].start, tokens[0].end, tokens) + + def handle_explicit(self): + assert self.in_class + # Nothing much to do. + # TODO(nnorwitz): maybe verify the method name == class name. + # This must be a ctor. + return self.GetMethod(FUNCTION_CTOR, None) + + def handle_this(self): + pass # Nothing to do. + + def handle_operator(self): + # Pull off the next token(s?) and make that part of the method name. + pass + + def handle_sizeof(self): + pass + + def handle_case(self): + pass + + def handle_switch(self): + pass + + def handle_default(self): + token = self._GetNextToken() + assert token.token_type == tokenize.SYNTAX + assert token.name == ':' + + def handle_if(self): + pass + + def handle_else(self): + pass + + def handle_return(self): + tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') + if not tokens: + return Return(self.current_token.start, self.current_token.end, None) + return Return(tokens[0].start, tokens[0].end, tokens) + + def handle_goto(self): + tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') + assert len(tokens) == 1, str(tokens) + return Goto(tokens[0].start, tokens[0].end, tokens[0].name) + + def handle_try(self): + pass # Not needed yet. + + def handle_catch(self): + pass # Not needed yet. + + def handle_throw(self): + pass # Not needed yet. + + def handle_while(self): + pass + + def handle_do(self): + pass + + def handle_for(self): + pass + + def handle_break(self): + self._IgnoreUpTo(tokenize.SYNTAX, ';') + + def handle_continue(self): + self._IgnoreUpTo(tokenize.SYNTAX, ';') + + +def BuilderFromSource(source, filename): + """Utility method that returns an AstBuilder from source code. + + Args: + source: 'C++ source code' + filename: 'file1' + + Returns: + AstBuilder + """ + return AstBuilder(tokenize.GetTokens(source), filename) + + +def PrintIndentifiers(filename, should_print): + """Prints all identifiers for a C++ source file. + + Args: + filename: 'file1' + should_print: predicate with signature: bool Function(token) + """ + source = utils.ReadFile(filename, False) + if source is None: + sys.stderr.write('Unable to find: %s\n' % filename) + return + + #print('Processing %s' % actual_filename) + builder = BuilderFromSource(source, filename) + try: + for node in builder.Generate(): + if should_print(node): + print(node.name) + except KeyboardInterrupt: + return + except: + pass + + +def PrintAllIndentifiers(filenames, should_print): + """Prints all identifiers for each C++ source file in filenames. + + Args: + filenames: ['file1', 'file2', ...] + should_print: predicate with signature: bool Function(token) + """ + for path in filenames: + PrintIndentifiers(path, should_print) + + +def main(argv): + for filename in argv[1:]: + source = utils.ReadFile(filename) + if source is None: + continue + + print('Processing %s' % filename) + builder = BuilderFromSource(source, filename) + try: + entire_ast = filter(None, builder.Generate()) + except KeyboardInterrupt: + return + except: + # Already printed a warning, print the traceback and continue. + traceback.print_exc() + else: + if utils.DEBUG: + for ast in entire_ast: + print(ast) + + +if __name__ == '__main__': + main(sys.argv) diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py new file mode 100755 index 00000000..f2b3521f --- /dev/null +++ b/scripts/generator/cpp/gmock_class.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# +# Copyright 2008 Google Inc. +# +# 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. + +"""Generate a Google Mock class from a production class. + +This program will read in a C++ source file and output the Google Mock class +for the specified class. + +Usage: + gmock_class.py header-file.h ClassName + +Output is sent to stdout. +""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + + +import os +import re +import sys + +from cpp import ast +from cpp import utils + +# How many spaces to indent. Can me set with INDENT environment variable. +_INDENT = 2 + + +def _GenerateMethods(output_lines, source, class_node): + function_type = ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL + ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR + + for node in class_node.body: + # We only care about virtual functions. + if (isinstance(node, ast.Function) and + node.modifiers & function_type and + not node.modifiers & ctor_or_dtor): + # Pick out all the elements we need from the original function. + const = '' + if node.modifiers & ast.FUNCTION_CONST: + const = 'CONST_' + return_type = 'void' + if node.return_type: + return_type = node.return_type.name + if node.return_type.pointer: + return_type += '*' + if node.return_type.reference: + return_type += '&' + prefix = 'MOCK_%sMETHOD%d' % (const, len(node.parameters)) + args = '' + if node.parameters: + # Get the full text of the parameters from the start + # of the first parameter to the end of the last parameter. + start = node.parameters[0].start + end = node.parameters[-1].end + args = re.sub(' +', ' ', source[start:end].replace('\n', '')) + + # Create the prototype. + indent = ' ' * _INDENT + line = ('%s%s(%s,\n%s%s(%s));' % + (indent, prefix, node.name, indent*3, return_type, args)) + output_lines.append(line) + + +def _GenerateMock(filename, source, ast_list, class_name): + lines = [] + for node in ast_list: + if isinstance(node, ast.Class) and node.body and node.name == class_name: + class_node = node + # Add namespace before the class. + if class_node.namespace: + lines.extend(['namespace %s {' % n for n in class_node.namespace]) # } + lines.append('') + + # Add the class prolog. + lines.append('class Mock%s : public %s {' % (class_name, class_name)) # } + lines.append('%spublic:' % (' ' * (_INDENT // 2))) + + # Add all the methods. + _GenerateMethods(lines, source, class_node) + + # Close the class. + if lines: + # If there are no virtual methods, no need for a public label. + if len(lines) == 2: + del lines[-1] + + # Only close the class if there really is a class. + lines.append('};') + lines.append('') # Add an extra newline. + + # Close the namespace. + if class_node.namespace: + for i in range(len(class_node.namespace)-1, -1, -1): + lines.append('} // namespace %s' % class_node.namespace[i]) + lines.append('') # Add an extra newline. + + if lines: + sys.stdout.write('\n'.join(lines)) + else: + sys.stderr.write('Class %s not found\n' % class_name) + + +def main(argv=sys.argv): + if len(argv) != 3: + sys.stdout.write(__doc__) + return 1 + + global _INDENT + try: + _INDENT = int(os.environ['INDENT']) + except KeyError: + pass + except: + sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT')) + + filename, class_name = argv[1:] + source = utils.ReadFile(filename) + if source is None: + return 1 + + builder = ast.BuilderFromSource(source, filename) + try: + entire_ast = filter(None, builder.Generate()) + except KeyboardInterrupt: + return + except: + # An error message was already printed since we couldn't parse. + pass + else: + _GenerateMock(filename, source, entire_ast, class_name) + + +if __name__ == '__main__': + main(sys.argv) diff --git a/scripts/generator/cpp/keywords.py b/scripts/generator/cpp/keywords.py new file mode 100755 index 00000000..73f0202c --- /dev/null +++ b/scripts/generator/cpp/keywords.py @@ -0,0 +1,58 @@ +# +# Copyright 2007 Neal Norwitz +# Portions Copyright 2007 Google Inc. +# +# 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. + +"""C++ keywords and helper utilities for determining keywords.""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + + +try: + # Python 3.x + import builtins +except ImportError: + # Python 2.x + import __builtin__ as builtins + + +if not hasattr(builtins, 'set'): + # Nominal support for Python 2.3. + from sets import Set as set + + +TYPES = set('bool char int long short double float void wchar_t unsigned signed'.split()) +TYPE_MODIFIERS = set('auto register const inline extern static virtual volatile mutable'.split()) +ACCESS = set('public protected private friend'.split()) + +CASTS = set('static_cast const_cast dynamic_cast reinterpret_cast'.split()) + +OTHERS = set('true false asm class namespace using explicit this operator sizeof'.split()) +OTHER_TYPES = set('new delete typedef struct union enum typeid typename template'.split()) + +CONTROL = set('case switch default if else return goto'.split()) +EXCEPTION = set('try catch throw'.split()) +LOOP = set('while do for break continue'.split()) + +ALL = TYPES | TYPE_MODIFIERS | ACCESS | CASTS | OTHERS | OTHER_TYPES | CONTROL | EXCEPTION | LOOP + + +def IsKeyword(token): + return token in ALL + +def IsBuiltinType(token): + if token in ('virtual', 'inline'): + # These only apply to methods, they can't be types by themselves. + return False + return token in TYPES or token in TYPE_MODIFIERS diff --git a/scripts/generator/cpp/tokenize.py b/scripts/generator/cpp/tokenize.py new file mode 100755 index 00000000..28c33452 --- /dev/null +++ b/scripts/generator/cpp/tokenize.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python +# +# Copyright 2007 Neal Norwitz +# Portions Copyright 2007 Google Inc. +# +# 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. + +"""Tokenize C++ source code.""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + + +try: + # Python 3.x + import builtins +except ImportError: + # Python 2.x + import __builtin__ as builtins + + +import sys + +from cpp import utils + + +if not hasattr(builtins, 'set'): + # Nominal support for Python 2.3. + from sets import Set as set + + +# Add $ as a valid identifier char since so much code uses it. +_letters = 'abcdefghijklmnopqrstuvwxyz' +VALID_IDENTIFIER_CHARS = set(_letters + _letters.upper() + '_0123456789$') +HEX_DIGITS = set('0123456789abcdefABCDEF') +INT_OR_FLOAT_DIGITS = set('01234567890eE-+') + + +# C++0x string preffixes. +_STR_PREFIXES = set(('R', 'u8', 'u8R', 'u', 'uR', 'U', 'UR', 'L', 'LR')) + + +# Token types. +UNKNOWN = 'UNKNOWN' +SYNTAX = 'SYNTAX' +CONSTANT = 'CONSTANT' +NAME = 'NAME' +PREPROCESSOR = 'PREPROCESSOR' + +# Where the token originated from. This can be used for backtracking. +# It is always set to WHENCE_STREAM in this code. +WHENCE_STREAM, WHENCE_QUEUE = range(2) + + +class Token(object): + """Data container to represent a C++ token. + + Tokens can be identifiers, syntax char(s), constants, or + pre-processor directives. + + start contains the index of the first char of the token in the source + end contains the index of the last char of the token in the source + """ + + def __init__(self, token_type, name, start, end): + self.token_type = token_type + self.name = name + self.start = start + self.end = end + self.whence = WHENCE_STREAM + + def __str__(self): + if not utils.DEBUG: + return 'Token(%r)' % self.name + return 'Token(%r, %s, %s)' % (self.name, self.start, self.end) + + __repr__ = __str__ + + +def _GetString(source, start, i): + i = source.find('"', i+1) + while source[i-1] == '\\': + # Count the trailing backslashes. + backslash_count = 1 + j = i - 2 + while source[j] == '\\': + backslash_count += 1 + j -= 1 + # When trailing backslashes are even, they escape each other. + if (backslash_count % 2) == 0: + break + i = source.find('"', i+1) + return i + 1 + + +def _GetChar(source, start, i): + # NOTE(nnorwitz): may not be quite correct, should be good enough. + i = source.find("'", i+1) + while source[i-1] == '\\': + # Need to special case '\\'. + if (i - 2) > start and source[i-2] == '\\': + break + i = source.find("'", i+1) + # Try to handle unterminated single quotes (in a #if 0 block). + if i < 0: + i = start + return i + 1 + + +def GetTokens(source): + """Returns a sequence of Tokens. + + Args: + source: string of C++ source code. + + Yields: + Token that represents the next token in the source. + """ + # Cache various valid character sets for speed. + valid_identifier_chars = VALID_IDENTIFIER_CHARS + hex_digits = HEX_DIGITS + int_or_float_digits = INT_OR_FLOAT_DIGITS + int_or_float_digits2 = int_or_float_digits | set('.') + + # Only ignore errors while in a #if 0 block. + ignore_errors = False + count_ifs = 0 + + i = 0 + end = len(source) + while i < end: + # Skip whitespace. + while i < end and source[i].isspace(): + i += 1 + if i >= end: + return + + token_type = UNKNOWN + start = i + c = source[i] + if c.isalpha() or c == '_': # Find a string token. + token_type = NAME + while source[i] in valid_identifier_chars: + i += 1 + # String and character constants can look like a name if + # they are something like L"". + if (source[i] == "'" and (i - start) == 1 and + source[start:i] in 'uUL'): + # u, U, and L are valid C++0x character preffixes. + token_type = CONSTANT + i = _GetChar(source, start, i) + elif source[i] == "'" and source[start:i] in _STR_PREFIXES: + token_type = CONSTANT + i = _GetString(source, start, i) + elif c == '/' and source[i+1] == '/': # Find // comments. + i = source.find('\n', i) + if i == -1: # Handle EOF. + i = end + continue + elif c == '/' and source[i+1] == '*': # Find /* comments. */ + i = source.find('*/', i) + 2 + continue + elif c in ':+-<>&|*=': # : or :: (plus other chars). + token_type = SYNTAX + i += 1 + new_ch = source[i] + if new_ch == c: + i += 1 + elif c == '-' and new_ch == '>': + i += 1 + elif new_ch == '=': + i += 1 + elif c in '()[]{}~!?^%;/.,': # Handle single char tokens. + token_type = SYNTAX + i += 1 + if c == '.' and source[i].isdigit(): + token_type = CONSTANT + i += 1 + while source[i] in int_or_float_digits: + i += 1 + # Handle float suffixes. + for suffix in ('l', 'f'): + if suffix == source[i:i+1].lower(): + i += 1 + break + elif c.isdigit(): # Find integer. + token_type = CONSTANT + if c == '0' and source[i+1] in 'xX': + # Handle hex digits. + i += 2 + while source[i] in hex_digits: + i += 1 + else: + while source[i] in int_or_float_digits2: + i += 1 + # Handle integer (and float) suffixes. + for suffix in ('ull', 'll', 'ul', 'l', 'f', 'u'): + size = len(suffix) + if suffix == source[i:i+size].lower(): + i += size + break + elif c == '"': # Find string. + token_type = CONSTANT + i = _GetString(source, start, i) + elif c == "'": # Find char. + token_type = CONSTANT + i = _GetChar(source, start, i) + elif c == '#': # Find pre-processor command. + token_type = PREPROCESSOR + got_if = source[i:i+3] == '#if' and source[i+3:i+4].isspace() + if got_if: + count_ifs += 1 + elif source[i:i+6] == '#endif': + count_ifs -= 1 + if count_ifs == 0: + ignore_errors = False + + # TODO(nnorwitz): handle preprocessor statements (\ continuations). + while 1: + i1 = source.find('\n', i) + i2 = source.find('//', i) + i3 = source.find('/*', i) + i4 = source.find('"', i) + # NOTE(nnorwitz): doesn't handle comments in #define macros. + # Get the first important symbol (newline, comment, EOF/end). + i = min([x for x in (i1, i2, i3, i4, end) if x != -1]) + + # Handle #include "dir//foo.h" properly. + if source[i] == '"': + i = source.find('"', i+1) + 1 + assert i > 0 + continue + # Keep going if end of the line and the line ends with \. + if not (i == i1 and source[i-1] == '\\'): + if got_if: + condition = source[start+4:i].lstrip() + if (condition.startswith('0') or + condition.startswith('(0)')): + ignore_errors = True + break + i += 1 + elif c == '\\': # Handle \ in code. + # This is different from the pre-processor \ handling. + i += 1 + continue + elif ignore_errors: + # The tokenizer seems to be in pretty good shape. This + # raise is conditionally disabled so that bogus code + # in an #if 0 block can be handled. Since we will ignore + # it anyways, this is probably fine. So disable the + # exception and return the bogus char. + i += 1 + else: + sys.stderr.write('Got invalid token in %s @ %d token:%s: %r\n' % + ('?', i, c, source[i-10:i+10])) + raise RuntimeError('unexpected token') + + if i <= 0: + print('Invalid index, exiting now.') + return + yield Token(token_type, source[start:i], start, i) + + +if __name__ == '__main__': + def main(argv): + """Driver mostly for testing purposes.""" + for filename in argv[1:]: + source = utils.ReadFile(filename) + if source is None: + continue + + for token in GetTokens(source): + print('%-12s: %s' % (token.token_type, token.name)) + # print('\r%6.2f%%' % (100.0 * index / token.end),) + sys.stdout.write('\n') + + + main(sys.argv) diff --git a/scripts/generator/cpp/utils.py b/scripts/generator/cpp/utils.py new file mode 100755 index 00000000..eab36eec --- /dev/null +++ b/scripts/generator/cpp/utils.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# +# Copyright 2007 Neal Norwitz +# Portions Copyright 2007 Google Inc. +# +# 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. + +"""Generic utilities for C++ parsing.""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + + +import sys + + +# Set to True to see the start/end token indices. +DEBUG = True + + +def ReadFile(filename, print_error=True): + """Returns the contents of a file.""" + try: + fp = open(filename) + try: + return fp.read() + finally: + fp.close() + except IOError: + if print_error: + print('Error reading %s: %s' % (filename, sys.exc_info()[1])) + return None diff --git a/scripts/generator/gmock_gen.py b/scripts/generator/gmock_gen.py new file mode 100755 index 00000000..5a3f6583 --- /dev/null +++ b/scripts/generator/gmock_gen.py @@ -0,0 +1,31 @@ +#!/usr/bin/python2.4 +# +# Copyright 2008 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. + +"""Driver for starting up Google Mock class generator.""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + +import os +import sys + +if __name__ == '__main__': + # Add the directory of this script to the path so we can import gmock_class. + sys.path.append(os.path.dirname(__file__)) + + from cpp import gmock_class + # Fix the docstring in case they require the usage. + gmock_class.__doc__ = gmock_class.__doc__.replace('gmock_class.py', __file__) + gmock_class.main() diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py new file mode 100755 index 00000000..ce8ec498 --- /dev/null +++ b/scripts/gmock_doctor.py @@ -0,0 +1,376 @@ +#!/usr/bin/python2.4 +# +# 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. + +"""Converts gcc errors in code using Google Mock to plain English.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import re +import sys + +_VERSION = '0.1.0.80421' + +_COMMON_GMOCK_SYMBOLS = [ + # Matchers + '_', + 'A', + 'AddressSatisfies', + 'AllOf', + 'An', + 'AnyOf', + 'ContainsRegex', + 'DoubleEq', + 'EndsWith', + 'Eq', + 'Field', + 'FloatEq', + 'Ge', + 'Gt', + 'HasSubstr', + 'Le', + 'Lt', + 'MatcherCast', + 'MatchesRegex', + 'Ne', + 'Not', + 'NotNull', + 'Pointee', + 'Property', + 'Ref', + 'StartsWith', + 'StrCaseEq', + 'StrCaseNe', + 'StrEq', + 'StrNe', + 'Truly', + 'TypedEq', + + # Actions + 'ByRef', + 'DoAll', + 'DoDefault', + 'IgnoreResult', + 'Invoke', + 'InvokeArgument', + 'InvokeWithoutArgs', + 'Return', + 'ReturnNull', + 'ReturnRef', + 'SetArgumentPointee', + 'SetArrayArgument', + 'WithArgs', + + # Cardinalities + 'AnyNumber', + 'AtLeast', + 'AtMost', + 'Between', + 'Exactly', + + # Sequences + 'InSequence', + 'Sequence', + + # Misc + 'DefaultValue', + 'Mock', + ] + + +def _FindAllMatches(regex, s): + """Generates all matches of regex in string s.""" + + r = re.compile(regex) + return r.finditer(s) + + +def _GenericDiagnoser(short_name, long_name, regex, diagnosis, msg): + """Diagnoses the given disease by pattern matching. + + Args: + short_name: Short name of the disease. + long_name: Long name of the disease. + regex: Regex for matching the symptoms. + diagnosis: Pattern for formatting the diagnosis. + msg: Gcc's error messages. + Yields: + Tuples of the form + (short name of disease, long name of disease, diagnosis). + """ + + for m in _FindAllMatches(regex, msg): + yield (short_name, long_name, diagnosis % m.groupdict()) + + +def _NeedToReturnReferenceDiagnoser(msg): + """Diagnoses the NRR disease, given the error messages by gcc.""" + + regex = (r'In member function \'testing::internal::ReturnAction.*\n' + r'(?P.*):(?P\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: creating array with negative size') + diagnosis = """%(file)s:%(line)s: +You are using an Return() action in a function that returns a reference. +Please use ReturnRef() instead.""" + return _GenericDiagnoser('NRR', 'Need to Return Reference', + regex, diagnosis, msg) + + +def _NeedToReturnSomethingDiagnoser(msg): + """Diagnoses the NRS disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: void value not ignored') + diagnosis = """%(file)s:%(line)s: +You are using an action that returns void, but it needs to return +*something*. Please tell it *what* to return.""" + return _GenericDiagnoser('NRS', 'Need to Return Something', + regex, diagnosis, msg) + + +def _NeedToReturnNothingDiagnoser(msg): + """Diagnoses the NRN disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: return-statement with a value, ' + r'in function returning \'void\'') + diagnosis = """%(file)s:%(line)s: +You are using an action that returns *something*, but it needs to return +void. Please use a void-returning action instead. + +All actions but the last in DoAll(...) must return void. Perhaps you need +to re-arrange the order of actions in a DoAll(), if you are using one?""" + return _GenericDiagnoser('NRN', 'Need to Return Nothing', + regex, diagnosis, msg) + + +def _IncompleteByReferenceArgumentDiagnoser(msg): + """Diagnoses the IBRA disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + r'.*gmock-printers\.h.*error: invalid application of ' + r'\'sizeof\' to incomplete type \'(?P.*)\'') + diagnosis = """%(file)s:%(line)s: +In order to mock this function, Google Mock needs to see the definition +of type "%(type)s" - declaration alone is not enough. Either #include +the header that defines it, or change the argument to be passed +by pointer.""" + return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type', + regex, diagnosis, msg) + + +def _OverloadedFunctionMatcherDiagnoser(msg): + """Diagnoses the OFM disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+): error: no matching function for ' + r'call to \'Truly\(\)') + diagnosis = """%(file)s:%(line)s: +The argument you gave to Truly() is an overloaded function. Please tell +gcc which overloaded version you want to use. + +For example, if you want to use the version whose signature is + bool Foo(int n); +you should write + Truly(static_cast(Foo))""" + return _GenericDiagnoser('OFM', 'Overloaded Function Matcher', + regex, diagnosis, msg) + + +def _OverloadedFunctionActionDiagnoser(msg): + """Diagnoses the OFA disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+): error: ' + r'no matching function for call to \'Invoke\(' + r'') + diagnosis = """%(file)s:%(line)s: +You are passing an overloaded function to Invoke(). Please tell gcc +which overloaded version you want to use. + +For example, if you want to use the version whose signature is + bool MyFunction(int n, double x); +you should write something like + Invoke(static_cast(MyFunction))""" + return _GenericDiagnoser('OFA', 'Overloaded Function Action', + regex, diagnosis, msg) + + +def _OverloadedMethodActionDiagnoser1(msg): + """Diagnoses the OMA disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+): error: ' + r'.*no matching function for call to \'Invoke\(.*, ' + r'unresolved overloaded function type>') + diagnosis = """%(file)s:%(line)s: +The second argument you gave to Invoke() is an overloaded method. Please +tell gcc which overloaded version you want to use. + +For example, if you want to use the version whose signature is + class Foo { + ... + bool Bar(int n, double x); + }; +you should write something like + Invoke(foo, static_cast(&Foo::Bar))""" + return _GenericDiagnoser('OMA', 'Overloaded Method Action', + regex, diagnosis, msg) + + +def _MockObjectPointerDiagnoser(msg): + """Diagnoses the MOP disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+): error: request for member ' + r'\'gmock_(?P.+)\' in \'(?P.+)\', ' + r'which is of non-class type \'(.*::)*(?P.+)\*\'') + diagnosis = """%(file)s:%(line)s: +The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*, +not a *pointer* to it. Please write '*(%(mock_object)s)' instead of +'%(mock_object)s' as your first argument. + +For example, given the mock class: + + class %(class_name)s : public ... { + ... + MOCK_METHOD0(%(method)s, ...); + }; + +and the following mock instance: + + %(class_name)s* mock_ptr = ... + +you should use the EXPECT_CALL like this: + + EXPECT_CALL(*mock_ptr, %(method)s(...));""" + return _GenericDiagnoser('MOP', 'Mock Object Pointer', + regex, diagnosis, msg) + + +def _OverloadedMethodActionDiagnoser2(msg): + """Diagnoses the OMA disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+): error: no matching function for ' + r'call to \'Invoke\(.+, \)') + diagnosis = """%(file)s:%(line)s: +The second argument you gave to Invoke() is an overloaded method. Please +tell gcc which overloaded version you want to use. + +For example, if you want to use the version whose signature is + class Foo { + ... + bool Bar(int n, double x); + }; +you should write something like + Invoke(foo, static_cast(&Foo::Bar))""" + return _GenericDiagnoser('OMA', 'Overloaded Method Action', + regex, diagnosis, msg) + + +def _NeedToUseSymbolDiagnoser(msg): + """Diagnoses the NUS disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+): error: \'(?P.+)\' ' + r'(was not declared in this scope|has not been declared)') + diagnosis = """%(file)s:%(line)s: +'%(symbol)s' is defined by Google Mock in the testing namespace. +Did you forget to write + using testing::%(symbol)s; +?""" + for m in _FindAllMatches(regex, msg): + symbol = m.groupdict()['symbol'] + if symbol in _COMMON_GMOCK_SYMBOLS: + yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) + + +_DIAGNOSERS = [ + _IncompleteByReferenceArgumentDiagnoser, + _MockObjectPointerDiagnoser, + _NeedToReturnNothingDiagnoser, + _NeedToReturnReferenceDiagnoser, + _NeedToReturnSomethingDiagnoser, + _NeedToUseSymbolDiagnoser, + _OverloadedFunctionActionDiagnoser, + _OverloadedFunctionMatcherDiagnoser, + _OverloadedMethodActionDiagnoser1, + _OverloadedMethodActionDiagnoser2, + ] + + +def Diagnose(msg): + """Generates all possible diagnoses given the gcc error message.""" + + for diagnoser in _DIAGNOSERS: + for diagnosis in diagnoser(msg): + yield '[%s - %s]\n%s' % diagnosis + + +def main(): + print ('Google Mock Doctor v%s - ' + 'diagnoses problems in code using Google Mock.' % _VERSION) + + if sys.stdin.isatty(): + print ('Please copy and paste the compiler errors here. Press c-D when ' + 'you are done:') + else: + print 'Waiting for compiler errors on stdin . . .' + + msg = sys.stdin.read().strip() + diagnoses = list(Diagnose(msg)) + count = len(diagnoses) + if not count: + print '\nGcc complained:' + print '8<------------------------------------------------------------' + print msg + print '------------------------------------------------------------>8' + print """ +Uh-oh, I'm not smart enough to figure out what the problem is. :-( +However... +If you send your source code and gcc's error messages to +googlemock@googlegroups.com, you can be helped and I can get smarter -- +win-win for us!""" + else: + print '------------------------------------------------------------' + print 'Your code appears to have the following', + if count > 1: + print '%s diseases:' % (count,) + else: + print 'disease:' + i = 0 + for d in diagnoses: + i += 1 + if count > 1: + print '\n#%s:' % (i,) + print d + print """ +How did I do? If you think I'm wrong or unhelpful, please send your +source code and gcc's error messages to googlemock@googlegroups.com. Then +you can be helped and I can get smarter -- I promise I won't be upset!""" + + +if __name__ == '__main__': + main() diff --git a/src/gmock-all.cc b/src/gmock-all.cc new file mode 100644 index 00000000..a14c397d --- /dev/null +++ b/src/gmock-all.cc @@ -0,0 +1,43 @@ +// 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) +// +// Google C++ Mocking Framework (Google Mock) +// +// This file #includes all Google Mock implementation .cc files. The +// purpose is to allow a user to build Google Mock by compiling this +// file alone. + +#include "src/gmock-cardinalities.cc" +#include "src/gmock-internal-utils.cc" +#include "src/gmock-matchers.cc" +#include "src/gmock-printers.cc" +#include "src/gmock-spec-builders.cc" +#include "src/gmock.cc" diff --git a/src/gmock-cardinalities.cc b/src/gmock-cardinalities.cc new file mode 100644 index 00000000..07eed469 --- /dev/null +++ b/src/gmock-cardinalities.cc @@ -0,0 +1,155 @@ +// 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 cardinalities. + +#include + +#include +#include // NOLINT +#include +#include +#include +#include + +namespace testing { + +namespace { + +// Implements the Between(m, n) cardinality. +class BetweenCardinalityImpl : public CardinalityInterface { + public: + BetweenCardinalityImpl(int min, int max) + : min_(min >= 0 ? min : 0), + max_(max >= min_ ? max : min_) { + std::stringstream ss; + if (min < 0) { + ss << "The invocation lower bound must be >= 0, " + << "but is actually " << min << "."; + internal::Expect(false, __FILE__, __LINE__, ss.str()); + } else if (max < 0) { + ss << "The invocation upper bound must be >= 0, " + << "but is actually " << max << "."; + internal::Expect(false, __FILE__, __LINE__, ss.str()); + } else if (min > max) { + ss << "The invocation upper bound (" << max + << ") must be >= the invocation lower bound (" << min + << ")."; + internal::Expect(false, __FILE__, __LINE__, ss.str()); + } + } + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + virtual int ConservativeLowerBound() const { return min_; } + virtual int ConservativeUpperBound() const { return max_; } + + virtual bool IsSatisfiedByCallCount(int call_count) const { + return min_ <= call_count && call_count <= max_ ; + } + + virtual bool IsSaturatedByCallCount(int call_count) const { + return call_count >= max_; + } + + virtual void DescribeTo(::std::ostream* os) const; + private: + const int min_; + const int max_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(BetweenCardinalityImpl); +}; + +// Formats "n times" in a human-friendly way. +inline internal::string FormatTimes(int n) { + if (n == 1) { + return "once"; + } else if (n == 2) { + return "twice"; + } else { + std::stringstream ss; + ss << n << " times"; + return ss.str(); + } +} + +// Describes the Between(m, n) cardinality in human-friendly text. +void BetweenCardinalityImpl::DescribeTo(::std::ostream* os) const { + if (min_ == 0) { + if (max_ == 0) { + *os << "never called"; + } else if (max_ == INT_MAX) { + *os << "called any number of times"; + } else { + *os << "called at most " << FormatTimes(max_); + } + } else if (min_ == max_) { + *os << "called " << FormatTimes(min_); + } else if (max_ == INT_MAX) { + *os << "called at least " << FormatTimes(min_); + } else { + // 0 < min_ < max_ < INT_MAX + *os << "called between " << min_ << " and " << max_ << " times"; + } +} + +} // Unnamed namespace + +// Describes the given call count to an ostream. +void Cardinality::DescribeActualCallCountTo(int actual_call_count, + ::std::ostream* os) { + if (actual_call_count > 0) { + *os << "called " << FormatTimes(actual_call_count); + } else { + *os << "never called"; + } +} + +// Creates a cardinality that allows at least n calls. +Cardinality AtLeast(int n) { return Between(n, INT_MAX); } + +// Creates a cardinality that allows at most n calls. +Cardinality AtMost(int n) { return Between(0, n); } + +// Creates a cardinality that allows any number of calls. +Cardinality AnyNumber() { return AtLeast(0); } + +// Creates a cardinality that allows between min and max calls. +Cardinality Between(int min, int max) { + return Cardinality(new BetweenCardinalityImpl(min, max)); +} + +// Creates a cardinality that allows exactly n calls. +Cardinality Exactly(int n) { return Between(n, n); } + +} // namespace testing diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc new file mode 100644 index 00000000..58bc64e4 --- /dev/null +++ b/src/gmock-internal-utils.cc @@ -0,0 +1,135 @@ +// 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 defines some utilities useful for implementing Google +// Mock. They are subject to change without notice, so please DO NOT +// USE THEM IN USER CODE. + +#include + +#include // NOLINT +#include +#include +#include +#include + +namespace testing { +namespace internal { + +// This class reports Google Mock failures as Google Test failures. A +// user can define another class in a similar fashion if he intends to +// use Google Mock with a testing framework other than Google Test. +class GoogleTestFailureReporter : public FailureReporterInterface { + public: + virtual void ReportFailure(FailureType type, const char* file, int line, + const string& message) { + AssertHelper(type == FATAL ? TPRT_FATAL_FAILURE : TPRT_NONFATAL_FAILURE, + file, line, message.c_str()) = Message(); + if (type == FATAL) { + abort(); + } + } +}; + +// Returns the global failure reporter. Will create a +// GoogleTestFailureReporter and return it the first time called. +FailureReporterInterface* GetFailureReporter() { + // Points to the global failure reporter used by Google Mock. gcc + // guarantees that the following use of failure_reporter is + // thread-safe. We may need to add additional synchronization to + // protect failure_reporter if we port Google Mock to other + // compilers. + static FailureReporterInterface* const failure_reporter = + new GoogleTestFailureReporter(); + return failure_reporter; +} + +// Protects global resources (stdout in particular) used by Log(). +static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); + +// Prints the given message to stdout iff 'severity' >= the level +// specified by the --gmock_verbose flag. If stack_frames_to_skip >= +// 0, also prints the stack trace excluding the top +// stack_frames_to_skip frames. In opt mode, any positive +// stack_frames_to_skip is treated as 0, since we don't know which +// function calls will be inlined by the compiler and need to be +// conservative. +void Log(LogSeverity severity, const string& message, + int stack_frames_to_skip) { + if (GMOCK_FLAG(verbose) == kErrorVerbosity) { + // The user is not interested in logs. + return; + } else if (GMOCK_FLAG(verbose) != kInfoVerbosity) { + // The user is interested in warnings but not informational logs. + // Note that invalid values of GMOCK_FLAG(verbose) are treated as + // "warning", which is the default value of the flag. + if (severity == INFO) { + return; + } + } + + // Ensures that logs from different threads don't interleave. + MutexLock l(&g_log_mutex); + using ::std::cout; + if (severity == WARNING) { + // Prints a GMOCK WARNING marker to make the warnings easily searchable. + cout << "\nGMOCK WARNING:"; + } + // Pre-pends a new-line to message if it doesn't start with one. + if (message.empty() || message[0] != '\n') { + cout << "\n"; + } + cout << message; + if (stack_frames_to_skip >= 0) { +#ifdef NDEBUG + // In opt mode, we have to be conservative and skip no stack frame. + const int actual_to_skip = 0; +#else + // In dbg mode, we can do what the caller tell us to do (plus one + // for skipping this function's stack frame). + const int actual_to_skip = stack_frames_to_skip + 1; +#endif // NDEBUG + + // Appends a new-line to message if it doesn't end with one. + if (!message.empty() && *message.rbegin() != '\n') { + cout << "\n"; + } + cout << "Stack trace:\n" + << ::testing::internal::GetCurrentOsStackTraceExceptTop( + ::testing::UnitTest::GetInstance(), actual_to_skip); + } + cout << ::std::flush; +} + +} // namespace internal +} // namespace testing diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc new file mode 100644 index 00000000..99fd3a2d --- /dev/null +++ b/src/gmock-matchers.cc @@ -0,0 +1,61 @@ +// 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 the Matcher and +// Matcher. + +#include + +namespace testing { + +// Constructs a matcher that matches a const string& whose value is +// equal to s. +Matcher::Matcher(const internal::string& s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a const string& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(internal::string(s)); +} + +// Constructs a matcher that matches a string whose value is equal to s. +Matcher::Matcher(const internal::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a string whose value is equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(internal::string(s)); +} + +} // namespace testing diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc new file mode 100644 index 00000000..611d8659 --- /dev/null +++ b/src/gmock-printers.cc @@ -0,0 +1,309 @@ +// 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 a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include +#include +#include +#include // NOLINT +#include +#include + +namespace testing { + +namespace { + +using ::std::ostream; + +#ifdef GTEST_OS_WINDOWS +#define snprintf _snprintf_s +#endif + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) { + *os << " "; + } + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Prints a wide char as a char literal without the quotes, escaping it +// when necessary. +static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\?': + *os << "\\?"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + // isprint() takes an int and requires it to be either EOF or in + // the range [0, 255]. We check that c is in this range before calling it. + if ((c & 0xFF) == c && isprint(c)) { + *os << static_cast(c); + } else { + // Buffer size enough for the maximum number of digits and \0. + char text[2 * sizeof(unsigned long) + 1] = ""; + snprintf(text, sizeof(text), "%lX", static_cast(c)); + *os << "\\x" << text; + } + } +} + +// Prints a char as if it's part of a string literal, escaping it when +// necessary. +static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + break; + case L'"': + *os << "\\\""; + break; + default: + PrintAsWideCharLiteralTo(c, os); + } +} + +// Prints a char as a char literal without the quotes, escaping it +// when necessary. +static void PrintAsCharLiteralTo(char c, ostream* os) { + PrintAsWideCharLiteralTo(static_cast(c), os); +} + +// Prints a char as if it's part of a string literal, escaping it when +// necessary. +static void PrintAsStringLiteralTo(char c, ostream* os) { + PrintAsWideStringLiteralTo(static_cast(c), os); +} + +// Prints a char and its code. The '\0' char is printed as "'\\0'", +// other unprintable characters are also properly escaped using the +// standard C++ escape sequence. +void PrintCharTo(char c, int char_code, ostream* os) { + *os << "'"; + PrintAsCharLiteralTo(c, os); + *os << "'"; + if (c != '\0') + *os << " (" << char_code << ")"; +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +void PrintTo(wchar_t wc, ostream* os) { + *os << "L'"; + PrintAsWideCharLiteralTo(wc, os); + *os << "'"; + if (wc != L'\0') { + // Type Int64 is used because it provides more storage than wchar_t thus + // when the compiler converts signed or unsigned implementation of wchar_t + // to Int64 it fills higher bits with either zeros or the sign bit + // passing it to operator <<() as either signed or unsigned integer. + *os << " (" << static_cast(wc) << ")"; + } +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + for (size_t index = 0; index < len; ++index) { + PrintAsStringLiteralTo(begin[index], os); + } + *os << "\""; +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + for (size_t index = 0; index < len; ++index) { + PrintAsWideStringLiteralTo(begin[index], os); + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << implicit_cast(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << implicit_cast(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_STD_STRING +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_STRING + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc new file mode 100644 index 00000000..353bb2df --- /dev/null +++ b/src/gmock-spec-builders.cc @@ -0,0 +1,337 @@ +// 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 the spec builder syntax (ON_CALL and +// EXPECT_CALL). + +#include + +#include +#include + +namespace testing { +namespace internal { + +// Protects the mock object registry (in class Mock), all function +// mockers, and all expectations. +Mutex g_gmock_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); + +// Constructs an ExpectationBase object. +ExpectationBase::ExpectationBase(const char* file, int line) + : file_(file), + line_(line), + cardinality_specified_(false), + cardinality_(Exactly(1)), + call_count_(0), + retired_(false) { +} + +// Destructs an ExpectationBase object. +ExpectationBase::~ExpectationBase() {} + +// Explicitly specifies the cardinality of this expectation. Used by +// the subclasses to implement the .Times() clause. +void ExpectationBase::SpecifyCardinality(const Cardinality& cardinality) { + cardinality_specified_ = true; + cardinality_ = cardinality; +} + +// Retires all pre-requisites of this expectation. +void ExpectationBase::RetireAllPreRequisites() { + if (is_retired()) { + // We can take this short-cut as we never retire an expectation + // until we have retired all its pre-requisites. + return; + } + + for (ExpectationBaseSet::const_iterator it = + immediate_prerequisites_.begin(); + it != immediate_prerequisites_.end(); + ++it) { + ExpectationBase* const prerequisite = (*it).get(); + if (!prerequisite->is_retired()) { + prerequisite->RetireAllPreRequisites(); + prerequisite->Retire(); + } + } +} + +// Returns true iff all pre-requisites of this expectation have been +// satisfied. +// L >= g_gmock_mutex +bool ExpectationBase::AllPrerequisitesAreSatisfied() const { + g_gmock_mutex.AssertHeld(); + for (ExpectationBaseSet::const_iterator it = immediate_prerequisites_.begin(); + it != immediate_prerequisites_.end(); ++it) { + if (!(*it)->IsSatisfied() || + !(*it)->AllPrerequisitesAreSatisfied()) + return false; + } + return true; +} + +// Adds unsatisfied pre-requisites of this expectation to 'result'. +// L >= g_gmock_mutex +void ExpectationBase::FindUnsatisfiedPrerequisites( + ExpectationBaseSet* result) const { + g_gmock_mutex.AssertHeld(); + for (ExpectationBaseSet::const_iterator it = immediate_prerequisites_.begin(); + it != immediate_prerequisites_.end(); ++it) { + if ((*it)->IsSatisfied()) { + // If *it is satisfied and has a call count of 0, some of its + // pre-requisites may not be satisfied yet. + if ((*it)->call_count_ == 0) { + (*it)->FindUnsatisfiedPrerequisites(result); + } + } else { + // Now that we know *it is unsatisfied, we are not so interested + // in whether its pre-requisites are satisfied. Therefore we + // don't recursively call FindUnsatisfiedPrerequisites() here. + result->insert(*it); + } + } +} + +// Points to the implicit sequence introduced by a living InSequence +// object (if any) in the current thread or NULL. +ThreadLocal g_gmock_implicit_sequence; + +// Reports an uninteresting call (whose description is in msg) in the +// manner specified by 'reaction'. +void ReportUninterestingCall(CallReaction reaction, const string& msg) { + switch (reaction) { + case ALLOW: + Log(INFO, msg, 4); + break; + case WARN: + Log(WARNING, msg, 4); + break; + default: // FAIL + Expect(false, NULL, -1, msg); + } +} + +} // namespace internal + +// Class Mock. + +namespace { + +typedef std::set FunctionMockers; +typedef std::map MockObjectRegistry; + +// Maps a mock object to the set of mock methods it owns. Protected +// by g_gmock_mutex. +MockObjectRegistry g_mock_object_registry; + +// Maps a mock object to the reaction Google Mock should have when an +// uninteresting method is called. Protected by g_gmock_mutex. +std::map g_uninteresting_call_reaction; + +// Sets the reaction Google Mock should have when an uninteresting +// method of the given mock object is called. +// L < g_gmock_mutex +void SetReactionOnUninterestingCalls(const void* mock_obj, + internal::CallReaction reaction) { + internal::MutexLock l(&internal::g_gmock_mutex); + g_uninteresting_call_reaction[mock_obj] = reaction; +} + +} // namespace + +// Tells Google Mock to allow uninteresting calls on the given mock +// object. +// L < g_gmock_mutex +void Mock::AllowUninterestingCalls(const void* mock_obj) { + SetReactionOnUninterestingCalls(mock_obj, internal::ALLOW); +} + +// Tells Google Mock to warn the user about uninteresting calls on the +// given mock object. +// L < g_gmock_mutex +void Mock::WarnUninterestingCalls(const void* mock_obj) { + SetReactionOnUninterestingCalls(mock_obj, internal::WARN); +} + +// Tells Google Mock to fail uninteresting calls on the given mock +// object. +// L < g_gmock_mutex +void Mock::FailUninterestingCalls(const void* mock_obj) { + SetReactionOnUninterestingCalls(mock_obj, internal::FAIL); +} + +// Tells Google Mock the given mock object is being destroyed and its +// entry in the call-reaction table should be removed. +// L < g_gmock_mutex +void Mock::UnregisterCallReaction(const void* mock_obj) { + internal::MutexLock l(&internal::g_gmock_mutex); + g_uninteresting_call_reaction.erase(mock_obj); +} + +// Returns the reaction Google Mock will have on uninteresting calls +// made on the given mock object. +// L < g_gmock_mutex +internal::CallReaction Mock::GetReactionOnUninterestingCalls( + const void* mock_obj) { + internal::MutexLock l(&internal::g_gmock_mutex); + return (g_uninteresting_call_reaction.count(mock_obj) == 0) ? + internal::WARN : g_uninteresting_call_reaction[mock_obj]; +} + +// Verifies and clears all expectations on the given mock object. If +// the expectations aren't satisfied, generates one or more Google +// Test non-fatal failures and returns false. +// L < g_gmock_mutex +bool Mock::VerifyAndClearExpectations(void* mock_obj) { + internal::MutexLock l(&internal::g_gmock_mutex); + return VerifyAndClearExpectationsLocked(mock_obj); +} + +// Verifies all expectations on the given mock object and clears its +// default actions and expectations. Returns true iff the +// verification was successful. +// L < g_gmock_mutex +bool Mock::VerifyAndClear(void* mock_obj) { + internal::MutexLock l(&internal::g_gmock_mutex); + ClearDefaultActionsLocked(mock_obj); + return VerifyAndClearExpectationsLocked(mock_obj); +} + +// Verifies and clears all expectations on the given mock object. If +// the expectations aren't satisfied, generates one or more Google +// Test non-fatal failures and returns false. +// L >= g_gmock_mutex +bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) { + internal::g_gmock_mutex.AssertHeld(); + if (g_mock_object_registry.count(mock_obj) == 0) { + // No EXPECT_CALL() was set on the given mock object. + return true; + } + + // Verifies and clears the expectations on each mock method in the + // given mock object. + bool expectations_met = true; + FunctionMockers& mockers = g_mock_object_registry[mock_obj]; + for (FunctionMockers::const_iterator it = mockers.begin(); + it != mockers.end(); ++it) { + if (!(*it)->VerifyAndClearExpectationsLocked()) { + expectations_met = false; + } + } + + // We don't clear the content of mockers, as they may still be + // needed by ClearDefaultActionsLocked(). + return expectations_met; +} + +// Registers a mock object and a mock method it owns. +// L < g_gmock_mutex +void Mock::Register(const void* mock_obj, + internal::UntypedFunctionMockerBase* mocker) { + internal::MutexLock l(&internal::g_gmock_mutex); + g_mock_object_registry[mock_obj].insert(mocker); +} + +// Unregisters a mock method; removes the owning mock object from the +// registry when the last mock method associated with it has been +// unregistered. This is called only in the destructor of +// FunctionMockerBase. +// L >= g_gmock_mutex +void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) { + internal::g_gmock_mutex.AssertHeld(); + for (MockObjectRegistry::iterator it = g_mock_object_registry.begin(); + it != g_mock_object_registry.end(); ++it) { + FunctionMockers& mockers = it->second; + if (mockers.erase(mocker) > 0) { + // mocker was in mockers and has been just removed. + if (mockers.empty()) { + g_mock_object_registry.erase(it); + } + return; + } + } +} + +// Clears all ON_CALL()s set on the given mock object. +// L >= g_gmock_mutex +void Mock::ClearDefaultActionsLocked(void* mock_obj) { + internal::g_gmock_mutex.AssertHeld(); + + if (g_mock_object_registry.count(mock_obj) == 0) { + // No ON_CALL() was set on the given mock object. + return; + } + + // Clears the default actions for each mock method in the given mock + // object. + FunctionMockers& mockers = g_mock_object_registry[mock_obj]; + for (FunctionMockers::const_iterator it = mockers.begin(); + it != mockers.end(); ++it) { + (*it)->ClearDefaultActionsLocked(); + } + + // We don't clear the content of mockers, as they may still be + // needed by VerifyAndClearExpectationsLocked(). +} + +// Adds an expectation to a sequence. +void Sequence::AddExpectation( + const internal::linked_ptr& expectation) const { + if (*last_expectation_ != expectation) { + if (*last_expectation_ != NULL) { + expectation->immediate_prerequisites_.insert(*last_expectation_); + } + *last_expectation_ = expectation; + } +} + +// Creates the implicit sequence if there isn't one. +InSequence::InSequence() { + if (internal::g_gmock_implicit_sequence.get() == NULL) { + internal::g_gmock_implicit_sequence.set(new Sequence); + sequence_created_ = true; + } else { + sequence_created_ = false; + } +} + +// Deletes the implicit sequence if it was created by the constructor +// of this object. +InSequence::~InSequence() { + if (sequence_created_) { + delete internal::g_gmock_implicit_sequence.get(); + internal::g_gmock_implicit_sequence.set(NULL); + } +} + +} // namespace testing diff --git a/src/gmock.cc b/src/gmock.cc new file mode 100644 index 00000000..b2f3d59d --- /dev/null +++ b/src/gmock.cc @@ -0,0 +1,155 @@ +// 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) + +#include +#include + +namespace testing { + +GMOCK_DEFINE_string(verbose, internal::kWarningVerbosity, + "Controls how verbose Google Mock's output is." + " Valid values:\n" + " info - prints all messages.\n" + " warning - prints warnings and errors.\n" + " error - prints errors only."); + +namespace internal { + +// Parses a string as a command line flag. The string should have the +// format "--gmock_flag=value". When def_optional is true, the +// "=value" part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +static const char* ParseGoogleMockFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--gmock_". + const String flag_str = String::Format("--gmock_%s", flag); + const size_t flag_len = flag_str.GetLength(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // 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 NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a Google Mock string flag, in the form of +// "--gmock_flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +static bool ParseGoogleMockStringFlag(const char* str, const char* flag, + String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseGoogleMockFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// The internal implementation of InitGoogleMock(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleMockImpl(int* argc, CharType** argv) { + // Makes sure Google Test is initialized. InitGoogleTest() is + // idempotent, so it's fine if the user has already called it. + InitGoogleTest(argc, argv); + if (*argc <= 0) return; + + for (int i = 1; i != *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + // Do we see a Google Mock flag? + if (ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } + } +} + +} // namespace internal + +// Initializes Google Mock. This must be called before running the +// tests. In particular, it parses a command line for the flags that +// Google Mock recognizes. Whenever a Google Mock flag is seen, it is +// removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Mock flag variables are +// updated. +// +// Since Google Test is needed for Google Mock to work, this function +// also initializes Google Test and parses its flags, if that hasn't +// been done. +void InitGoogleMock(int* argc, char** argv) { + internal::InitGoogleMockImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleMock(int* argc, wchar_t** argv) { + internal::InitGoogleMockImpl(argc, argv); +} + +} // namespace testing diff --git a/src/gmock_main.cc b/src/gmock_main.cc new file mode 100644 index 00000000..a97e9532 --- /dev/null +++ b/src/gmock_main.cc @@ -0,0 +1,43 @@ +// 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) + +#include +#include +#include + +int main(int argc, char **argv) { + std::cout << "Running main() from gmock_main.cc\n"; + // Since Google Mock depends on Google Test, InitGoogleMock() is + // also responsible for initializing Google Test. Therefore there's + // no need for calling testing::InitGoogleTest() separately. + testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc new file mode 100644 index 00000000..1000e306 --- /dev/null +++ b/test/gmock-actions_test.cc @@ -0,0 +1,902 @@ +// 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 tests the built-in actions. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using ::std::tr1::get; +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +using ::std::tr1::tuple_element; +using testing::internal::BuiltInDefaultValue; +using testing::internal::Int64; +using testing::internal::UInt64; +// This list should be kept sorted. +using testing::_; +using testing::Action; +using testing::ActionInterface; +using testing::Assign; +using testing::DefaultValue; +using testing::DoDefault; +using testing::IgnoreResult; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::MakePolymorphicAction; +using testing::Ne; +using testing::PolymorphicAction; +using testing::Return; +using testing::ReturnNull; +using testing::ReturnRef; +using testing::SetArgumentPointee; +using testing::SetArrayArgument; +using testing::SetErrnoAndReturn; + +#if GMOCK_HAS_PROTOBUF_ +using testing::internal::TestMessage; +#endif // GMOCK_HAS_PROTOBUF_ + +// Tests that BuiltInDefaultValue::Get() returns NULL. +TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) { + EXPECT_TRUE(BuiltInDefaultValue::Get() == NULL); + EXPECT_TRUE(BuiltInDefaultValue::Get() == NULL); + EXPECT_TRUE(BuiltInDefaultValue::Get() == NULL); +} + +// Tests that BuiltInDefaultValue::Get() returns 0 when T is a +// built-in numeric type. +TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); +#ifndef GTEST_OS_WINDOWS + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); +#endif // GTEST_OS_WINDOWS + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); +} + +// Tests that BuiltInDefaultValue::Get() returns false. +TEST(BuiltInDefaultValueTest, IsFalseForBool) { + EXPECT_FALSE(BuiltInDefaultValue::Get()); +} + +// Tests that BuiltInDefaultValue::Get() returns "" when T is a +// string type. +TEST(BuiltInDefaultValueTest, IsEmptyStringForString) { +#if GTEST_HAS_GLOBAL_STRING + EXPECT_EQ("", BuiltInDefaultValue< ::string>::Get()); +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_STD_STRING + EXPECT_EQ("", BuiltInDefaultValue< ::std::string>::Get()); +#endif // GTEST_HAS_STD_STRING +} + +// Tests that BuiltInDefaultValue::Get() returns the same +// value as BuiltInDefaultValue::Get() does. +TEST(BuiltInDefaultValueTest, WorksForConstTypes) { + EXPECT_EQ("", BuiltInDefaultValue::Get()); + EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_TRUE(BuiltInDefaultValue::Get() == NULL); + EXPECT_FALSE(BuiltInDefaultValue::Get()); +} + +// Tests that BuiltInDefaultValue::Get() aborts the program with +// the correct error message when T is a user-defined type. +struct UserType { + UserType() : value(0) {} + + int value; +}; + +#ifdef GTEST_HAS_DEATH_TEST + +// Tests that BuiltInDefaultValue::Get() aborts the program. +TEST(BuiltInDefaultValueDeathTest, IsUndefinedForReferences) { + EXPECT_DEATH({ // NOLINT + BuiltInDefaultValue::Get(); + }, ""); + EXPECT_DEATH({ // NOLINT + BuiltInDefaultValue::Get(); + }, ""); +} + +TEST(BuiltInDefaultValueDeathTest, IsUndefinedForUserTypes) { + EXPECT_DEATH({ // NOLINT + BuiltInDefaultValue::Get(); + }, ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Tests that DefaultValue::IsSet() is false initially. +TEST(DefaultValueTest, IsInitiallyUnset) { + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); +} + +// Tests that DefaultValue can be set and then unset. +TEST(DefaultValueTest, CanBeSetAndUnset) { + DefaultValue::Set(1); + DefaultValue::Set(UserType()); + + EXPECT_EQ(1, DefaultValue::Get()); + EXPECT_EQ(0, DefaultValue::Get().value); + + DefaultValue::Clear(); + DefaultValue::Clear(); + + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); +} + +// Tests that DefaultValue::Get() returns the +// BuiltInDefaultValue::Get() when DefaultValue::IsSet() is +// false. +TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); + + EXPECT_EQ(0, DefaultValue::Get()); + +#ifdef GTEST_HAS_DEATH_TEST + EXPECT_DEATH({ // NOLINT + DefaultValue::Get(); + }, ""); +#endif // GTEST_HAS_DEATH_TEST +} + +// Tests that DefaultValue::Get() returns void. +TEST(DefaultValueTest, GetWorksForVoid) { + return DefaultValue::Get(); +} + +// Tests using DefaultValue with a reference type. + +// Tests that DefaultValue::IsSet() is false initially. +TEST(DefaultValueOfReferenceTest, IsInitiallyUnset) { + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); +} + +// Tests that DefaultValue can be set and then unset. +TEST(DefaultValueOfReferenceTest, CanBeSetAndUnset) { + int n = 1; + DefaultValue::Set(n); + UserType u; + DefaultValue::Set(u); + + EXPECT_EQ(&n, &(DefaultValue::Get())); + EXPECT_EQ(&u, &(DefaultValue::Get())); + + DefaultValue::Clear(); + DefaultValue::Clear(); + + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); +} + +// Tests that DefaultValue::Get() returns the +// BuiltInDefaultValue::Get() when DefaultValue::IsSet() is +// false. +TEST(DefaultValueOfReferenceDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); + +#ifdef GTEST_HAS_DEATH_TEST + EXPECT_DEATH({ // NOLINT + DefaultValue::Get(); + }, ""); + EXPECT_DEATH({ // NOLINT + DefaultValue::Get(); + }, ""); +#endif // GTEST_HAS_DEATH_TEST +} + +// Tests that ActionInterface can be implemented by defining the +// Perform method. + +typedef int MyFunction(bool, int); + +class MyActionImpl : public ActionInterface { + public: + virtual int Perform(const tuple& args) { + return get<0>(args) ? get<1>(args) : 0; + } +}; + +TEST(ActionInterfaceTest, CanBeImplementedByDefiningPerform) { + MyActionImpl my_action_impl; + + EXPECT_FALSE(my_action_impl.IsDoDefault()); +} + +TEST(ActionInterfaceTest, MakeAction) { + Action action = MakeAction(new MyActionImpl); + + // When exercising the Perform() method of Action, we must pass + // it a tuple whose size and type are compatible with F's argument + // types. For example, if F is int(), then Perform() takes a + // 0-tuple; if F is void(bool, int), then Perform() takes a + // tuple, and so on. + EXPECT_EQ(5, action.Perform(make_tuple(true, 5))); +} + +// Tests that Action can be contructed from a pointer to +// ActionInterface. +TEST(ActionTest, CanBeConstructedFromActionInterface) { + Action action(new MyActionImpl); +} + +// Tests that Action delegates actual work to ActionInterface. +TEST(ActionTest, DelegatesWorkToActionInterface) { + const Action action(new MyActionImpl); + + EXPECT_EQ(5, action.Perform(make_tuple(true, 5))); + EXPECT_EQ(0, action.Perform(make_tuple(false, 1))); +} + +// Tests that Action can be copied. +TEST(ActionTest, IsCopyable) { + Action a1(new MyActionImpl); + Action a2(a1); // Tests the copy constructor. + + // a1 should continue to work after being copied from. + EXPECT_EQ(5, a1.Perform(make_tuple(true, 5))); + EXPECT_EQ(0, a1.Perform(make_tuple(false, 1))); + + // a2 should work like the action it was copied from. + EXPECT_EQ(5, a2.Perform(make_tuple(true, 5))); + EXPECT_EQ(0, a2.Perform(make_tuple(false, 1))); + + a2 = a1; // Tests the assignment operator. + + // a1 should continue to work after being copied from. + EXPECT_EQ(5, a1.Perform(make_tuple(true, 5))); + EXPECT_EQ(0, a1.Perform(make_tuple(false, 1))); + + // a2 should work like the action it was copied from. + EXPECT_EQ(5, a2.Perform(make_tuple(true, 5))); + EXPECT_EQ(0, a2.Perform(make_tuple(false, 1))); +} + +// Tests that an Action object can be converted to a +// compatible Action object. + +class IsNotZero : public ActionInterface { // NOLINT + public: + virtual bool Perform(const tuple& arg) { + return get<0>(arg) != 0; + } +}; + +TEST(ActionTest, CanBeConvertedToOtherActionType) { + const Action a1(new IsNotZero); // NOLINT + const Action a2 = Action(a1); // NOLINT + EXPECT_EQ(1, a2.Perform(make_tuple('a'))); + EXPECT_EQ(0, a2.Perform(make_tuple('\0'))); +} + +// The following two classes are for testing MakePolymorphicAction(). + +// Implements a polymorphic action that returns the second of the +// arguments it receives. +class ReturnSecondArgumentAction { + public: + // We want to verify that MakePolymorphicAction() can work with a + // polymorphic action whose Perform() method template is either + // const or not. This lets us verify the non-const case. + template + Result Perform(const ArgumentTuple& args) { return get<1>(args); } +}; + +// Implements a polymorphic action that can be used in a nullary +// function to return 0. +class ReturnZeroFromNullaryFunctionAction { + public: + // For testing that MakePolymorphicAction() works when the + // implementation class' Perform() method template takes only one + // template parameter. + // + // We want to verify that MakePolymorphicAction() can work with a + // polymorphic action whose Perform() method template is either + // const or not. This lets us verify the const case. + template + Result Perform(const tuple<>&) const { return 0; } +}; + +// These functions verify that MakePolymorphicAction() returns a +// PolymorphicAction where T is the argument's type. + +PolymorphicAction ReturnSecondArgument() { + return MakePolymorphicAction(ReturnSecondArgumentAction()); +} + +PolymorphicAction +ReturnZeroFromNullaryFunction() { + return MakePolymorphicAction(ReturnZeroFromNullaryFunctionAction()); +} + +// Tests that MakePolymorphicAction() turns a polymorphic action +// implementation class into a polymorphic action. +TEST(MakePolymorphicActionTest, ConstructsActionFromImpl) { + Action a1 = ReturnSecondArgument(); // NOLINT + EXPECT_EQ(5, a1.Perform(make_tuple(false, 5, 2.0))); +} + +// Tests that MakePolymorphicAction() works when the implementation +// class' Perform() method template has only one template parameter. +TEST(MakePolymorphicActionTest, WorksWhenPerformHasOneTemplateParameter) { + Action a1 = ReturnZeroFromNullaryFunction(); + EXPECT_EQ(0, a1.Perform(make_tuple())); + + Action a2 = ReturnZeroFromNullaryFunction(); + EXPECT_TRUE(a2.Perform(make_tuple()) == NULL); +} + +// Tests that Return() works as an action for void-returning +// functions. +TEST(ReturnTest, WorksForVoid) { + const Action ret = Return(); // NOLINT + return ret.Perform(make_tuple(1)); +} + +// Tests that Return(v) returns v. +TEST(ReturnTest, ReturnsGivenValue) { + Action ret = Return(1); // NOLINT + EXPECT_EQ(1, ret.Perform(make_tuple())); + + ret = Return(-5); + EXPECT_EQ(-5, ret.Perform(make_tuple())); +} + +// Tests that Return("string literal") works. +TEST(ReturnTest, AcceptsStringLiteral) { + Action a1 = Return("Hello"); + EXPECT_STREQ("Hello", a1.Perform(make_tuple())); + + Action a2 = Return("world"); + EXPECT_EQ("world", a2.Perform(make_tuple())); +} + +// Tests that Return(v) is covaraint. + +struct Base { + bool operator==(const Base&) { return true; } +}; + +struct Derived : public Base { + bool operator==(const Derived&) { return true; } +}; + +TEST(ReturnTest, IsCovariant) { + Base base; + Derived derived; + Action ret = Return(&base); + EXPECT_EQ(&base, ret.Perform(make_tuple())); + + ret = Return(&derived); + EXPECT_EQ(&derived, ret.Perform(make_tuple())); +} + +// Tests that ReturnNull() returns NULL in a pointer-returning function. +TEST(ReturnNullTest, WorksInPointerReturningFunction) { + const Action a1 = ReturnNull(); + EXPECT_TRUE(a1.Perform(make_tuple()) == NULL); + + const Action a2 = ReturnNull(); // NOLINT + EXPECT_TRUE(a2.Perform(make_tuple(true)) == NULL); +} + +// Tests that ReturnRef(v) works for reference types. +TEST(ReturnRefTest, WorksForReference) { + const int n = 0; + const Action ret = ReturnRef(n); // NOLINT + + EXPECT_EQ(&n, &ret.Perform(make_tuple(true))); +} + +// Tests that ReturnRef(v) is covariant. +TEST(ReturnRefTest, IsCovariant) { + Base base; + Derived derived; + Action a = ReturnRef(base); + EXPECT_EQ(&base, &a.Perform(make_tuple())); + + a = ReturnRef(derived); + EXPECT_EQ(&derived, &a.Perform(make_tuple())); +} + +// Tests that DoDefault() does the default action for the mock method. + +class MyClass {}; + +class MockClass { + public: + MOCK_METHOD1(IntFunc, int(bool flag)); // NOLINT + MOCK_METHOD0(Foo, MyClass()); +}; + +// Tests that DoDefault() returns the built-in default value for the +// return type by default. +TEST(DoDefaultTest, ReturnsBuiltInDefaultValueByDefault) { + MockClass mock; + EXPECT_CALL(mock, IntFunc(_)) + .WillOnce(DoDefault()); + EXPECT_EQ(0, mock.IntFunc(true)); +} + +#ifdef GTEST_HAS_DEATH_TEST + +// Tests that DoDefault() aborts the process when there is no built-in +// default value for the return type. +TEST(DoDefaultDeathTest, DiesForUnknowType) { + MockClass mock; + EXPECT_CALL(mock, Foo()) + .WillRepeatedly(DoDefault()); + EXPECT_DEATH({ // NOLINT + mock.Foo(); + }, ""); +} + +// Tests that using DoDefault() inside a composite action leads to a +// run-time error. + +void VoidFunc(bool flag) {} + +TEST(DoDefaultDeathTest, DiesIfUsedInCompositeAction) { + MockClass mock; + EXPECT_CALL(mock, IntFunc(_)) + .WillRepeatedly(DoAll(Invoke(VoidFunc), + DoDefault())); + + // Ideally we should verify the error message as well. Sadly, + // EXPECT_DEATH() can only capture stderr, while Google Mock's + // errors are printed on stdout. Therefore we have to settle for + // not verifying the message. + EXPECT_DEATH({ // NOLINT + mock.IntFunc(true); + }, ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Tests that DoDefault() returns the default value set by +// DefaultValue::Set() when it's not overriden by an ON_CALL(). +TEST(DoDefaultTest, ReturnsUserSpecifiedPerTypeDefaultValueWhenThereIsOne) { + DefaultValue::Set(1); + MockClass mock; + EXPECT_CALL(mock, IntFunc(_)) + .WillOnce(DoDefault()); + EXPECT_EQ(1, mock.IntFunc(false)); + DefaultValue::Clear(); +} + +// Tests that DoDefault() does the action specified by ON_CALL(). +TEST(DoDefaultTest, DoesWhatOnCallSpecifies) { + MockClass mock; + ON_CALL(mock, IntFunc(_)) + .WillByDefault(Return(2)); + EXPECT_CALL(mock, IntFunc(_)) + .WillOnce(DoDefault()); + EXPECT_EQ(2, mock.IntFunc(false)); +} + +// Tests that using DoDefault() in ON_CALL() leads to a run-time failure. +TEST(DoDefaultTest, CannotBeUsedInOnCall) { + MockClass mock; + EXPECT_NONFATAL_FAILURE({ // NOLINT + ON_CALL(mock, IntFunc(_)) + .WillByDefault(DoDefault()); + }, "DoDefault() cannot be used in ON_CALL()"); +} + +// Tests that SetArgumentPointee(v) sets the variable pointed to by +// the N-th (0-based) argument to v. +TEST(SetArgumentPointeeTest, SetsTheNthPointee) { + typedef void MyFunction(bool, int*, char*); + Action a = SetArgumentPointee<1>(2); + + int n = 0; + char ch = '\0'; + a.Perform(make_tuple(true, &n, &ch)); + EXPECT_EQ(2, n); + EXPECT_EQ('\0', ch); + + a = SetArgumentPointee<2>('a'); + n = 0; + ch = '\0'; + a.Perform(make_tuple(true, &n, &ch)); + EXPECT_EQ(0, n); + EXPECT_EQ('a', ch); +} + +#if GMOCK_HAS_PROTOBUF_ + +// Tests that SetArgumentPointee(proto_buffer) sets the variable +// pointed to by the N-th (0-based) argument to proto_buffer. +TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferType) { + typedef void MyFunction(bool, TestMessage*); + TestMessage* const msg = new TestMessage; + msg->set_member("yes"); + TestMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgumentPointee<1>(*msg); + // SetArgumentPointee(proto_buffer) makes a copy of proto_buffer + // s.t. the action works even when the original proto_buffer has + // died. We ensure this behavior by deleting msg before using the + // action. + delete msg; + + TestMessage dest; + EXPECT_FALSE(orig_msg.Equals(dest)); + a.Perform(make_tuple(true, &dest)); + EXPECT_TRUE(orig_msg.Equals(dest)); +} + +// Tests that SetArgumentPointee(proto2_buffer) sets the variable +// pointed to by the N-th (0-based) argument to proto2_buffer. +TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferType) { + using testing::internal::FooMessage; + typedef void MyFunction(bool, FooMessage*); + FooMessage* const msg = new FooMessage; + msg->set_int_field(2); + msg->set_string_field("hi"); + FooMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgumentPointee<1>(*msg); + // SetArgumentPointee(proto2_buffer) makes a copy of + // proto2_buffer s.t. the action works even when the original + // proto2_buffer has died. We ensure this behavior by deleting msg + // before using the action. + delete msg; + + FooMessage dest; + dest.set_int_field(0); + a.Perform(make_tuple(true, &dest)); + EXPECT_EQ(2, dest.int_field()); + EXPECT_EQ("hi", dest.string_field()); +} + +#endif // GMOCK_HAS_PROTOBUF_ + +// Tests that SetArrayArgument(first, last) sets the elements of the array +// pointed to by the N-th (0-based) argument to values in range [first, last). +TEST(SetArrayArgumentTest, SetsTheNthArray) { + typedef void MyFunction(bool, int*, char*); + int numbers[] = { 1, 2, 3 }; + Action a = SetArrayArgument<1>(numbers, numbers + 3); + + int n[4] = {}; + int* pn = n; + char ch[4] = {}; + char* pch = ch; + a.Perform(make_tuple(true, pn, pch)); + EXPECT_EQ(1, n[0]); + EXPECT_EQ(2, n[1]); + EXPECT_EQ(3, n[2]); + EXPECT_EQ(0, n[3]); + EXPECT_EQ('\0', ch[0]); + EXPECT_EQ('\0', ch[1]); + EXPECT_EQ('\0', ch[2]); + EXPECT_EQ('\0', ch[3]); + + // Tests first and last are iterators. + std::string letters = "abc"; + a = SetArrayArgument<2>(letters.begin(), letters.end()); + std::fill_n(n, 4, 0); + std::fill_n(ch, 4, '\0'); + a.Perform(make_tuple(true, pn, pch)); + EXPECT_EQ(0, n[0]); + EXPECT_EQ(0, n[1]); + EXPECT_EQ(0, n[2]); + EXPECT_EQ(0, n[3]); + EXPECT_EQ('a', ch[0]); + EXPECT_EQ('b', ch[1]); + EXPECT_EQ('c', ch[2]); + EXPECT_EQ('\0', ch[3]); +} + +// Tests SetArrayArgument(first, last) where first == last. +TEST(SetArrayArgumentTest, SetsTheNthArrayWithEmptyRange) { + typedef void MyFunction(bool, int*); + int numbers[] = { 1, 2, 3 }; + Action a = SetArrayArgument<1>(numbers, numbers); + + int n[4] = {}; + int* pn = n; + a.Perform(make_tuple(true, pn)); + EXPECT_EQ(0, n[0]); + EXPECT_EQ(0, n[1]); + EXPECT_EQ(0, n[2]); + EXPECT_EQ(0, n[3]); +} + +// Tests SetArrayArgument(first, last) where *first is convertible +// (but not equal) to the argument type. +TEST(SetArrayArgumentTest, SetsTheNthArrayWithConvertibleType) { + typedef void MyFunction(bool, char*); + int codes[] = { 97, 98, 99 }; + Action a = SetArrayArgument<1>(codes, codes + 3); + + char ch[4] = {}; + char* pch = ch; + a.Perform(make_tuple(true, pch)); + EXPECT_EQ('a', ch[0]); + EXPECT_EQ('b', ch[1]); + EXPECT_EQ('c', ch[2]); + EXPECT_EQ('\0', ch[3]); +} + +// Test SetArrayArgument(first, last) with iterator as argument. +TEST(SetArrayArgumentTest, SetsTheNthArrayWithIteratorArgument) { + typedef void MyFunction(bool, std::back_insert_iterator); + std::string letters = "abc"; + Action a = SetArrayArgument<1>(letters.begin(), letters.end()); + + std::string s; + a.Perform(make_tuple(true, back_inserter(s))); + EXPECT_EQ(letters, s); +} + +// Sample functions and functors for testing Invoke() and etc. +int Nullary() { return 1; } + +class NullaryFunctor { + public: + int operator()() { return 2; } +}; + +bool g_done = false; +void VoidNullary() { g_done = true; } + +class VoidNullaryFunctor { + public: + void operator()() { g_done = true; } +}; + +bool Unary(int x) { return x < 0; } + +const char* Plus1(const char* s) { return s + 1; } + +void VoidUnary(int n) { g_done = true; } + +bool ByConstRef(const std::string& s) { return s == "Hi"; } + +const double g_double = 0; +bool ReferencesGlobalDouble(const double& x) { return &x == &g_double; } + +std::string ByNonConstRef(std::string& s) { return s += "+"; } // NOLINT + +struct UnaryFunctor { + int operator()(bool x) { return x ? 1 : -1; } +}; + +const char* Binary(const char* input, short n) { return input + n; } // NOLINT + +void VoidBinary(int, char) { g_done = true; } + +int Ternary(int x, char y, short z) { return x + y + z; } // NOLINT + +void VoidTernary(int, char, bool) { g_done = true; } + +int SumOf4(int a, int b, int c, int d) { return a + b + c + d; } + +void VoidFunctionWithFourArguments(char, int, float, double) { g_done = true; } + +int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } + +struct SumOf5Functor { + int operator()(int a, int b, int c, int d, int e) { + return a + b + c + d + e; + } +}; + +int SumOf6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +struct SumOf6Functor { + int operator()(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; + } +}; + +class Foo { + public: + Foo() : value_(123) {} + + int Nullary() const { return value_; } + short Unary(long x) { return static_cast(value_ + x); } // NOLINT + std::string Binary(const std::string& str, char c) const { return str + c; } + int Ternary(int x, bool y, char z) { return value_ + x + y*z; } + int SumOf4(int a, int b, int c, int d) const { + return a + b + c + d + value_; + } + int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } + int SumOf6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; + } + private: + int value_; +}; + +// Tests InvokeWithoutArgs(function). +TEST(InvokeWithoutArgsTest, Function) { + // As an action that takes one argument. + Action a = InvokeWithoutArgs(Nullary); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple(2))); + + // As an action that takes two arguments. + Action a2 = InvokeWithoutArgs(Nullary); // NOLINT + EXPECT_EQ(1, a2.Perform(make_tuple(2, 3.5))); + + // As an action that returns void. + Action a3 = InvokeWithoutArgs(VoidNullary); // NOLINT + g_done = false; + a3.Perform(make_tuple(1)); + EXPECT_TRUE(g_done); +} + +// Tests InvokeWithoutArgs(functor). +TEST(InvokeWithoutArgsTest, Functor) { + // As an action that takes no argument. + Action a = InvokeWithoutArgs(NullaryFunctor()); // NOLINT + EXPECT_EQ(2, a.Perform(make_tuple())); + + // As an action that takes three arguments. + Action a2 = // NOLINT + InvokeWithoutArgs(NullaryFunctor()); + EXPECT_EQ(2, a2.Perform(make_tuple(3, 3.5, 'a'))); + + // As an action that returns void. + Action a3 = InvokeWithoutArgs(VoidNullaryFunctor()); + g_done = false; + a3.Perform(make_tuple()); + EXPECT_TRUE(g_done); +} + +// Tests InvokeWithoutArgs(obj_ptr, method). +TEST(InvokeWithoutArgsTest, Method) { + Foo foo; + Action a = // NOLINT + InvokeWithoutArgs(&foo, &Foo::Nullary); + EXPECT_EQ(123, a.Perform(make_tuple(true, 'a'))); +} + +// Tests using IgnoreResult() on a polymorphic action. +TEST(IgnoreResultTest, PolymorphicAction) { + Action a = IgnoreResult(Return(5)); // NOLINT + a.Perform(make_tuple(1)); +} + +// Tests using IgnoreResult() on a monomorphic action. + +int ReturnOne() { + g_done = true; + return 1; +} + +TEST(IgnoreResultTest, MonomorphicAction) { + g_done = false; + Action a = IgnoreResult(Invoke(ReturnOne)); + a.Perform(make_tuple()); + EXPECT_TRUE(g_done); +} + +// Tests using IgnoreResult() on an action that returns a class type. + +MyClass ReturnMyClass(double x) { + g_done = true; + return MyClass(); +} + +TEST(IgnoreResultTest, ActionReturningClass) { + g_done = false; + Action a = IgnoreResult(Invoke(ReturnMyClass)); // NOLINT + a.Perform(make_tuple(2)); + EXPECT_TRUE(g_done); +} + +TEST(AssignTest, Int) { + int x = 0; + Action a = Assign(&x, 5); + a.Perform(make_tuple(0)); + EXPECT_EQ(5, x); +} + +TEST(AssignTest, String) { + ::std::string x; + Action a = Assign(&x, "Hello, world"); + a.Perform(make_tuple()); + EXPECT_EQ("Hello, world", x); +} + +TEST(AssignTest, CompatibleTypes) { + double x = 0; + Action a = Assign(&x, 5); + a.Perform(make_tuple(0)); + EXPECT_DOUBLE_EQ(5, x); +} + +class SetErrnoAndReturnTest : public testing::Test { + protected: + virtual void SetUp() { errno = 0; } + virtual void TearDown() { errno = 0; } +}; + +TEST_F(SetErrnoAndReturnTest, Int) { + Action a = SetErrnoAndReturn(ENOTTY, -5); + EXPECT_EQ(-5, a.Perform(make_tuple())); + EXPECT_EQ(ENOTTY, errno); +} + +TEST_F(SetErrnoAndReturnTest, Ptr) { + int x; + Action a = SetErrnoAndReturn(ENOTTY, &x); + EXPECT_EQ(&x, a.Perform(make_tuple())); + EXPECT_EQ(ENOTTY, errno); +} + +TEST_F(SetErrnoAndReturnTest, CompatibleTypes) { + Action a = SetErrnoAndReturn(EINVAL, 5); + EXPECT_DOUBLE_EQ(5.0, a.Perform(make_tuple())); + EXPECT_EQ(EINVAL, errno); +} + +} // Unnamed namespace diff --git a/test/gmock-cardinalities_test.cc b/test/gmock-cardinalities_test.cc new file mode 100644 index 00000000..f3f1e106 --- /dev/null +++ b/test/gmock-cardinalities_test.cc @@ -0,0 +1,422 @@ +// 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 tests the built-in cardinalities. + +#include +#include +#include + +namespace { + +using std::stringstream; +using testing::AnyNumber; +using testing::AtLeast; +using testing::AtMost; +using testing::Between; +using testing::Cardinality; +using testing::CardinalityInterface; +using testing::Exactly; +using testing::IsSubstring; +using testing::MakeCardinality; + +class MockFoo { + public: + MOCK_METHOD0(Bar, int()); // NOLINT +}; + +// Tests that Cardinality objects can be default constructed. +TEST(CardinalityTest, IsDefaultConstructable) { + Cardinality c; +} + +// Tests that Cardinality objects are copyable. +TEST(CardinalityTest, IsCopyable) { + // Tests the copy constructor. + Cardinality c = Exactly(1); + EXPECT_FALSE(c.IsSatisfiedByCallCount(0)); + EXPECT_TRUE(c.IsSatisfiedByCallCount(1)); + EXPECT_TRUE(c.IsSaturatedByCallCount(1)); + + // Tests the assignment operator. + c = Exactly(2); + EXPECT_FALSE(c.IsSatisfiedByCallCount(1)); + EXPECT_TRUE(c.IsSatisfiedByCallCount(2)); + EXPECT_TRUE(c.IsSaturatedByCallCount(2)); +} + +TEST(CardinalityTest, IsOverSaturatedByCallCountWorks) { + const Cardinality c = AtMost(5); + EXPECT_FALSE(c.IsOverSaturatedByCallCount(4)); + EXPECT_FALSE(c.IsOverSaturatedByCallCount(5)); + EXPECT_TRUE(c.IsOverSaturatedByCallCount(6)); +} + +// Tests that Cardinality::DescribeActualCallCountTo() creates the +// correct description. +TEST(CardinalityTest, CanDescribeActualCallCount) { + stringstream ss0; + Cardinality::DescribeActualCallCountTo(0, &ss0); + EXPECT_EQ("never called", ss0.str()); + + stringstream ss1; + Cardinality::DescribeActualCallCountTo(1, &ss1); + EXPECT_EQ("called once", ss1.str()); + + stringstream ss2; + Cardinality::DescribeActualCallCountTo(2, &ss2); + EXPECT_EQ("called twice", ss2.str()); + + stringstream ss3; + Cardinality::DescribeActualCallCountTo(3, &ss3); + EXPECT_EQ("called 3 times", ss3.str()); +} + +// Tests AnyNumber() +TEST(AnyNumber, Works) { + const Cardinality c = AnyNumber(); + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_FALSE(c.IsSaturatedByCallCount(0)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(1)); + EXPECT_FALSE(c.IsSaturatedByCallCount(1)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(9)); + EXPECT_FALSE(c.IsSaturatedByCallCount(9)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "called any number of times", + ss.str()); +} + +TEST(AnyNumberTest, HasCorrectBounds) { + const Cardinality c = AnyNumber(); + EXPECT_EQ(0, c.ConservativeLowerBound()); + EXPECT_EQ(INT_MAX, c.ConservativeUpperBound()); +} + +// Tests AtLeast(n). + +TEST(AtLeastTest, OnNegativeNumber) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + AtLeast(-1); + }, "The invocation lower bound must be >= 0"); +} + +TEST(AtLeastTest, OnZero) { + const Cardinality c = AtLeast(0); + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_FALSE(c.IsSaturatedByCallCount(0)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(1)); + EXPECT_FALSE(c.IsSaturatedByCallCount(1)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "any number of times", + ss.str()); +} + +TEST(AtLeastTest, OnPositiveNumber) { + const Cardinality c = AtLeast(2); + EXPECT_FALSE(c.IsSatisfiedByCallCount(0)); + EXPECT_FALSE(c.IsSaturatedByCallCount(0)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(1)); + EXPECT_FALSE(c.IsSaturatedByCallCount(1)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(2)); + EXPECT_FALSE(c.IsSaturatedByCallCount(2)); + + stringstream ss1; + AtLeast(1).DescribeTo(&ss1); + EXPECT_PRED_FORMAT2(IsSubstring, "at least once", + ss1.str()); + + stringstream ss2; + c.DescribeTo(&ss2); + EXPECT_PRED_FORMAT2(IsSubstring, "at least twice", + ss2.str()); + + stringstream ss3; + AtLeast(3).DescribeTo(&ss3); + EXPECT_PRED_FORMAT2(IsSubstring, "at least 3 times", + ss3.str()); +} + +TEST(AtLeastTest, HasCorrectBounds) { + const Cardinality c = AtLeast(2); + EXPECT_EQ(2, c.ConservativeLowerBound()); + EXPECT_EQ(INT_MAX, c.ConservativeUpperBound()); +} + +// Tests AtMost(n). + +TEST(AtMostTest, OnNegativeNumber) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + AtMost(-1); + }, "The invocation upper bound must be >= 0"); +} + +TEST(AtMostTest, OnZero) { + const Cardinality c = AtMost(0); + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_TRUE(c.IsSaturatedByCallCount(0)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(1)); + EXPECT_TRUE(c.IsSaturatedByCallCount(1)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "never called", + ss.str()); +} + +TEST(AtMostTest, OnPositiveNumber) { + const Cardinality c = AtMost(2); + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_FALSE(c.IsSaturatedByCallCount(0)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(1)); + EXPECT_FALSE(c.IsSaturatedByCallCount(1)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(2)); + EXPECT_TRUE(c.IsSaturatedByCallCount(2)); + + stringstream ss1; + AtMost(1).DescribeTo(&ss1); + EXPECT_PRED_FORMAT2(IsSubstring, "called at most once", + ss1.str()); + + stringstream ss2; + c.DescribeTo(&ss2); + EXPECT_PRED_FORMAT2(IsSubstring, "called at most twice", + ss2.str()); + + stringstream ss3; + AtMost(3).DescribeTo(&ss3); + EXPECT_PRED_FORMAT2(IsSubstring, "called at most 3 times", + ss3.str()); +} + +TEST(AtMostTest, HasCorrectBounds) { + const Cardinality c = AtMost(2); + EXPECT_EQ(0, c.ConservativeLowerBound()); + EXPECT_EQ(2, c.ConservativeUpperBound()); +} + +// Tests Between(m, n). + +TEST(BetweenTest, OnNegativeStart) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + Between(-1, 2); + }, "The invocation lower bound must be >= 0, but is actually -1"); +} + +TEST(BetweenTest, OnNegativeEnd) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + Between(1, -2); + }, "The invocation upper bound must be >= 0, but is actually -2"); +} + +TEST(BetweenTest, OnStartBiggerThanEnd) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + Between(2, 1); + }, "The invocation upper bound (1) must be >= " + "the invocation lower bound (2)"); +} + +TEST(BetweenTest, OnZeroStartAndZeroEnd) { + const Cardinality c = Between(0, 0); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_TRUE(c.IsSaturatedByCallCount(0)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(1)); + EXPECT_TRUE(c.IsSaturatedByCallCount(1)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "never called", + ss.str()); +} + +TEST(BetweenTest, OnZeroStartAndNonZeroEnd) { + const Cardinality c = Between(0, 2); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_FALSE(c.IsSaturatedByCallCount(0)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(2)); + EXPECT_TRUE(c.IsSaturatedByCallCount(2)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(4)); + EXPECT_TRUE(c.IsSaturatedByCallCount(4)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "called at most twice", + ss.str()); +} + +TEST(BetweenTest, OnSameStartAndEnd) { + const Cardinality c = Between(3, 3); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(2)); + EXPECT_FALSE(c.IsSaturatedByCallCount(2)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(3)); + EXPECT_TRUE(c.IsSaturatedByCallCount(3)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(4)); + EXPECT_TRUE(c.IsSaturatedByCallCount(4)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "called 3 times", + ss.str()); +} + +TEST(BetweenTest, OnDifferentStartAndEnd) { + const Cardinality c = Between(3, 5); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(2)); + EXPECT_FALSE(c.IsSaturatedByCallCount(2)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(3)); + EXPECT_FALSE(c.IsSaturatedByCallCount(3)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(5)); + EXPECT_TRUE(c.IsSaturatedByCallCount(5)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(6)); + EXPECT_TRUE(c.IsSaturatedByCallCount(6)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "called between 3 and 5 times", + ss.str()); +} + +TEST(BetweenTest, HasCorrectBounds) { + const Cardinality c = Between(3, 5); + EXPECT_EQ(3, c.ConservativeLowerBound()); + EXPECT_EQ(5, c.ConservativeUpperBound()); +} + +// Tests Exactly(n). + +TEST(ExactlyTest, OnNegativeNumber) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + Exactly(-1); + }, "The invocation lower bound must be >= 0"); +} + +TEST(ExactlyTest, OnZero) { + const Cardinality c = Exactly(0); + EXPECT_TRUE(c.IsSatisfiedByCallCount(0)); + EXPECT_TRUE(c.IsSaturatedByCallCount(0)); + + EXPECT_FALSE(c.IsSatisfiedByCallCount(1)); + EXPECT_TRUE(c.IsSaturatedByCallCount(1)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_PRED_FORMAT2(IsSubstring, "never called", + ss.str()); +} + +TEST(ExactlyTest, OnPositiveNumber) { + const Cardinality c = Exactly(2); + EXPECT_FALSE(c.IsSatisfiedByCallCount(0)); + EXPECT_FALSE(c.IsSaturatedByCallCount(0)); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(2)); + EXPECT_TRUE(c.IsSaturatedByCallCount(2)); + + stringstream ss1; + Exactly(1).DescribeTo(&ss1); + EXPECT_PRED_FORMAT2(IsSubstring, "called once", + ss1.str()); + + stringstream ss2; + c.DescribeTo(&ss2); + EXPECT_PRED_FORMAT2(IsSubstring, "called twice", + ss2.str()); + + stringstream ss3; + Exactly(3).DescribeTo(&ss3); + EXPECT_PRED_FORMAT2(IsSubstring, "called 3 times", + ss3.str()); +} + +TEST(ExactlyTest, HasCorrectBounds) { + const Cardinality c = Exactly(3); + EXPECT_EQ(3, c.ConservativeLowerBound()); + EXPECT_EQ(3, c.ConservativeUpperBound()); +} + +// Tests that a user can make his own cardinality by implementing +// CardinalityInterface and calling MakeCardinality(). + +class EvenCardinality : public CardinalityInterface { + public: + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const { + return (call_count % 2 == 0); + } + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const { return false; } + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* ss) const { + *ss << "called even number of times"; + } +}; + +TEST(MakeCardinalityTest, ConstructsCardinalityFromInterface) { + const Cardinality c = MakeCardinality(new EvenCardinality); + + EXPECT_TRUE(c.IsSatisfiedByCallCount(2)); + EXPECT_FALSE(c.IsSatisfiedByCallCount(3)); + + EXPECT_FALSE(c.IsSaturatedByCallCount(10000)); + + stringstream ss; + c.DescribeTo(&ss); + EXPECT_EQ("called even number of times", ss.str()); +} + +} // Unnamed namespace diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc new file mode 100644 index 00000000..4f2e877a --- /dev/null +++ b/test/gmock-generated-actions_test.cc @@ -0,0 +1,946 @@ +// 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 tests the built-in actions generated by a script. + +#include + +#include +#include +#include +#include + +namespace testing { +namespace gmock_generated_actions_test { + +using ::std::plus; +using ::std::string; +using ::std::tr1::get; +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +using ::std::tr1::tuple_element; +using testing::_; +using testing::Action; +using testing::ActionInterface; +using testing::ByRef; +using testing::DoAll; +using testing::Invoke; +using testing::InvokeArgument; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Unused; +using testing::WithArg; +using testing::WithArgs; +using testing::WithoutArgs; + +// Sample functions and functors for testing Invoke() and etc. +int Nullary() { return 1; } + +class NullaryFunctor { + public: + int operator()() { return 2; } +}; + +bool g_done = false; +void VoidNullary() { g_done = true; } + +class VoidNullaryFunctor { + public: + void operator()() { g_done = true; } +}; + +bool Unary(int x) { return x < 0; } + +const char* Plus1(const char* s) { return s + 1; } + +void VoidUnary(int n) { g_done = true; } + +bool ByConstRef(const string& s) { return s == "Hi"; } + +const double g_double = 0; +bool ReferencesGlobalDouble(const double& x) { return &x == &g_double; } + +string ByNonConstRef(string& s) { return s += "+"; } // NOLINT + +struct UnaryFunctor { + int operator()(bool x) { return x ? 1 : -1; } +}; + +const char* Binary(const char* input, short n) { return input + n; } // NOLINT + +void VoidBinary(int, char) { g_done = true; } + +int Ternary(int x, char y, short z) { return x + y + z; } // NOLINT + +void VoidTernary(int, char, bool) { g_done = true; } + +int SumOf4(int a, int b, int c, int d) { return a + b + c + d; } + +int SumOfFirst2(int a, int b, Unused, Unused) { return a + b; } + +void VoidFunctionWithFourArguments(char, int, float, double) { g_done = true; } + +string Concat4(const char* s1, const char* s2, const char* s3, + const char* s4) { + return string(s1) + s2 + s3 + s4; +} + +int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } + +struct SumOf5Functor { + int operator()(int a, int b, int c, int d, int e) { + return a + b + c + d + e; + } +}; + +string Concat5(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5) { + return string(s1) + s2 + s3 + s4 + s5; +} + +int SumOf6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +struct SumOf6Functor { + int operator()(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; + } +}; + +string Concat6(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6) { + return string(s1) + s2 + s3 + s4 + s5 + s6; +} + +string Concat7(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7; +} + +string Concat8(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8; +} + +string Concat9(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; +} + +string Concat10(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9, + const char* s10) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; +} + +class Foo { + public: + Foo() : value_(123) {} + + int Nullary() const { return value_; } + + short Unary(long x) { return static_cast(value_ + x); } // NOLINT + + string Binary(const string& str, char c) const { return str + c; } + + int Ternary(int x, bool y, char z) { return value_ + x + y*z; } + + int SumOf4(int a, int b, int c, int d) const { + return a + b + c + d + value_; + } + + int SumOfLast2(Unused, Unused, int a, int b) const { return a + b; } + + int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } + + int SumOf6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; + } + + string Concat7(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7; + } + + string Concat8(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8; + } + + string Concat9(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; + } + + string Concat10(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9, + const char* s10) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; + } + private: + int value_; +}; + +// Tests using Invoke() with a nullary function. +TEST(InvokeTest, Nullary) { + Action a = Invoke(Nullary); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple())); +} + +// Tests using Invoke() with a unary function. +TEST(InvokeTest, Unary) { + Action a = Invoke(Unary); // NOLINT + EXPECT_FALSE(a.Perform(make_tuple(1))); + EXPECT_TRUE(a.Perform(make_tuple(-1))); +} + +// Tests using Invoke() with a binary function. +TEST(InvokeTest, Binary) { + Action a = Invoke(Binary); // NOLINT + const char* p = "Hello"; + EXPECT_EQ(p + 2, a.Perform(make_tuple(p, 2))); +} + +// Tests using Invoke() with a ternary function. +TEST(InvokeTest, Ternary) { + Action a = Invoke(Ternary); // NOLINT + EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', 3))); +} + +// Tests using Invoke() with a 4-argument function. +TEST(InvokeTest, FunctionThatTakes4Arguments) { + Action a = Invoke(SumOf4); // NOLINT + EXPECT_EQ(1234, a.Perform(make_tuple(1000, 200, 30, 4))); +} + +// Tests using Invoke() with a 5-argument function. +TEST(InvokeTest, FunctionThatTakes5Arguments) { + Action a = Invoke(SumOf5); // NOLINT + EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5))); +} + +// Tests using Invoke() with a 6-argument function. +TEST(InvokeTest, FunctionThatTakes6Arguments) { + Action a = Invoke(SumOf6); // NOLINT + EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); +} + +// Tests using Invoke() with a 7-argument function. +TEST(InvokeTest, FunctionThatTakes7Arguments) { + Action a = + Invoke(Concat7); + EXPECT_EQ("1234567", + a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7"))); +} + +// Tests using Invoke() with a 8-argument function. +TEST(InvokeTest, FunctionThatTakes8Arguments) { + Action a = + Invoke(Concat8); + EXPECT_EQ("12345678", + a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8"))); +} + +// Tests using Invoke() with a 9-argument function. +TEST(InvokeTest, FunctionThatTakes9Arguments) { + Action a = Invoke(Concat9); + EXPECT_EQ("123456789", + a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8", "9"))); +} + +// Tests using Invoke() with a 10-argument function. +TEST(InvokeTest, FunctionThatTakes10Arguments) { + Action a = Invoke(Concat10); + EXPECT_EQ("1234567890", a.Perform(make_tuple("1", "2", "3", "4", "5", "6", + "7", "8", "9", "0"))); +} + +// Tests using Invoke() with functions with parameters declared as Unused. +TEST(InvokeTest, FunctionWithUnusedParameters) { + Action a1 = + Invoke(SumOfFirst2); + EXPECT_EQ(12, a1.Perform(make_tuple(10, 2, 5.6, "hi"))); + + Action a2 = + Invoke(SumOfFirst2); + EXPECT_EQ(23, a2.Perform(make_tuple(20, 3, true, static_cast(NULL)))); +} + +// Tests using Invoke() with methods with parameters declared as Unused. +TEST(InvokeTest, MethodWithUnusedParameters) { + Foo foo; + Action a1 = + Invoke(&foo, &Foo::SumOfLast2); + EXPECT_EQ(12, a1.Perform(make_tuple("hi", true, 10, 2))); + + Action a2 = + Invoke(&foo, &Foo::SumOfLast2); + EXPECT_EQ(23, a2.Perform(make_tuple('a', 2.5, 20, 3))); +} + +// Tests using Invoke() with a functor. +TEST(InvokeTest, Functor) { + Action a = Invoke(plus()); // NOLINT + EXPECT_EQ(3, a.Perform(make_tuple(1, 2))); +} + +// Tests using Invoke(f) as an action of a compatible type. +TEST(InvokeTest, FunctionWithCompatibleType) { + Action a = Invoke(SumOf4); // NOLINT + EXPECT_EQ(4321, a.Perform(make_tuple(4000, 300, 20, true))); +} + +// Tests using Invoke() with an object pointer and a method pointer. + +// Tests using Invoke() with a nullary method. +TEST(InvokeMethodTest, Nullary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Nullary); // NOLINT + EXPECT_EQ(123, a.Perform(make_tuple())); +} + +// Tests using Invoke() with a unary method. +TEST(InvokeMethodTest, Unary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Unary); // NOLINT + EXPECT_EQ(4123, a.Perform(make_tuple(4000))); +} + +// Tests using Invoke() with a binary method. +TEST(InvokeMethodTest, Binary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Binary); + string s("Hell"); + EXPECT_EQ("Hello", a.Perform(make_tuple(s, 'o'))); +} + +// Tests using Invoke() with a ternary method. +TEST(InvokeMethodTest, Ternary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Ternary); // NOLINT + EXPECT_EQ(1124, a.Perform(make_tuple(1000, true, 1))); +} + +// Tests using Invoke() with a 4-argument method. +TEST(InvokeMethodTest, MethodThatTakes4Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::SumOf4); // NOLINT + EXPECT_EQ(1357, a.Perform(make_tuple(1000, 200, 30, 4))); +} + +// Tests using Invoke() with a 5-argument method. +TEST(InvokeMethodTest, MethodThatTakes5Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::SumOf5); // NOLINT + EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5))); +} + +// Tests using Invoke() with a 6-argument method. +TEST(InvokeMethodTest, MethodThatTakes6Arguments) { + Foo foo; + Action a = // NOLINT + Invoke(&foo, &Foo::SumOf6); + EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); +} + +// Tests using Invoke() with a 7-argument method. +TEST(InvokeMethodTest, MethodThatTakes7Arguments) { + Foo foo; + Action a = + Invoke(&foo, &Foo::Concat7); + EXPECT_EQ("1234567", + a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7"))); +} + +// Tests using Invoke() with a 8-argument method. +TEST(InvokeMethodTest, MethodThatTakes8Arguments) { + Foo foo; + Action a = + Invoke(&foo, &Foo::Concat8); + EXPECT_EQ("12345678", + a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8"))); +} + +// Tests using Invoke() with a 9-argument method. +TEST(InvokeMethodTest, MethodThatTakes9Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::Concat9); + EXPECT_EQ("123456789", + a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8", "9"))); +} + +// Tests using Invoke() with a 10-argument method. +TEST(InvokeMethodTest, MethodThatTakes10Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::Concat10); + EXPECT_EQ("1234567890", a.Perform(make_tuple("1", "2", "3", "4", "5", "6", + "7", "8", "9", "0"))); +} + +// Tests using Invoke(f) as an action of a compatible type. +TEST(InvokeMethodTest, MethodWithCompatibleType) { + Foo foo; + Action a = // NOLINT + Invoke(&foo, &Foo::SumOf4); + EXPECT_EQ(4444, a.Perform(make_tuple(4000, 300, 20, true))); +} + +// Tests ByRef(). + +// Tests that ReferenceWrapper is copyable. +TEST(ByRefTest, IsCopyable) { + const string s1 = "Hi"; + const string s2 = "Hello"; + + ::testing::internal::ReferenceWrapper ref_wrapper = ByRef(s1); + const string& r1 = ref_wrapper; + EXPECT_EQ(&s1, &r1); + + // Assigns a new value to ref_wrapper. + ref_wrapper = ByRef(s2); + const string& r2 = ref_wrapper; + EXPECT_EQ(&s2, &r2); + + ::testing::internal::ReferenceWrapper ref_wrapper1 = ByRef(s1); + // Copies ref_wrapper1 to ref_wrapper. + ref_wrapper = ref_wrapper1; + const string& r3 = ref_wrapper; + EXPECT_EQ(&s1, &r3); +} + +// Tests using ByRef() on a const value. +TEST(ByRefTest, ConstValue) { + const int n = 0; + // int& ref = ByRef(n); // This shouldn't compile - we have a + // negative compilation test to catch it. + const int& const_ref = ByRef(n); + EXPECT_EQ(&n, &const_ref); +} + +// Tests using ByRef() on a non-const value. +TEST(ByRefTest, NonConstValue) { + int n = 0; + + // ByRef(n) can be used as either an int&, + int& ref = ByRef(n); + EXPECT_EQ(&n, &ref); + + // or a const int&. + const int& const_ref = ByRef(n); + EXPECT_EQ(&n, &const_ref); +} + +struct Base { + bool operator==(const Base&) { return true; } +}; + +struct Derived : public Base { + bool operator==(const Derived&) { return true; } +}; + +// Tests explicitly specifying the type when using ByRef(). +TEST(ByRefTest, ExplicitType) { + int n = 0; + const int& r1 = ByRef(n); + EXPECT_EQ(&n, &r1); + + // ByRef(n); // This shouldn't compile - we have a negative + // compilation test to catch it. + + + Derived d; + Derived& r2 = ByRef(d); + EXPECT_EQ(&d, &r2); + + const Derived& r3 = ByRef(d); + EXPECT_EQ(&d, &r3); + + Base& r4 = ByRef(d); + EXPECT_EQ(&d, &r4); + + const Base& r5 = ByRef(d); + EXPECT_EQ(&d, &r5); + + // The following shouldn't compile - we have a negative compilation + // test for it. + // + // Base b; + // ByRef(b); +} + +// Tests InvokeArgument(...). + +// Tests using InvokeArgument with a nullary function. +TEST(InvokeArgumentTest, Function0) { + Action a = InvokeArgument<1>(); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple(2, &Nullary))); +} + +// Tests using InvokeArgument with a unary function. +TEST(InvokeArgumentTest, Functor1) { + Action a = InvokeArgument<0>(true); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple(UnaryFunctor()))); +} + +// Tests using InvokeArgument with a 5-ary function. +TEST(InvokeArgumentTest, Function5) { + Action a = // NOLINT + InvokeArgument<0>(10000, 2000, 300, 40, 5); + EXPECT_EQ(12345, a.Perform(make_tuple(&SumOf5))); +} + +// Tests using InvokeArgument with a 5-ary functor. +TEST(InvokeArgumentTest, Functor5) { + Action a = // NOLINT + InvokeArgument<0>(10000, 2000, 300, 40, 5); + EXPECT_EQ(12345, a.Perform(make_tuple(SumOf5Functor()))); +} + +// Tests using InvokeArgument with a 6-ary function. +TEST(InvokeArgumentTest, Function6) { + Action a = // NOLINT + InvokeArgument<0>(100000, 20000, 3000, 400, 50, 6); + EXPECT_EQ(123456, a.Perform(make_tuple(&SumOf6))); +} + +// Tests using InvokeArgument with a 6-ary functor. +TEST(InvokeArgumentTest, Functor6) { + Action a = // NOLINT + InvokeArgument<0>(100000, 20000, 3000, 400, 50, 6); + EXPECT_EQ(123456, a.Perform(make_tuple(SumOf6Functor()))); +} + +// Tests using InvokeArgument with a 7-ary function. +TEST(InvokeArgumentTest, Function7) { + Action a = + InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7"); + EXPECT_EQ("1234567", a.Perform(make_tuple(&Concat7))); +} + +// Tests using InvokeArgument with a 8-ary function. +TEST(InvokeArgumentTest, Function8) { + Action a = + InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8"); + EXPECT_EQ("12345678", a.Perform(make_tuple(&Concat8))); +} + +// Tests using InvokeArgument with a 9-ary function. +TEST(InvokeArgumentTest, Function9) { + Action a = + InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9"); + EXPECT_EQ("123456789", a.Perform(make_tuple(&Concat9))); +} + +// Tests using InvokeArgument with a 10-ary function. +TEST(InvokeArgumentTest, Function10) { + Action a = + InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9", "0"); + EXPECT_EQ("1234567890", a.Perform(make_tuple(&Concat10))); +} + +// Tests using InvokeArgument with a function that takes a pointer argument. +TEST(InvokeArgumentTest, ByPointerFunction) { + Action a = // NOLINT + InvokeArgument<0>(static_cast("Hi"), 1); + EXPECT_STREQ("i", a.Perform(make_tuple(&Binary))); +} + +// Tests using InvokeArgument with a function that takes a const char* +// by passing it a C-string literal. +TEST(InvokeArgumentTest, FunctionWithCStringLiteral) { + Action a = // NOLINT + InvokeArgument<0>("Hi", 1); + EXPECT_STREQ("i", a.Perform(make_tuple(&Binary))); +} + +// Tests using InvokeArgument with a function that takes a const reference. +TEST(InvokeArgumentTest, ByConstReferenceFunction) { + Action a = // NOLINT + InvokeArgument<0>(string("Hi")); + // When action 'a' is constructed, it makes a copy of the temporary + // string object passed to it, so it's OK to use 'a' later, when the + // temporary object has already died. + EXPECT_TRUE(a.Perform(make_tuple(&ByConstRef))); +} + +// Tests using InvokeArgument with ByRef() and a function that takes a +// const reference. +TEST(InvokeArgumentTest, ByExplicitConstReferenceFunction) { + Action a = // NOLINT + InvokeArgument<0>(ByRef(g_double)); + // The above line calls ByRef() on a const value. + EXPECT_TRUE(a.Perform(make_tuple(&ReferencesGlobalDouble))); + + double x = 0; + a = InvokeArgument<0>(ByRef(x)); // This calls ByRef() on a non-const. + EXPECT_FALSE(a.Perform(make_tuple(&ReferencesGlobalDouble))); +} + +// Tests using WithoutArgs with an action that takes no argument. +TEST(WithoutArgsTest, NoArg) { + Action a = WithoutArgs(Invoke(Nullary)); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple(2))); +} + +// Tests using WithArgs and WithArg with an action that takes 1 argument. +TEST(WithArgsTest, OneArg) { + Action a = WithArgs<1>(Invoke(Unary)); // NOLINT + EXPECT_TRUE(a.Perform(make_tuple(1.5, -1))); + EXPECT_FALSE(a.Perform(make_tuple(1.5, 1))); + + // Also tests the synonym WithArg. + Action b = WithArg<1>(Invoke(Unary)); // NOLINT + EXPECT_TRUE(a.Perform(make_tuple(1.5, -1))); + EXPECT_FALSE(a.Perform(make_tuple(1.5, 1))); + +} + +// Tests using WithArgs with an action that takes 2 arguments. +TEST(WithArgsTest, TwoArgs) { + Action a = + WithArgs<0, 2>(Invoke(Binary)); + const char s[] = "Hello"; + EXPECT_EQ(s + 2, a.Perform(make_tuple(s, 0.5, 2))); +} + +// Tests using WithArgs with an action that takes 3 arguments. +TEST(WithArgsTest, ThreeArgs) { + Action a = // NOLINT + WithArgs<0, 2, 3>(Invoke(Ternary)); + EXPECT_EQ(123, a.Perform(make_tuple(100, 6.5, 20, 3))); +} + +// Tests using WithArgs with an action that takes 4 arguments. +TEST(WithArgsTest, FourArgs) { + Action a = + WithArgs<4, 3, 1, 0>(Invoke(Concat4)); + EXPECT_EQ("4310", a.Perform(make_tuple("0", "1", 2.5, "3", "4"))); +} + +// Tests using WithArgs with an action that takes 5 arguments. +TEST(WithArgsTest, FiveArgs) { + Action a = + WithArgs<4, 3, 2, 1, 0>(Invoke(Concat5)); + EXPECT_EQ("43210", a.Perform(make_tuple("0", "1", "2", "3", "4"))); +} + +// Tests using WithArgs with an action that takes 6 arguments. +TEST(WithArgsTest, SixArgs) { + Action a = + WithArgs<0, 1, 2, 2, 1, 0>(Invoke(Concat6)); + EXPECT_EQ("012210", a.Perform(make_tuple("0", "1", "2"))); +} + +// Tests using WithArgs with an action that takes 7 arguments. +TEST(WithArgsTest, SevenArgs) { + Action a = + WithArgs<0, 1, 2, 3, 2, 1, 0>(Invoke(Concat7)); + EXPECT_EQ("0123210", a.Perform(make_tuple("0", "1", "2", "3"))); +} + +// Tests using WithArgs with an action that takes 8 arguments. +TEST(WithArgsTest, EightArgs) { + Action a = + WithArgs<0, 1, 2, 3, 0, 1, 2, 3>(Invoke(Concat8)); + EXPECT_EQ("01230123", a.Perform(make_tuple("0", "1", "2", "3"))); +} + +// Tests using WithArgs with an action that takes 9 arguments. +TEST(WithArgsTest, NineArgs) { + Action a = + WithArgs<0, 1, 2, 3, 1, 2, 3, 2, 3>(Invoke(Concat9)); + EXPECT_EQ("012312323", a.Perform(make_tuple("0", "1", "2", "3"))); +} + +// Tests using WithArgs with an action that takes 10 arguments. +TEST(WithArgsTest, TenArgs) { + Action a = + WithArgs<0, 1, 2, 3, 2, 1, 0, 1, 2, 3>(Invoke(Concat10)); + EXPECT_EQ("0123210123", a.Perform(make_tuple("0", "1", "2", "3"))); +} + +// Tests using WithArgs with an action that is not Invoke(). +class SubstractAction : public ActionInterface { // NOLINT + public: + virtual int Perform(const tuple& args) { + return get<0>(args) - get<1>(args); + } +}; + +TEST(WithArgsTest, NonInvokeAction) { + Action a = // NOLINT + WithArgs<2, 1>(MakeAction(new SubstractAction)); + EXPECT_EQ(8, a.Perform(make_tuple("hi", 2, 10))); +} + +// Tests using WithArgs to pass all original arguments in the original order. +TEST(WithArgsTest, Identity) { + Action a = // NOLINT + WithArgs<0, 1, 2>(Invoke(Ternary)); + EXPECT_EQ(123, a.Perform(make_tuple(100, 20, 3))); +} + +// Tests using WithArgs with repeated arguments. +TEST(WithArgsTest, RepeatedArguments) { + Action a = // NOLINT + WithArgs<1, 1, 1, 1>(Invoke(SumOf4)); + EXPECT_EQ(4, a.Perform(make_tuple(false, 1, 10))); +} + +// Tests using WithArgs with reversed argument order. +TEST(WithArgsTest, ReversedArgumentOrder) { + Action a = // NOLINT + WithArgs<1, 0>(Invoke(Binary)); + const char s[] = "Hello"; + EXPECT_EQ(s + 2, a.Perform(make_tuple(2, s))); +} + +// Tests using WithArgs with compatible, but not identical, argument types. +TEST(WithArgsTest, ArgsOfCompatibleTypes) { + Action a = // NOLINT + WithArgs<0, 1, 3>(Invoke(Ternary)); + EXPECT_EQ(123, a.Perform(make_tuple(100, 20, 5.6, 3))); +} + +// Tests using WithArgs with an action that returns void. +TEST(WithArgsTest, VoidAction) { + Action a = WithArgs<2, 1>(Invoke(VoidBinary)); + g_done = false; + a.Perform(make_tuple(1.5, 'a', 3)); + EXPECT_TRUE(g_done); +} + +// Tests DoAll(a1, a2). +TEST(DoAllTest, TwoActions) { + int n = 0; + Action a = DoAll(SetArgumentPointee<0>(1), // NOLINT + Return(2)); + EXPECT_EQ(2, a.Perform(make_tuple(&n))); + EXPECT_EQ(1, n); +} + +// Tests DoAll(a1, a2, a3). +TEST(DoAllTest, ThreeActions) { + int m = 0, n = 0; + Action a = DoAll(SetArgumentPointee<0>(1), // NOLINT + SetArgumentPointee<1>(2), + Return(3)); + EXPECT_EQ(3, a.Perform(make_tuple(&m, &n))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); +} + +// Tests DoAll(a1, a2, a3, a4). +TEST(DoAllTest, FourActions) { + int m = 0, n = 0; + char ch = '\0'; + Action a = // NOLINT + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + Return(3)); + EXPECT_EQ(3, a.Perform(make_tuple(&m, &n, &ch))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', ch); +} + +// Tests DoAll(a1, a2, a3, a4, a5). +TEST(DoAllTest, FiveActions) { + int m = 0, n = 0; + char a = '\0', b = '\0'; + Action action = // NOLINT + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + SetArgumentPointee<3>('b'), + Return(3)); + EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', a); + EXPECT_EQ('b', b); +} + +// Tests DoAll(a1, a2, ..., a6). +TEST(DoAllTest, SixActions) { + int m = 0, n = 0; + char a = '\0', b = '\0', c = '\0'; + Action action = // NOLINT + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + SetArgumentPointee<3>('b'), + SetArgumentPointee<4>('c'), + Return(3)); + EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', a); + EXPECT_EQ('b', b); + EXPECT_EQ('c', c); +} + +// Tests DoAll(a1, a2, ..., a7). +TEST(DoAllTest, SevenActions) { + int m = 0, n = 0; + char a = '\0', b = '\0', c = '\0', d = '\0'; + Action action = // NOLINT + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + SetArgumentPointee<3>('b'), + SetArgumentPointee<4>('c'), + SetArgumentPointee<5>('d'), + Return(3)); + EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', a); + EXPECT_EQ('b', b); + EXPECT_EQ('c', c); + EXPECT_EQ('d', d); +} + +// Tests DoAll(a1, a2, ..., a8). +TEST(DoAllTest, EightActions) { + int m = 0, n = 0; + char a = '\0', b = '\0', c = '\0', d = '\0', e = '\0'; + Action action = + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + SetArgumentPointee<3>('b'), + SetArgumentPointee<4>('c'), + SetArgumentPointee<5>('d'), + SetArgumentPointee<6>('e'), + Return(3)); + EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d, &e))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', a); + EXPECT_EQ('b', b); + EXPECT_EQ('c', c); + EXPECT_EQ('d', d); + EXPECT_EQ('e', e); +} + +// Tests DoAll(a1, a2, ..., a9). +TEST(DoAllTest, NineActions) { + int m = 0, n = 0; + char a = '\0', b = '\0', c = '\0', d = '\0', e = '\0', f = '\0'; + Action action = + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + SetArgumentPointee<3>('b'), + SetArgumentPointee<4>('c'), + SetArgumentPointee<5>('d'), + SetArgumentPointee<6>('e'), + SetArgumentPointee<7>('f'), + Return(3)); + EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d, &e, &f))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', a); + EXPECT_EQ('b', b); + EXPECT_EQ('c', c); + EXPECT_EQ('d', d); + EXPECT_EQ('e', e); + EXPECT_EQ('f', f); +} + +// Tests DoAll(a1, a2, ..., a10). +TEST(DoAllTest, TenActions) { + int m = 0, n = 0; + char a = '\0', b = '\0', c = '\0', d = '\0'; + char e = '\0', f = '\0', g = '\0'; + Action action = + DoAll(SetArgumentPointee<0>(1), + SetArgumentPointee<1>(2), + SetArgumentPointee<2>('a'), + SetArgumentPointee<3>('b'), + SetArgumentPointee<4>('c'), + SetArgumentPointee<5>('d'), + SetArgumentPointee<6>('e'), + SetArgumentPointee<7>('f'), + SetArgumentPointee<8>('g'), + Return(3)); + EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d, &e, &f, &g))); + EXPECT_EQ(1, m); + EXPECT_EQ(2, n); + EXPECT_EQ('a', a); + EXPECT_EQ('b', b); + EXPECT_EQ('c', c); + EXPECT_EQ('d', d); + EXPECT_EQ('e', e); + EXPECT_EQ('f', f); + EXPECT_EQ('g', g); +} + +} // namespace gmock_generated_actions_test +} // namespace testing diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc new file mode 100644 index 00000000..d8e678b2 --- /dev/null +++ b/test/gmock-generated-function-mockers_test.cc @@ -0,0 +1,426 @@ +// 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 tests the function mocker classes. + +#include + +#include +#include +#include +#include + +#ifdef GTEST_OS_WINDOWS +// MSDN says the header file to be included for STDMETHOD is BaseTyps.h but +// we are getting compiler errors if we use basetyps.h, hence including +// objbase.h for definition of STDMETHOD. +#include +#endif // GTEST_OS_WINDOWS + +// There is a bug in MSVC (fixed in VS 2008) that prevents creating a +// mock for a function with const arguments, so we don't test such +// cases for MSVC versions older than 2008. +#if !defined(GTEST_OS_WINDOWS) || (_MSC_VER >= 1500) +#define GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS +#endif // !defined(GTEST_OS_WINDOWS) || (_MSC_VER >= 1500) + +namespace testing { +namespace gmock_generated_function_mockers_test { + +using testing::internal::string; +using testing::_; +using testing::A; +using testing::An; +using testing::AnyNumber; +using testing::Const; +using testing::DoDefault; +using testing::Eq; +using testing::Lt; +using testing::Ref; +using testing::Return; +using testing::ReturnRef; +using testing::TypedEq; + +class FooInterface { + public: + virtual ~FooInterface() {} + + virtual void VoidReturning(int x) = 0; + + virtual int Nullary() = 0; + virtual bool Unary(int x) = 0; + virtual long Binary(short x, int y) = 0; // NOLINT + virtual int Decimal(bool b, char c, short d, int e, long f, // NOLINT + float g, double h, unsigned i, char* j, const string& k) + = 0; + + virtual bool TakesNonConstReference(int& n) = 0; // NOLINT + virtual string TakesConstReference(const int& n) = 0; +#ifdef GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS + virtual bool TakesConst(const int x) = 0; +#endif // GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS + + virtual int OverloadedOnArgumentNumber() = 0; + virtual int OverloadedOnArgumentNumber(int n) = 0; + + virtual int OverloadedOnArgumentType(int n) = 0; + virtual char OverloadedOnArgumentType(char c) = 0; + + virtual int OverloadedOnConstness() = 0; + virtual char OverloadedOnConstness() const = 0; + + virtual int TypeWithHole(int (*func)()) = 0; + virtual int TypeWithComma(const std::map& a_map) = 0; + +#ifdef GTEST_OS_WINDOWS + STDMETHOD_(int, CTNullary)() = 0; + STDMETHOD_(bool, CTUnary)(int x) = 0; + STDMETHOD_(int, CTDecimal)(bool b, char c, short d, int e, long f, // NOLINT + float g, double h, unsigned i, char* j, const string& k) = 0; + STDMETHOD_(char, CTConst)(int x) const = 0; +#endif // GTEST_OS_WINDOWS +}; + +class MockFoo : public FooInterface { + public: + // Makes sure that a mock function parameter can be named. + MOCK_METHOD1(VoidReturning, void(int n)); // NOLINT + + MOCK_METHOD0(Nullary, int()); // NOLINT + + // Makes sure that a mock function parameter can be unnamed. + MOCK_METHOD1(Unary, bool(int)); // NOLINT + MOCK_METHOD2(Binary, long(short, int)); // NOLINT + MOCK_METHOD10(Decimal, int(bool, char, short, int, long, float, // NOLINT + double, unsigned, char*, const string& str)); + + MOCK_METHOD1(TakesNonConstReference, bool(int&)); // NOLINT + MOCK_METHOD1(TakesConstReference, string(const int&)); +#ifdef GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS + MOCK_METHOD1(TakesConst, bool(const int)); // NOLINT +#endif // GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS + MOCK_METHOD0(OverloadedOnArgumentNumber, int()); // NOLINT + MOCK_METHOD1(OverloadedOnArgumentNumber, int(int)); // NOLINT + + MOCK_METHOD1(OverloadedOnArgumentType, int(int)); // NOLINT + MOCK_METHOD1(OverloadedOnArgumentType, char(char)); // NOLINT + + MOCK_METHOD0(OverloadedOnConstness, int()); // NOLINT + MOCK_CONST_METHOD0(OverloadedOnConstness, char()); // NOLINT + + MOCK_METHOD1(TypeWithHole, int(int (*)())); // NOLINT + MOCK_METHOD1(TypeWithComma, int(const std::map&)); // NOLINT +#ifdef GTEST_OS_WINDOWS + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, CTNullary, int()); + MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, CTUnary, bool(int)); + MOCK_METHOD10_WITH_CALLTYPE(STDMETHODCALLTYPE, CTDecimal, int(bool b, char c, + short d, int e, long f, float g, double h, unsigned i, char* j, + const string& k)); + MOCK_CONST_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, CTConst, char(int)); +#endif // GTEST_OS_WINDOWS +}; + +class FunctionMockerTest : public testing::Test { + protected: + FunctionMockerTest() : foo_(&mock_foo_) {} + + FooInterface* const foo_; + MockFoo mock_foo_; +}; + +// Tests mocking a void-returning function. +TEST_F(FunctionMockerTest, MocksVoidFunction) { + EXPECT_CALL(mock_foo_, VoidReturning(Lt(100))); + foo_->VoidReturning(0); +} + +// Tests mocking a nullary function. +TEST_F(FunctionMockerTest, MocksNullaryFunction) { + EXPECT_CALL(mock_foo_, Nullary()) + .WillOnce(DoDefault()) + .WillOnce(Return(1)); + + EXPECT_EQ(0, foo_->Nullary()); + EXPECT_EQ(1, foo_->Nullary()); +} + +// Tests mocking a unary function. +TEST_F(FunctionMockerTest, MocksUnaryFunction) { + EXPECT_CALL(mock_foo_, Unary(Eq(2))) + .Times(2) + .WillOnce(Return(true)); + + EXPECT_TRUE(foo_->Unary(2)); + EXPECT_FALSE(foo_->Unary(2)); +} + +// Tests mocking a binary function. +TEST_F(FunctionMockerTest, MocksBinaryFunction) { + EXPECT_CALL(mock_foo_, Binary(2, _)) + .WillOnce(Return(3)); + + EXPECT_EQ(3, foo_->Binary(2, 1)); +} + +// Tests mocking a decimal function. +TEST_F(FunctionMockerTest, MocksDecimalFunction) { + EXPECT_CALL(mock_foo_, Decimal(true, 'a', 0, 0, 1L, A(), + Lt(100), 5U, NULL, "hi")) + .WillOnce(Return(5)); + + EXPECT_EQ(5, foo_->Decimal(true, 'a', 0, 0, 1, 0, 0, 5, NULL, "hi")); +} + +// Tests mocking a function that takes a non-const reference. +TEST_F(FunctionMockerTest, MocksFunctionWithNonConstReferenceArgument) { + int a = 0; + EXPECT_CALL(mock_foo_, TakesNonConstReference(Ref(a))) + .WillOnce(Return(true)); + + EXPECT_TRUE(foo_->TakesNonConstReference(a)); +} + +// Tests mocking a function that takes a const reference. +TEST_F(FunctionMockerTest, MocksFunctionWithConstReferenceArgument) { + int a = 0; + EXPECT_CALL(mock_foo_, TakesConstReference(Ref(a))) + .WillOnce(Return("Hello")); + + EXPECT_EQ("Hello", foo_->TakesConstReference(a)); +} + +#ifdef GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS +// Tests mocking a function that takes a const variable. +TEST_F(FunctionMockerTest, MocksFunctionWithConstArgument) { + EXPECT_CALL(mock_foo_, TakesConst(Lt(10))) + .WillOnce(DoDefault()); + + EXPECT_FALSE(foo_->TakesConst(5)); +} +#endif // GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS + +// Tests mocking functions overloaded on the number of arguments. +TEST_F(FunctionMockerTest, MocksFunctionsOverloadedOnArgumentNumber) { + EXPECT_CALL(mock_foo_, OverloadedOnArgumentNumber()) + .WillOnce(Return(1)); + EXPECT_CALL(mock_foo_, OverloadedOnArgumentNumber(_)) + .WillOnce(Return(2)); + + EXPECT_EQ(2, foo_->OverloadedOnArgumentNumber(1)); + EXPECT_EQ(1, foo_->OverloadedOnArgumentNumber()); +} + +// Tests mocking functions overloaded on the types of argument. +TEST_F(FunctionMockerTest, MocksFunctionsOverloadedOnArgumentType) { + EXPECT_CALL(mock_foo_, OverloadedOnArgumentType(An())) + .WillOnce(Return(1)); + EXPECT_CALL(mock_foo_, OverloadedOnArgumentType(TypedEq('a'))) + .WillOnce(Return('b')); + + EXPECT_EQ(1, foo_->OverloadedOnArgumentType(0)); + EXPECT_EQ('b', foo_->OverloadedOnArgumentType('a')); +} + +// Tests mocking functions overloaded on the const-ness of this object. +TEST_F(FunctionMockerTest, MocksFunctionsOverloadedOnConstnessOfThis) { + EXPECT_CALL(mock_foo_, OverloadedOnConstness()); + EXPECT_CALL(Const(mock_foo_), OverloadedOnConstness()) + .WillOnce(Return('a')); + + EXPECT_EQ(0, foo_->OverloadedOnConstness()); + EXPECT_EQ('a', Const(*foo_).OverloadedOnConstness()); +} + +#ifdef GTEST_OS_WINDOWS +// Tests mocking a nullary function with calltype. +TEST_F(FunctionMockerTest, MocksNullaryFunctionWithCallType) { + EXPECT_CALL(mock_foo_, CTNullary()) + .WillOnce(Return(-1)) + .WillOnce(Return(0)); + + EXPECT_EQ(-1, foo_->CTNullary()); + EXPECT_EQ(0, foo_->CTNullary()); +} + +// Tests mocking a unary function with calltype. +TEST_F(FunctionMockerTest, MocksUnaryFunctionWithCallType) { + EXPECT_CALL(mock_foo_, CTUnary(Eq(2))) + .Times(2) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + + EXPECT_TRUE(foo_->CTUnary(2)); + EXPECT_FALSE(foo_->CTUnary(2)); +} + +// Tests mocking a decimal function with calltype. +TEST_F(FunctionMockerTest, MocksDecimalFunctionWithCallType) { + EXPECT_CALL(mock_foo_, CTDecimal(true, 'a', 0, 0, 1L, A(), + Lt(100), 5U, NULL, "hi")) + .WillOnce(Return(10)); + + EXPECT_EQ(10, foo_->CTDecimal(true, 'a', 0, 0, 1, 0, 0, 5, NULL, "hi")); +} + +// Tests mocking functions overloaded on the const-ness of this object. +TEST_F(FunctionMockerTest, MocksFunctionsConstFunctionWithCallType) { + EXPECT_CALL(Const(mock_foo_), CTConst(_)) + .WillOnce(Return('a')); + + EXPECT_EQ('a', Const(*foo_).CTConst(0)); +} + +#endif // GTEST_OS_WINDOWS + +class MockB { + public: + MOCK_METHOD0(DoB, void()); +}; + +// Tests that functions with no EXPECT_CALL() ruls can be called any +// number of times. +TEST(ExpectCallTest, UnmentionedFunctionCanBeCalledAnyNumberOfTimes) { + { + MockB b; + } + + { + MockB b; + b.DoB(); + } + + { + MockB b; + b.DoB(); + b.DoB(); + } +} + +// Tests mocking template interfaces. + +template +class StackInterface { + public: + virtual ~StackInterface() {} + + // Template parameter appears in function parameter. + virtual void Push(const T& value) = 0; + virtual void Pop() = 0; + virtual int GetSize() const = 0; + // Template parameter appears in function return type. + virtual const T& GetTop() const = 0; +}; + +template +class MockStack : public StackInterface { + public: + MOCK_METHOD1_T(Push, void(const T& elem)); + MOCK_METHOD0_T(Pop, void()); + MOCK_CONST_METHOD0_T(GetSize, int()); // NOLINT + MOCK_CONST_METHOD0_T(GetTop, const T&()); +}; + +// Tests that template mock works. +TEST(TemplateMockTest, Works) { + MockStack mock; + + EXPECT_CALL(mock, GetSize()) + .WillOnce(Return(0)) + .WillOnce(Return(1)) + .WillOnce(Return(0)); + EXPECT_CALL(mock, Push(_)); + int n = 5; + EXPECT_CALL(mock, GetTop()) + .WillOnce(ReturnRef(n)); + EXPECT_CALL(mock, Pop()) + .Times(AnyNumber()); + + EXPECT_EQ(0, mock.GetSize()); + mock.Push(5); + EXPECT_EQ(1, mock.GetSize()); + EXPECT_EQ(5, mock.GetTop()); + mock.Pop(); + EXPECT_EQ(0, mock.GetSize()); +} + +#ifdef GTEST_OS_WINDOWS +// Tests mocking template interfaces with calltype. + +template +class StackInterfaceWithCallType { + public: + virtual ~StackInterfaceWithCallType() {} + + // Template parameter appears in function parameter. + STDMETHOD_(void, Push)(const T& value) = 0; + STDMETHOD_(void, Pop)() = 0; + STDMETHOD_(int, GetSize)() const = 0; + // Template parameter appears in function return type. + STDMETHOD_(const T&, GetTop)() const = 0; +}; + +template +class MockStackWithCallType : public StackInterfaceWithCallType { + public: + MOCK_METHOD1_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Push, void(const T& elem)); + MOCK_METHOD0_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Pop, void()); + MOCK_CONST_METHOD0_T_WITH_CALLTYPE(STDMETHODCALLTYPE, GetSize, int()); + MOCK_CONST_METHOD0_T_WITH_CALLTYPE(STDMETHODCALLTYPE, GetTop, const T&()); +}; + +// Tests that template mock with calltype works. +TEST(TemplateMockTestWithCallType, Works) { + MockStackWithCallType mock; + + EXPECT_CALL(mock, GetSize()) + .WillOnce(Return(0)) + .WillOnce(Return(1)) + .WillOnce(Return(0)); + EXPECT_CALL(mock, Push(_)); + int n = 5; + EXPECT_CALL(mock, GetTop()) + .WillOnce(ReturnRef(n)); + EXPECT_CALL(mock, Pop()) + .Times(AnyNumber()); + + EXPECT_EQ(0, mock.GetSize()); + mock.Push(5); + EXPECT_EQ(1, mock.GetSize()); + EXPECT_EQ(5, mock.GetTop()); + mock.Pop(); + EXPECT_EQ(0, mock.GetSize()); +} +#endif // GTEST_OS_WINDOWS + +} // namespace gmock_generated_function_mockers_test +} // namespace testing diff --git a/test/gmock-generated-internal-utils_test.cc b/test/gmock-generated-internal-utils_test.cc new file mode 100644 index 00000000..13b4c5cf --- /dev/null +++ b/test/gmock-generated-internal-utils_test.cc @@ -0,0 +1,127 @@ +// 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 tests the internal utilities. + +#include +#include +#include + +namespace { + +using ::std::tr1::tuple; +using ::testing::Matcher; +using ::testing::internal::CompileAssertTypesEqual; +using ::testing::internal::MatcherTuple; +using ::testing::internal::Function; +using ::testing::internal::IgnoredValue; + +// Tests the MatcherTuple template struct. + +TEST(MatcherTupleTest, ForSize0) { + CompileAssertTypesEqual, MatcherTuple >::type>(); +} + +TEST(MatcherTupleTest, ForSize1) { + CompileAssertTypesEqual >, + MatcherTuple >::type>(); +} + +TEST(MatcherTupleTest, ForSize2) { + CompileAssertTypesEqual, Matcher >, + MatcherTuple >::type>(); +} + +TEST(MatcherTupleTest, ForSize5) { + CompileAssertTypesEqual, Matcher, Matcher, + Matcher, Matcher >, + MatcherTuple + >::type>(); +} + +// Tests the Function template struct. + +TEST(FunctionTest, Nullary) { + typedef Function F; // NOLINT + CompileAssertTypesEqual(); + CompileAssertTypesEqual, F::ArgumentTuple>(); + CompileAssertTypesEqual, F::ArgumentMatcherTuple>(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); +} + +TEST(FunctionTest, Unary) { + typedef Function F; // NOLINT + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual, F::ArgumentTuple>(); + CompileAssertTypesEqual >, F::ArgumentMatcherTuple>(); + CompileAssertTypesEqual(); // NOLINT + CompileAssertTypesEqual(); +} + +TEST(FunctionTest, Binary) { + typedef Function F; // NOLINT + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); // NOLINT + CompileAssertTypesEqual, F::ArgumentTuple>(); // NOLINT + CompileAssertTypesEqual, Matcher >, // NOLINT + F::ArgumentMatcherTuple>(); + CompileAssertTypesEqual(); // NOLINT + CompileAssertTypesEqual(); +} + +TEST(FunctionTest, LongArgumentList) { + typedef Function F; // NOLINT + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); // NOLINT + CompileAssertTypesEqual, // NOLINT + F::ArgumentTuple>(); + CompileAssertTypesEqual, Matcher, Matcher, + Matcher, Matcher >, // NOLINT + F::ArgumentMatcherTuple>(); + CompileAssertTypesEqual(); + CompileAssertTypesEqual< + IgnoredValue(bool, int, char*, int&, const long&), // NOLINT + F::MakeResultIgnoredValue>(); +} + +} // Unnamed namespace diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc new file mode 100644 index 00000000..89b26caa --- /dev/null +++ b/test/gmock-generated-matchers_test.cc @@ -0,0 +1,373 @@ +// 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 tests the built-in matchers generated by a script. + +#include + +#include +#include +#include +#include + +#include +#include + +namespace { + +using std::list; +using std::stringstream; +using std::vector; +using testing::_; +using testing::ElementsAre; +using testing::ElementsAreArray; +using testing::Eq; +using testing::Ge; +using testing::Gt; +using testing::MakeMatcher; +using testing::Matcher; +using testing::MatcherInterface; +using testing::Ne; +using testing::Not; +using testing::Pointee; +using testing::Ref; +using testing::StrEq; +using testing::internal::string; + +// Returns the description of the given matcher. +template +string Describe(const Matcher& m) { + stringstream ss; + m.DescribeTo(&ss); + return ss.str(); +} + +// Returns the description of the negation of the given matcher. +template +string DescribeNegation(const Matcher& m) { + stringstream ss; + m.DescribeNegationTo(&ss); + return ss.str(); +} + +// Returns the reason why x matches, or doesn't match, m. +template +string Explain(const MatcherType& m, const Value& x) { + stringstream ss; + m.ExplainMatchResultTo(x, &ss); + return ss.str(); +} + +// For testing ExplainMatchResultTo(). +class GreaterThanMatcher : public MatcherInterface { + public: + explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} + + virtual bool Matches(int lhs) const { return lhs > rhs_; } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is greater than " << rhs_; + } + + virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { + const int diff = lhs - rhs_; + if (diff > 0) { + *os << "is " << diff << " more than " << rhs_; + } else if (diff == 0) { + *os << "is the same as " << rhs_; + } else { + *os << "is " << -diff << " less than " << rhs_; + } + } + private: + const int rhs_; +}; + +Matcher GreaterThan(int n) { + return MakeMatcher(new GreaterThanMatcher(n)); +} + +// Tests for ElementsAre(). + +// Evaluates to the number of elements in 'array'. +#define GMOCK_ARRAY_SIZE_(array) (sizeof(array)/sizeof(array[0])) + +TEST(ElementsAreTest, CanDescribeExpectingNoElement) { + Matcher&> m = ElementsAre(); + EXPECT_EQ("is empty", Describe(m)); +} + +TEST(ElementsAreTest, CanDescribeExpectingOneElement) { + Matcher > m = ElementsAre(Gt(5)); + EXPECT_EQ("has 1 element that is greater than 5", Describe(m)); +} + +TEST(ElementsAreTest, CanDescribeExpectingManyElements) { + Matcher > m = ElementsAre(StrEq("one"), "two"); + EXPECT_EQ("has 2 elements where\n" + "element 0 is equal to \"one\",\n" + "element 1 is equal to \"two\"", Describe(m)); +} + +TEST(ElementsAreTest, CanDescribeNegationOfExpectingNoElement) { + Matcher > m = ElementsAre(); + EXPECT_EQ("is not empty", DescribeNegation(m)); +} + +TEST(ElementsAreTest, CanDescribeNegationOfExpectingOneElment) { + Matcher& > m = ElementsAre(Gt(5)); + EXPECT_EQ("does not have 1 element, or\n" + "element 0 is not greater than 5", DescribeNegation(m)); +} + +TEST(ElementsAreTest, CanDescribeNegationOfExpectingManyElements) { + Matcher& > m = ElementsAre("one", "two"); + EXPECT_EQ("does not have 2 elements, or\n" + "element 0 is not equal to \"one\", or\n" + "element 1 is not equal to \"two\"", DescribeNegation(m)); +} + +TEST(ElementsAreTest, DoesNotExplainTrivialMatch) { + Matcher& > m = ElementsAre(1, Ne(2)); + + list test_list; + test_list.push_back(1); + test_list.push_back(3); + EXPECT_EQ("", Explain(m, test_list)); // No need to explain anything. +} + +TEST(ElementsAreTest, ExplainsNonTrivialMatch) { + Matcher& > m = + ElementsAre(GreaterThan(1), 0, GreaterThan(2)); + + const int a[] = { 10, 0, 100 }; + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + EXPECT_EQ("element 0 is 9 more than 1,\n" + "element 2 is 98 more than 2", Explain(m, test_vector)); +} + +TEST(ElementsAreTest, CanExplainMismatchWrongSize) { + Matcher& > m = ElementsAre(1, 3); + + list test_list; + // No need to explain when the container is empty. + EXPECT_EQ("", Explain(m, test_list)); + + test_list.push_back(1); + EXPECT_EQ("has 1 element", Explain(m, test_list)); +} + +TEST(ElementsAreTest, CanExplainMismatchRightSize) { + Matcher& > m = ElementsAre(1, GreaterThan(5)); + + vector v; + v.push_back(2); + v.push_back(1); + EXPECT_EQ("element 0 doesn't match", Explain(m, v)); + + v[0] = 1; + EXPECT_EQ("element 1 doesn't match (is 4 less than 5)", Explain(m, v)); +} + +TEST(ElementsAreTest, MatchesOneElementVector) { + vector test_vector; + test_vector.push_back("test string"); + + EXPECT_THAT(test_vector, ElementsAre(StrEq("test string"))); +} + +TEST(ElementsAreTest, MatchesOneElementList) { + list test_list; + test_list.push_back("test string"); + + EXPECT_THAT(test_list, ElementsAre("test string")); +} + +TEST(ElementsAreTest, MatchesThreeElementVector) { + vector test_vector; + test_vector.push_back("one"); + test_vector.push_back("two"); + test_vector.push_back("three"); + + EXPECT_THAT(test_vector, ElementsAre("one", StrEq("two"), _)); +} + +TEST(ElementsAreTest, MatchesOneElementEqMatcher) { + vector test_vector; + test_vector.push_back(4); + + EXPECT_THAT(test_vector, ElementsAre(Eq(4))); +} + +TEST(ElementsAreTest, MatchesOneElementAnyMatcher) { + vector test_vector; + test_vector.push_back(4); + + EXPECT_THAT(test_vector, ElementsAre(_)); +} + +TEST(ElementsAreTest, MatchesOneElementValue) { + vector test_vector; + test_vector.push_back(4); + + EXPECT_THAT(test_vector, ElementsAre(4)); +} + +TEST(ElementsAreTest, MatchesThreeElementsMixedMatchers) { + vector test_vector; + test_vector.push_back(1); + test_vector.push_back(2); + test_vector.push_back(3); + + EXPECT_THAT(test_vector, ElementsAre(1, Eq(2), _)); +} + +TEST(ElementsAreTest, MatchesTenElementVector) { + const int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + + EXPECT_THAT(test_vector, + // The element list can contain values and/or matchers + // of different types. + ElementsAre(0, Ge(0), _, 3, 4, Ne(2), Eq(6), 7, 8, _)); +} + +TEST(ElementsAreTest, DoesNotMatchWrongSize) { + vector test_vector; + test_vector.push_back("test string"); + test_vector.push_back("test string"); + + Matcher > m = ElementsAre(StrEq("test string")); + EXPECT_FALSE(m.Matches(test_vector)); +} + +TEST(ElementsAreTest, DoesNotMatchWrongValue) { + vector test_vector; + test_vector.push_back("other string"); + + Matcher > m = ElementsAre(StrEq("test string")); + EXPECT_FALSE(m.Matches(test_vector)); +} + +TEST(ElementsAreTest, DoesNotMatchWrongOrder) { + vector test_vector; + test_vector.push_back("one"); + test_vector.push_back("three"); + test_vector.push_back("two"); + + Matcher > m = ElementsAre( + StrEq("one"), StrEq("two"), StrEq("three")); + EXPECT_FALSE(m.Matches(test_vector)); +} + +TEST(ElementsAreTest, WorksForNestedContainer) { + const char* strings[] = { + "Hi", + "world" + }; + + vector > nested; + for (int i = 0; i < GMOCK_ARRAY_SIZE_(strings); i++) { + nested.push_back(list(strings[i], strings[i] + strlen(strings[i]))); + } + + EXPECT_THAT(nested, ElementsAre(ElementsAre('H', Ne('e')), + ElementsAre('w', 'o', _, _, 'd'))); + EXPECT_THAT(nested, Not(ElementsAre(ElementsAre('H', 'e'), + ElementsAre('w', 'o', _, _, 'd')))); +} + +TEST(ElementsAreTest, WorksWithByRefElementMatchers) { + int a[] = { 0, 1, 2 }; + vector v(a, a + GMOCK_ARRAY_SIZE_(a)); + + EXPECT_THAT(v, ElementsAre(Ref(v[0]), Ref(v[1]), Ref(v[2]))); + EXPECT_THAT(v, Not(ElementsAre(Ref(v[0]), Ref(v[1]), Ref(a[2])))); +} + +TEST(ElementsAreTest, WorksWithContainerPointerUsingPointee) { + int a[] = { 0, 1, 2 }; + vector v(a, a + GMOCK_ARRAY_SIZE_(a)); + + EXPECT_THAT(&v, Pointee(ElementsAre(0, 1, _))); + EXPECT_THAT(&v, Not(Pointee(ElementsAre(0, _, 3)))); +} + +// Tests for ElementsAreArray(). Since ElementsAreArray() shares most +// of the implementation with ElementsAre(), we don't test it as +// thoroughly here. + +TEST(ElementsAreArrayTest, CanBeCreatedWithValueArray) { + const int a[] = { 1, 2, 3 }; + + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + EXPECT_THAT(test_vector, ElementsAreArray(a)); + + test_vector[2] = 0; + EXPECT_THAT(test_vector, Not(ElementsAreArray(a))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithArraySize) { + const char* a[] = { "one", "two", "three" }; + + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + EXPECT_THAT(test_vector, ElementsAreArray(a, GMOCK_ARRAY_SIZE_(a))); + + const char** p = a; + test_vector[0] = "1"; + EXPECT_THAT(test_vector, Not(ElementsAreArray(p, GMOCK_ARRAY_SIZE_(a)))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithoutArraySize) { + const char* a[] = { "one", "two", "three" }; + + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + EXPECT_THAT(test_vector, ElementsAreArray(a)); + + test_vector[0] = "1"; + EXPECT_THAT(test_vector, Not(ElementsAreArray(a))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { + const Matcher kMatcherArray[] = + { StrEq("one"), StrEq("two"), StrEq("three") }; + + vector test_vector; + test_vector.push_back("one"); + test_vector.push_back("two"); + test_vector.push_back("three"); + EXPECT_THAT(test_vector, ElementsAreArray(kMatcherArray)); + + test_vector.push_back("three"); + EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); +} + +} // namespace diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc new file mode 100644 index 00000000..2a43caa9 --- /dev/null +++ b/test/gmock-internal-utils_test.cc @@ -0,0 +1,521 @@ +// 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 tests the internal utilities. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace testing { +namespace internal { + +namespace { + +using ::std::tr1::tuple; + +// Tests that CompileAssertTypesEqual compiles when the type arguments are +// equal. +TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); +} + +// Tests that RemoveReference does not affect non-reference types. +TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests that RemoveReference removes reference from reference types. +TEST(RemoveReferenceTest, RemovesReference) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests GMOCK_REMOVE_REFERENCE. + +template +void TestGMockRemoveReference() { + CompileAssertTypesEqual(); +} + +TEST(RemoveReferenceTest, MacroVersion) { + TestGMockRemoveReference(); + TestGMockRemoveReference(); +} + + +// Tests that RemoveConst does not affect non-const types. +TEST(RemoveConstTest, DoesNotAffectNonConstType) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests that RemoveConst removes const from const types. +TEST(RemoveConstTest, RemovesConst) { + CompileAssertTypesEqual::type>(); +} + +// Tests GMOCK_REMOVE_CONST. + +template +void TestGMockRemoveConst() { + CompileAssertTypesEqual(); +} + +TEST(RemoveConstTest, MacroVersion) { + TestGMockRemoveConst(); + TestGMockRemoveConst(); + TestGMockRemoveConst(); +} + +// Tests that AddReference does not affect reference types. +TEST(AddReferenceTest, DoesNotAffectReferenceType) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests that AddReference adds reference to non-reference types. +TEST(AddReferenceTest, AddsReference) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests GMOCK_ADD_REFERENCE. + +template +void TestGMockAddReference() { + CompileAssertTypesEqual(); +} + +TEST(AddReferenceTest, MacroVersion) { + TestGMockAddReference(); + TestGMockAddReference(); +} + +// Tests GMOCK_REFERENCE_TO_CONST. + +template +void TestGMockReferenceToConst() { + CompileAssertTypesEqual(); +} + +TEST(GMockReferenceToConstTest, Works) { + TestGMockReferenceToConst(); + TestGMockReferenceToConst(); + TestGMockReferenceToConst(); + TestGMockReferenceToConst(); +} + +TEST(PointeeOfTest, WorksForSmartPointers) { + CompileAssertTypesEqual >::type>(); +} + +TEST(PointeeOfTest, WorksForRawPointers) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +TEST(GetRawPointerTest, WorksForSmartPointers) { + const char* const raw_p4 = new const char('a'); // NOLINT + const internal::linked_ptr p4(raw_p4); + EXPECT_EQ(raw_p4, GetRawPointer(p4)); +} + +TEST(GetRawPointerTest, WorksForRawPointers) { + int* p = NULL; + EXPECT_EQ(NULL, GetRawPointer(p)); + int n = 1; + EXPECT_EQ(&n, GetRawPointer(&n)); +} + +class Base {}; +class Derived : public Base {}; + +// Tests that ImplicitlyConvertible::value is a compile-time constant. +TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { + GMOCK_COMPILE_ASSERT((ImplicitlyConvertible::value), const_true); + GMOCK_COMPILE_ASSERT((!ImplicitlyConvertible::value), const_false); +} + +// Tests that ImplicitlyConvertible::value is true when T1 can +// be implicitly converted to T2. +TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) { + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); +} + +// Tests that ImplicitlyConvertible::value is false when T1 +// cannot be implicitly converted to T2. +TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { + EXPECT_FALSE((ImplicitlyConvertible::value)); + EXPECT_FALSE((ImplicitlyConvertible::value)); + EXPECT_FALSE((ImplicitlyConvertible::value)); + EXPECT_FALSE((ImplicitlyConvertible::value)); +} + +// Tests that IsAProtocolMessage::value is a compile-time constant. +TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { + GMOCK_COMPILE_ASSERT(IsAProtocolMessage::value, const_true); + GMOCK_COMPILE_ASSERT(!IsAProtocolMessage::value, const_false); +} + +// Tests that IsAProtocolMessage::value is true when T is +// ProtocolMessage or a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { + EXPECT_TRUE(IsAProtocolMessage::value); +#if GMOCK_HAS_PROTOBUF_ + EXPECT_TRUE(IsAProtocolMessage::value); +#endif // GMOCK_HAS_PROTOBUF_ +} + +// Tests that IsAProtocolMessage::value is false when T is neither +// ProtocolMessage nor a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { + EXPECT_FALSE(IsAProtocolMessage::value); + EXPECT_FALSE(IsAProtocolMessage::value); +} + +// Tests IsContainerTest. + +class NonContainer {}; + +TEST(IsContainerTestTest, WorksForNonContainer) { + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); +} + +TEST(IsContainerTestTest, WorksForContainer) { + EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); + EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); +} + +// Tests the TupleMatches() template function. + +TEST(TupleMatchesTest, WorksForSize0) { + tuple<> matchers; + tuple<> values; + + EXPECT_TRUE(TupleMatches(matchers, values)); +} + +TEST(TupleMatchesTest, WorksForSize1) { + tuple > matchers(Eq(1)); + tuple values1(1), + values2(2); + + EXPECT_TRUE(TupleMatches(matchers, values1)); + EXPECT_FALSE(TupleMatches(matchers, values2)); +} + +TEST(TupleMatchesTest, WorksForSize2) { + tuple, Matcher > matchers(Eq(1), Eq('a')); + tuple values1(1, 'a'), + values2(1, 'b'), + values3(2, 'a'), + values4(2, 'b'); + + EXPECT_TRUE(TupleMatches(matchers, values1)); + EXPECT_FALSE(TupleMatches(matchers, values2)); + EXPECT_FALSE(TupleMatches(matchers, values3)); + EXPECT_FALSE(TupleMatches(matchers, values4)); +} + +TEST(TupleMatchesTest, WorksForSize5) { + tuple, Matcher, Matcher, Matcher, // NOLINT + Matcher > + matchers(Eq(1), Eq('a'), Eq(true), Eq(2L), Eq("hi")); + tuple // NOLINT + values1(1, 'a', true, 2L, "hi"), + values2(1, 'a', true, 2L, "hello"), + values3(2, 'a', true, 2L, "hi"); + + EXPECT_TRUE(TupleMatches(matchers, values1)); + EXPECT_FALSE(TupleMatches(matchers, values2)); + EXPECT_FALSE(TupleMatches(matchers, values3)); +} + +// Tests that Assert(true, ...) succeeds. +TEST(AssertTest, SucceedsOnTrue) { + Assert(true, __FILE__, __LINE__, "This should succeed."); + Assert(true, __FILE__, __LINE__); // This should succeed too. +} + +#ifdef GTEST_HAS_DEATH_TEST + +// Tests that Assert(false, ...) generates a fatal failure. +TEST(AssertTest, FailsFatallyOnFalse) { + EXPECT_DEATH({ // NOLINT + Assert(false, __FILE__, __LINE__, "This should fail."); + }, ""); + + EXPECT_DEATH({ // NOLINT + Assert(false, __FILE__, __LINE__); + }, ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Tests that Expect(true, ...) succeeds. +TEST(ExpectTest, SucceedsOnTrue) { + Expect(true, __FILE__, __LINE__, "This should succeed."); + Expect(true, __FILE__, __LINE__); // This should succeed too. +} + +// Tests that Expect(false, ...) generates a non-fatal failure. +TEST(ExpectTest, FailsNonfatallyOnFalse) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + Expect(false, __FILE__, __LINE__, "This should fail."); + }, "This should fail"); + + EXPECT_NONFATAL_FAILURE({ // NOLINT + Expect(false, __FILE__, __LINE__); + }, "Expectation failed"); +} + +// TODO(wan@google.com): find a way to re-enable these tests. +#if 0 + +// Tests the Log() function. + +// Verifies that Log() behaves correctly for the given verbosity level +// and log severity. +void TestLogWithSeverity(const string& verbosity, LogSeverity severity, + bool should_print) { + const string old_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = verbosity; + CaptureTestStdout(); + Log(severity, "Test log.\n", 0); + if (should_print) { + EXPECT_PRED2(RE::FullMatch, + GetCapturedTestStdout(), + severity == WARNING ? + "\nGMOCK WARNING:\nTest log\\.\nStack trace:\n[\\s\\S]*" : + "\nTest log\\.\nStack trace:\n[\\s\\S]*"); + } else { + EXPECT_EQ("", GetCapturedTestStdout()); + } + GMOCK_FLAG(verbose) = old_flag; +} + +// Tests that when the stack_frames_to_skip parameter is negative, +// Log() doesn't include the stack trace in the output. +TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { + GMOCK_FLAG(verbose) = kInfoVerbosity; + CaptureTestStdout(); + Log(INFO, "Test log.\n", -1); + EXPECT_EQ("\nTest log.\n", GetCapturedTestStdout()); +} + +// Tests that in opt mode, a positive stack_frames_to_skip argument is +// treated as 0. +TEST(LogTest, NoSkippingStackFrameInOptMode) { + CaptureTestStdout(); + Log(WARNING, "Test log.\n", 100); + const string log = GetCapturedTestStdout(); +#ifdef NDEBUG + // In opt mode, no stack frame should be skipped. + EXPECT_THAT(log, ContainsRegex("\nGMOCK WARNING:\n" + "Test log\\.\n" + "Stack trace:\n" + ".+")); +#else + // In dbg mode, the stack frames should be skipped. + EXPECT_EQ("\nGMOCK WARNING:\n" + "Test log.\n" + "Stack trace:\n", log); +#endif // NDEBUG +} + +// Tests that all logs are printed when the value of the +// --gmock_verbose flag is "info". +TEST(LogTest, AllLogsArePrintedWhenVerbosityIsInfo) { + TestLogWithSeverity(kInfoVerbosity, INFO, true); + TestLogWithSeverity(kInfoVerbosity, WARNING, true); +} + +// Tests that only warnings are printed when the value of the +// --gmock_verbose flag is "warning". +TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsWarning) { + TestLogWithSeverity(kWarningVerbosity, INFO, false); + TestLogWithSeverity(kWarningVerbosity, WARNING, true); +} + +// Tests that no logs are printed when the value of the +// --gmock_verbose flag is "error". +TEST(LogTest, NoLogsArePrintedWhenVerbosityIsError) { + TestLogWithSeverity(kErrorVerbosity, INFO, false); + TestLogWithSeverity(kErrorVerbosity, WARNING, false); +} + +// Tests that only warnings are printed when the value of the +// --gmock_verbose flag is invalid. +TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsInvalid) { + TestLogWithSeverity("invalid", INFO, false); + TestLogWithSeverity("invalid", WARNING, true); +} + +#endif // 0 + +TEST(TypeTraitsTest, true_type) { + EXPECT_TRUE(true_type::value); +} + +TEST(TypeTraitsTest, false_type) { + EXPECT_FALSE(false_type::value); +} + +TEST(TypeTraitsTest, is_reference) { + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); + EXPECT_TRUE(is_reference::value); +} + +TEST(TypeTraitsTest, is_pointer) { + EXPECT_FALSE(is_pointer::value); + EXPECT_FALSE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); +} + +TEST(TypeTraitsTest, type_equals) { + EXPECT_FALSE((type_equals::value)); + EXPECT_FALSE((type_equals::value)); + EXPECT_FALSE((type_equals::value)); + EXPECT_TRUE((type_equals::value)); +} + +TEST(TypeTraitsTest, remove_reference) { + EXPECT_TRUE((type_equals::type>::value)); + EXPECT_TRUE((type_equals::type>::value)); + EXPECT_TRUE((type_equals::type>::value)); + EXPECT_TRUE((type_equals::type>::value)); +} + +// TODO(wan@google.com): find a way to re-enable these tests. +#if 0 + +// Verifies that Log() behaves correctly for the given verbosity level +// and log severity. +string GrabOutput(void(*logger)(), const char* verbosity) { + const string saved_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = verbosity; + CaptureTestStdout(); + logger(); + GMOCK_FLAG(verbose) = saved_flag; + return GetCapturedTestStdout(); +} + +class DummyMock { + public: + MOCK_METHOD0(TestMethod, void()); + MOCK_METHOD1(TestMethodArg, void(int dummy)); +}; + +void ExpectCallLogger() { + DummyMock mock; + EXPECT_CALL(mock, TestMethod()); + mock.TestMethod(); +}; + +// Verifies that EXPECT_CALL logs if the --gmock_verbose flag is set to "info". +TEST(ExpectCallTest, LogsWhenVerbosityIsInfo) { + EXPECT_THAT(GrabOutput(ExpectCallLogger, kInfoVerbosity), + HasSubstr("EXPECT_CALL(mock, TestMethod())")); +} + +// Verifies that EXPECT_CALL doesn't log +// if the --gmock_verbose flag is set to "warning". +TEST(ExpectCallTest, DoesNotLogWhenVerbosityIsWarning) { + EXPECT_EQ("", GrabOutput(ExpectCallLogger, kWarningVerbosity)); +} + +// Verifies that EXPECT_CALL doesn't log +// if the --gmock_verbose flag is set to "error". +TEST(ExpectCallTest, DoesNotLogWhenVerbosityIsError) { + EXPECT_EQ("", GrabOutput(ExpectCallLogger, kErrorVerbosity)); +} + +void OnCallLogger() { + DummyMock mock; + ON_CALL(mock, TestMethod()); +}; + +// Verifies that ON_CALL logs if the --gmock_verbose flag is set to "info". +TEST(OnCallTest, LogsWhenVerbosityIsInfo) { + EXPECT_THAT(GrabOutput(OnCallLogger, kInfoVerbosity), + HasSubstr("ON_CALL(mock, TestMethod())")); +} + +// Verifies that ON_CALL doesn't log +// if the --gmock_verbose flag is set to "warning". +TEST(OnCallTest, DoesNotLogWhenVerbosityIsWarning) { + EXPECT_EQ("", GrabOutput(OnCallLogger, kWarningVerbosity)); +} + +// Verifies that ON_CALL doesn't log if +// the --gmock_verbose flag is set to "error". +TEST(OnCallTest, DoesNotLogWhenVerbosityIsError) { + EXPECT_EQ("", GrabOutput(OnCallLogger, kErrorVerbosity)); +} + +void OnCallAnyArgumentLogger() { + DummyMock mock; + ON_CALL(mock, TestMethodArg(_)); +} + +// Verifies that ON_CALL prints provided _ argument. +TEST(OnCallTest, LogsAnythingArgument) { + EXPECT_THAT(GrabOutput(OnCallAnyArgumentLogger, kInfoVerbosity), + HasSubstr("ON_CALL(mock, TestMethodArg(_)")); +} + +#endif // 0 + +} // namespace +} // namespace internal +} // namespace testing diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc new file mode 100644 index 00000000..29b038e4 --- /dev/null +++ b/test/gmock-matchers_test.cc @@ -0,0 +1,2629 @@ +// 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 tests some commonly used argument matchers. + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace testing { +namespace gmock_matchers_test { + +using std::stringstream; +using testing::A; +using testing::AllOf; +using testing::An; +using testing::AnyOf; +using testing::ByRef; +using testing::DoubleEq; +using testing::EndsWith; +using testing::Eq; +using testing::Field; +using testing::FloatEq; +using testing::Ge; +using testing::Gt; +using testing::HasSubstr; +using testing::Le; +using testing::Lt; +using testing::MakeMatcher; +using testing::MakePolymorphicMatcher; +using testing::Matcher; +using testing::MatcherCast; +using testing::MatcherInterface; +using testing::Matches; +using testing::NanSensitiveDoubleEq; +using testing::NanSensitiveFloatEq; +using testing::Ne; +using testing::Not; +using testing::NotNull; +using testing::Pointee; +using testing::PolymorphicMatcher; +using testing::Property; +using testing::Ref; +using testing::ResultOf; +using testing::StartsWith; +using testing::StrCaseEq; +using testing::StrCaseNe; +using testing::StrEq; +using testing::StrNe; +using testing::Truly; +using testing::TypedEq; +using testing::_; +using testing::internal::FloatingEqMatcher; +using testing::internal::String; +using testing::internal::string; + +#ifdef GMOCK_HAS_REGEX +using testing::ContainsRegex; +using testing::MatchesRegex; +using testing::internal::RE; +#endif // GMOCK_HAS_REGEX + +// Returns the description of the given matcher. +template +string Describe(const Matcher& m) { + stringstream ss; + m.DescribeTo(&ss); + return ss.str(); +} + +// Returns the description of the negation of the given matcher. +template +string DescribeNegation(const Matcher& m) { + stringstream ss; + m.DescribeNegationTo(&ss); + return ss.str(); +} + +// Returns the reason why x matches, or doesn't match, m. +template +string Explain(const MatcherType& m, const Value& x) { + stringstream ss; + m.ExplainMatchResultTo(x, &ss); + return ss.str(); +} + +// Makes sure that the MatcherInterface interface doesn't +// change. +class EvenMatcherImpl : public MatcherInterface { + public: + virtual bool Matches(int x) const { return x % 2 == 0; } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is an even number"; + } + + // We deliberately don't define DescribeNegationTo() and + // ExplainMatchResultTo() here, to make sure the definition of these + // two methods is optional. +}; + +TEST(MatcherInterfaceTest, CanBeImplemented) { + EvenMatcherImpl m; +} + +// Tests default-constructing a matcher. +TEST(MatcherTest, CanBeDefaultConstructed) { + Matcher m; +} + +// Tests that Matcher can be constructed from a MatcherInterface*. +TEST(MatcherTest, CanBeConstructedFromMatcherInterface) { + const MatcherInterface* impl = new EvenMatcherImpl; + Matcher m(impl); + EXPECT_TRUE(m.Matches(4)); + EXPECT_FALSE(m.Matches(5)); +} + +// Tests that value can be used in place of Eq(value). +TEST(MatcherTest, CanBeImplicitlyConstructedFromValue) { + Matcher m1 = 5; + EXPECT_TRUE(m1.Matches(5)); + EXPECT_FALSE(m1.Matches(6)); +} + +// Tests that NULL can be used in place of Eq(NULL). +TEST(MatcherTest, CanBeImplicitlyConstructedFromNULL) { + Matcher m1 = NULL; + EXPECT_TRUE(m1.Matches(NULL)); + int n = 0; + EXPECT_FALSE(m1.Matches(&n)); +} + +// Tests that matchers are copyable. +TEST(MatcherTest, IsCopyable) { + // Tests the copy constructor. + Matcher m1 = Eq(false); + EXPECT_TRUE(m1.Matches(false)); + EXPECT_FALSE(m1.Matches(true)); + + // Tests the assignment operator. + m1 = Eq(true); + EXPECT_TRUE(m1.Matches(true)); + EXPECT_FALSE(m1.Matches(false)); +} + +// Tests that Matcher::DescribeTo() calls +// MatcherInterface::DescribeTo(). +TEST(MatcherTest, CanDescribeItself) { + EXPECT_EQ("is an even number", + Describe(Matcher(new EvenMatcherImpl))); +} + +// Tests that a C-string literal can be implicitly converted to a +// Matcher or Matcher. +TEST(StringMatcherTest, CanBeImplicitlyConstructedFromCStringLiteral) { + Matcher m1 = "hi"; + EXPECT_TRUE(m1.Matches("hi")); + EXPECT_FALSE(m1.Matches("hello")); + + Matcher m2 = "hi"; + EXPECT_TRUE(m2.Matches("hi")); + EXPECT_FALSE(m2.Matches("hello")); +} + +// Tests that a string object can be implicitly converted to a +// Matcher or Matcher. +TEST(StringMatcherTest, CanBeImplicitlyConstructedFromString) { + Matcher m1 = string("hi"); + EXPECT_TRUE(m1.Matches("hi")); + EXPECT_FALSE(m1.Matches("hello")); + + Matcher m2 = string("hi"); + EXPECT_TRUE(m2.Matches("hi")); + EXPECT_FALSE(m2.Matches("hello")); +} + +// Tests that MakeMatcher() constructs a Matcher from a +// MatcherInterface* without requiring the user to explicitly +// write the type. +TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) { + const MatcherInterface* dummy_impl = NULL; + Matcher m = MakeMatcher(dummy_impl); +} + +// Tests that MakePolymorphicMatcher() constructs a polymorphic +// matcher from its implementation. +const int bar = 1; +class ReferencesBarOrIsZeroImpl { + public: + template + bool Matches(const T& x) const { + const void* p = &x; + return p == &bar || x == 0; + } + + void DescribeTo(::std::ostream* os) const { *os << "bar or zero"; } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't reference bar and is not zero"; + } +}; + +// This function verifies that MakePolymorphicMatcher() returns a +// PolymorphicMatcher where T is the argument's type. +PolymorphicMatcher ReferencesBarOrIsZero() { + return MakePolymorphicMatcher(ReferencesBarOrIsZeroImpl()); +} + +TEST(MakePolymorphicMatcherTest, ConstructsMatcherFromImpl) { + // Using a polymorphic matcher to match a reference type. + Matcher m1 = ReferencesBarOrIsZero(); + EXPECT_TRUE(m1.Matches(0)); + // Verifies that the identity of a by-reference argument is preserved. + EXPECT_TRUE(m1.Matches(bar)); + EXPECT_FALSE(m1.Matches(1)); + EXPECT_EQ("bar or zero", Describe(m1)); + + // Using a polymorphic matcher to match a value type. + Matcher m2 = ReferencesBarOrIsZero(); + EXPECT_TRUE(m2.Matches(0.0)); + EXPECT_FALSE(m2.Matches(0.1)); + EXPECT_EQ("bar or zero", Describe(m2)); +} + +// Tests that MatcherCast(m) works when m is a polymorphic matcher. +TEST(MatcherCastTest, FromPolymorphicMatcher) { + Matcher m = MatcherCast(Eq(5)); + EXPECT_TRUE(m.Matches(5)); + EXPECT_FALSE(m.Matches(6)); +} + +// For testing casting matchers between compatible types. +class IntValue { + public: + // An int can be statically (although not implicitly) cast to a + // IntValue. + explicit IntValue(int value) : value_(value) {} + + int value() const { return value_; } + private: + int value_; +}; + +// For testing casting matchers between compatible types. +bool IsPositiveIntValue(const IntValue& foo) { + return foo.value() > 0; +} + +// Tests that MatcherCast(m) works when m is a Matcher where T +// can be statically converted to U. +TEST(MatcherCastTest, FromCompatibleType) { + Matcher m1 = Eq(2.0); + Matcher m2 = MatcherCast(m1); + EXPECT_TRUE(m2.Matches(2)); + EXPECT_FALSE(m2.Matches(3)); + + Matcher m3 = Truly(IsPositiveIntValue); + Matcher m4 = MatcherCast(m3); + // In the following, the arguments 1 and 0 are statically converted + // to IntValue objects, and then tested by the IsPositiveIntValue() + // predicate. + EXPECT_TRUE(m4.Matches(1)); + EXPECT_FALSE(m4.Matches(0)); +} + +// Tests that MatcherCast(m) works when m is a Matcher. +TEST(MatcherCastTest, FromConstReferenceToNonReference) { + Matcher m1 = Eq(0); + Matcher m2 = MatcherCast(m1); + EXPECT_TRUE(m2.Matches(0)); + EXPECT_FALSE(m2.Matches(1)); +} + +// Tests that MatcherCast(m) works when m is a Matcher. +TEST(MatcherCastTest, FromReferenceToNonReference) { + Matcher m1 = Eq(0); + Matcher m2 = MatcherCast(m1); + EXPECT_TRUE(m2.Matches(0)); + EXPECT_FALSE(m2.Matches(1)); +} + +// Tests that MatcherCast(m) works when m is a Matcher. +TEST(MatcherCastTest, FromNonReferenceToConstReference) { + Matcher m1 = Eq(0); + Matcher m2 = MatcherCast(m1); + EXPECT_TRUE(m2.Matches(0)); + EXPECT_FALSE(m2.Matches(1)); +} + +// Tests that MatcherCast(m) works when m is a Matcher. +TEST(MatcherCastTest, FromNonReferenceToReference) { + Matcher m1 = Eq(0); + Matcher m2 = MatcherCast(m1); + int n = 0; + EXPECT_TRUE(m2.Matches(n)); + n = 1; + EXPECT_FALSE(m2.Matches(n)); +} + +// Tests that MatcherCast(m) works when m is a Matcher. +TEST(MatcherCastTest, FromSameType) { + Matcher m1 = Eq(0); + Matcher m2 = MatcherCast(m1); + EXPECT_TRUE(m2.Matches(0)); + EXPECT_FALSE(m2.Matches(1)); +} + +// Tests that A() matches any value of type T. +TEST(ATest, MatchesAnyValue) { + // Tests a matcher for a value type. + Matcher m1 = A(); + EXPECT_TRUE(m1.Matches(91.43)); + EXPECT_TRUE(m1.Matches(-15.32)); + + // Tests a matcher for a reference type. + int a = 2; + int b = -6; + Matcher m2 = A(); + EXPECT_TRUE(m2.Matches(a)); + EXPECT_TRUE(m2.Matches(b)); +} + +// Tests that A() describes itself properly. +TEST(ATest, CanDescribeSelf) { + EXPECT_EQ("is anything", Describe(A())); +} + +// Tests that An() matches any value of type T. +TEST(AnTest, MatchesAnyValue) { + // Tests a matcher for a value type. + Matcher m1 = An(); + EXPECT_TRUE(m1.Matches(9143)); + EXPECT_TRUE(m1.Matches(-1532)); + + // Tests a matcher for a reference type. + int a = 2; + int b = -6; + Matcher m2 = An(); + EXPECT_TRUE(m2.Matches(a)); + EXPECT_TRUE(m2.Matches(b)); +} + +// Tests that An() describes itself properly. +TEST(AnTest, CanDescribeSelf) { + EXPECT_EQ("is anything", Describe(An())); +} + +// Tests that _ can be used as a matcher for any type and matches any +// value of that type. +TEST(UnderscoreTest, MatchesAnyValue) { + // Uses _ as a matcher for a value type. + Matcher m1 = _; + EXPECT_TRUE(m1.Matches(123)); + EXPECT_TRUE(m1.Matches(-242)); + + // Uses _ as a matcher for a reference type. + bool a = false; + const bool b = true; + Matcher m2 = _; + EXPECT_TRUE(m2.Matches(a)); + EXPECT_TRUE(m2.Matches(b)); +} + +// Tests that _ describes itself properly. +TEST(UnderscoreTest, CanDescribeSelf) { + Matcher m = _; + EXPECT_EQ("is anything", Describe(m)); +} + +// Tests that Eq(x) matches any value equal to x. +TEST(EqTest, MatchesEqualValue) { + // 2 C-strings with same content but different addresses. + const char a1[] = "hi"; + const char a2[] = "hi"; + + Matcher m1 = Eq(a1); + EXPECT_TRUE(m1.Matches(a1)); + EXPECT_FALSE(m1.Matches(a2)); +} + +// Tests that Eq(v) describes itself properly. + +class Unprintable { + public: + Unprintable() : c_('a') {} + + bool operator==(const Unprintable& rhs) { return true; } + private: + char c_; +}; + +TEST(EqTest, CanDescribeSelf) { + Matcher m = Eq(Unprintable()); + EXPECT_EQ("is equal to 1-byte object <61>", Describe(m)); +} + +// Tests that Eq(v) can be used to match any type that supports +// comparing with type T, where T is v's type. +TEST(EqTest, IsPolymorphic) { + Matcher m1 = Eq(1); + EXPECT_TRUE(m1.Matches(1)); + EXPECT_FALSE(m1.Matches(2)); + + Matcher m2 = Eq(1); + EXPECT_TRUE(m2.Matches('\1')); + EXPECT_FALSE(m2.Matches('a')); +} + +// Tests that TypedEq(v) matches values of type T that's equal to v. +TEST(TypedEqTest, ChecksEqualityForGivenType) { + Matcher m1 = TypedEq('a'); + EXPECT_TRUE(m1.Matches('a')); + EXPECT_FALSE(m1.Matches('b')); + + Matcher m2 = TypedEq(6); + EXPECT_TRUE(m2.Matches(6)); + EXPECT_FALSE(m2.Matches(7)); +} + +// Tests that TypedEq(v) describes itself properly. +TEST(TypedEqTest, CanDescribeSelf) { + EXPECT_EQ("is equal to 2", Describe(TypedEq(2))); +} + +// Tests that TypedEq(v) has type Matcher. + +// Type::IsTypeOf(v) compiles iff the type of value v is T, where T +// is a "bare" type (i.e. not in the form of const U or U&). If v's +// type is not T, the compiler will generate a message about +// "undefined referece". +template +struct Type { + static bool IsTypeOf(const T& v) { return true; } + + template + static void IsTypeOf(T2 v); +}; + +TEST(TypedEqTest, HasSpecifiedType) { + // Verfies that the type of TypedEq(v) is Matcher. + Type >::IsTypeOf(TypedEq(5)); + Type >::IsTypeOf(TypedEq(5)); +} + +// Tests that Ge(v) matches anything >= v. +TEST(GeTest, ImplementsGreaterThanOrEqual) { + Matcher m1 = Ge(0); + EXPECT_TRUE(m1.Matches(1)); + EXPECT_TRUE(m1.Matches(0)); + EXPECT_FALSE(m1.Matches(-1)); +} + +// Tests that Ge(v) describes itself properly. +TEST(GeTest, CanDescribeSelf) { + Matcher m = Ge(5); + EXPECT_EQ("is greater than or equal to 5", Describe(m)); +} + +// Tests that Gt(v) matches anything > v. +TEST(GtTest, ImplementsGreaterThan) { + Matcher m1 = Gt(0); + EXPECT_TRUE(m1.Matches(1.0)); + EXPECT_FALSE(m1.Matches(0.0)); + EXPECT_FALSE(m1.Matches(-1.0)); +} + +// Tests that Gt(v) describes itself properly. +TEST(GtTest, CanDescribeSelf) { + Matcher m = Gt(5); + EXPECT_EQ("is greater than 5", Describe(m)); +} + +// Tests that Le(v) matches anything <= v. +TEST(LeTest, ImplementsLessThanOrEqual) { + Matcher m1 = Le('b'); + EXPECT_TRUE(m1.Matches('a')); + EXPECT_TRUE(m1.Matches('b')); + EXPECT_FALSE(m1.Matches('c')); +} + +// Tests that Le(v) describes itself properly. +TEST(LeTest, CanDescribeSelf) { + Matcher m = Le(5); + EXPECT_EQ("is less than or equal to 5", Describe(m)); +} + +// Tests that Lt(v) matches anything < v. +TEST(LtTest, ImplementsLessThan) { + Matcher m1 = Lt("Hello"); + EXPECT_TRUE(m1.Matches("Abc")); + EXPECT_FALSE(m1.Matches("Hello")); + EXPECT_FALSE(m1.Matches("Hello, world!")); +} + +// Tests that Lt(v) describes itself properly. +TEST(LtTest, CanDescribeSelf) { + Matcher m = Lt(5); + EXPECT_EQ("is less than 5", Describe(m)); +} + +// Tests that Ne(v) matches anything != v. +TEST(NeTest, ImplementsNotEqual) { + Matcher m1 = Ne(0); + EXPECT_TRUE(m1.Matches(1)); + EXPECT_TRUE(m1.Matches(-1)); + EXPECT_FALSE(m1.Matches(0)); +} + +// Tests that Ne(v) describes itself properly. +TEST(NeTest, CanDescribeSelf) { + Matcher m = Ne(5); + EXPECT_EQ("is not equal to 5", Describe(m)); +} + +// Tests that NotNull() matches any non-NULL pointer of any type. +TEST(NotNullTest, MatchesNonNullPointer) { + Matcher m1 = NotNull(); + int* p1 = NULL; + int n = 0; + EXPECT_FALSE(m1.Matches(p1)); + EXPECT_TRUE(m1.Matches(&n)); + + Matcher m2 = NotNull(); + const char* p2 = NULL; + EXPECT_FALSE(m2.Matches(p2)); + EXPECT_TRUE(m2.Matches("hi")); +} + +// Tests that NotNull() describes itself properly. +TEST(NotNullTest, CanDescribeSelf) { + Matcher m = NotNull(); + EXPECT_EQ("is not NULL", Describe(m)); +} + +// Tests that Ref(variable) matches an argument that references +// 'variable'. +TEST(RefTest, MatchesSameVariable) { + int a = 0; + int b = 0; + Matcher m = Ref(a); + EXPECT_TRUE(m.Matches(a)); + EXPECT_FALSE(m.Matches(b)); +} + +// Tests that Ref(variable) describes itself properly. +TEST(RefTest, CanDescribeSelf) { + int n = 5; + Matcher m = Ref(n); + stringstream ss; + ss << "references the variable @" << &n << " 5"; + EXPECT_EQ(string(ss.str()), Describe(m)); +} + +// Test that Ref(non_const_varialbe) can be used as a matcher for a +// const reference. +TEST(RefTest, CanBeUsedAsMatcherForConstReference) { + int a = 0; + int b = 0; + Matcher m = Ref(a); + EXPECT_TRUE(m.Matches(a)); + EXPECT_FALSE(m.Matches(b)); +} + +// Tests that Ref(variable) is covariant, i.e. Ref(derived) can be +// used wherever Ref(base) can be used (Ref(derived) is a sub-type +// of Ref(base), but not vice versa. + +class Base {}; +class Derived : public Base {}; + +TEST(RefTest, IsCovariant) { + Base base, base2; + Derived derived; + Matcher m1 = Ref(base); + EXPECT_TRUE(m1.Matches(base)); + EXPECT_FALSE(m1.Matches(base2)); + EXPECT_FALSE(m1.Matches(derived)); + + m1 = Ref(derived); + EXPECT_TRUE(m1.Matches(derived)); + EXPECT_FALSE(m1.Matches(base)); + EXPECT_FALSE(m1.Matches(base2)); +} + +// Tests string comparison matchers. + +TEST(StrEqTest, MatchesEqualString) { + Matcher m = StrEq(string("Hello")); + EXPECT_TRUE(m.Matches("Hello")); + EXPECT_FALSE(m.Matches("hello")); + EXPECT_FALSE(m.Matches(NULL)); + + Matcher m2 = StrEq("Hello"); + EXPECT_TRUE(m2.Matches("Hello")); + EXPECT_FALSE(m2.Matches("Hi")); +} + +TEST(StrEqTest, CanDescribeSelf) { + Matcher m = StrEq("Hi-\'\"\?\\\a\b\f\n\r\t\v\xD3"); + EXPECT_EQ("is equal to \"Hi-\'\\\"\\?\\\\\\a\\b\\f\\n\\r\\t\\v\\xD3\"", + Describe(m)); + + string str("01204500800"); + str[3] = '\0'; + Matcher m2 = StrEq(str); + EXPECT_EQ("is equal to \"012\\04500800\"", Describe(m2)); + str[0] = str[6] = str[7] = str[9] = str[10] = '\0'; + Matcher m3 = StrEq(str); + EXPECT_EQ("is equal to \"\\012\\045\\0\\08\\0\\0\"", Describe(m3)); +} + +TEST(StrNeTest, MatchesUnequalString) { + Matcher m = StrNe("Hello"); + EXPECT_TRUE(m.Matches("")); + EXPECT_TRUE(m.Matches(NULL)); + EXPECT_FALSE(m.Matches("Hello")); + + Matcher m2 = StrNe(string("Hello")); + EXPECT_TRUE(m2.Matches("hello")); + EXPECT_FALSE(m2.Matches("Hello")); +} + +TEST(StrNeTest, CanDescribeSelf) { + Matcher m = StrNe("Hi"); + EXPECT_EQ("is not equal to \"Hi\"", Describe(m)); +} + +TEST(StrCaseEqTest, MatchesEqualStringIgnoringCase) { + Matcher m = StrCaseEq(string("Hello")); + EXPECT_TRUE(m.Matches("Hello")); + EXPECT_TRUE(m.Matches("hello")); + EXPECT_FALSE(m.Matches("Hi")); + EXPECT_FALSE(m.Matches(NULL)); + + Matcher m2 = StrCaseEq("Hello"); + EXPECT_TRUE(m2.Matches("hello")); + EXPECT_FALSE(m2.Matches("Hi")); +} + +TEST(StrCaseEqTest, MatchesEqualStringWith0IgnoringCase) { + string str1("oabocdooeoo"); + string str2("OABOCDOOEOO"); + Matcher m0 = StrCaseEq(str1); + EXPECT_FALSE(m0.Matches(str2 + string(1, '\0'))); + + str1[3] = str2[3] = '\0'; + Matcher m1 = StrCaseEq(str1); + EXPECT_TRUE(m1.Matches(str2)); + + str1[0] = str1[6] = str1[7] = str1[10] = '\0'; + str2[0] = str2[6] = str2[7] = str2[10] = '\0'; + Matcher m2 = StrCaseEq(str1); + str1[9] = str2[9] = '\0'; + EXPECT_FALSE(m2.Matches(str2)); + + Matcher m3 = StrCaseEq(str1); + EXPECT_TRUE(m3.Matches(str2)); + + EXPECT_FALSE(m3.Matches(str2 + "x")); + str2.append(1, '\0'); + EXPECT_FALSE(m3.Matches(str2)); + EXPECT_FALSE(m3.Matches(string(str2, 0, 9))); +} + +TEST(StrCaseEqTest, CanDescribeSelf) { + Matcher m = StrCaseEq("Hi"); + EXPECT_EQ("is equal to (ignoring case) \"Hi\"", Describe(m)); +} + +TEST(StrCaseNeTest, MatchesUnequalStringIgnoringCase) { + Matcher m = StrCaseNe("Hello"); + EXPECT_TRUE(m.Matches("Hi")); + EXPECT_TRUE(m.Matches(NULL)); + EXPECT_FALSE(m.Matches("Hello")); + EXPECT_FALSE(m.Matches("hello")); + + Matcher m2 = StrCaseNe(string("Hello")); + EXPECT_TRUE(m2.Matches("")); + EXPECT_FALSE(m2.Matches("Hello")); +} + +TEST(StrCaseNeTest, CanDescribeSelf) { + Matcher m = StrCaseNe("Hi"); + EXPECT_EQ("is not equal to (ignoring case) \"Hi\"", Describe(m)); +} + +// Tests that HasSubstr() works for matching string-typed values. +TEST(HasSubstrTest, WorksForStringClasses) { + const Matcher m1 = HasSubstr("foo"); + EXPECT_TRUE(m1.Matches(string("I love food."))); + EXPECT_FALSE(m1.Matches(string("tofo"))); + + const Matcher m2 = HasSubstr("foo"); + EXPECT_TRUE(m2.Matches(std::string("I love food."))); + EXPECT_FALSE(m2.Matches(std::string("tofo"))); +} + +// Tests that HasSubstr() works for matching C-string-typed values. +TEST(HasSubstrTest, WorksForCStrings) { + const Matcher m1 = HasSubstr("foo"); + EXPECT_TRUE(m1.Matches(const_cast("I love food."))); + EXPECT_FALSE(m1.Matches(const_cast("tofo"))); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = HasSubstr("foo"); + EXPECT_TRUE(m2.Matches("I love food.")); + EXPECT_FALSE(m2.Matches("tofo")); + EXPECT_FALSE(m2.Matches(NULL)); +} + +// Tests that HasSubstr(s) describes itself properly. +TEST(HasSubstrTest, CanDescribeSelf) { + Matcher m = HasSubstr("foo\n\""); + EXPECT_EQ("has substring \"foo\\n\\\"\"", Describe(m)); +} + +// Tests StartsWith(s). + +TEST(StartsWithTest, MatchesStringWithGivenPrefix) { + const Matcher m1 = StartsWith(string("")); + EXPECT_TRUE(m1.Matches("Hi")); + EXPECT_TRUE(m1.Matches("")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = StartsWith("Hi"); + EXPECT_TRUE(m2.Matches("Hi")); + EXPECT_TRUE(m2.Matches("Hi Hi!")); + EXPECT_TRUE(m2.Matches("High")); + EXPECT_FALSE(m2.Matches("H")); + EXPECT_FALSE(m2.Matches(" Hi")); +} + +TEST(StartsWithTest, CanDescribeSelf) { + Matcher m = StartsWith("Hi"); + EXPECT_EQ("starts with \"Hi\"", Describe(m)); +} + +// Tests EndsWith(s). + +TEST(EndsWithTest, MatchesStringWithGivenSuffix) { + const Matcher m1 = EndsWith(""); + EXPECT_TRUE(m1.Matches("Hi")); + EXPECT_TRUE(m1.Matches("")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = EndsWith(string("Hi")); + EXPECT_TRUE(m2.Matches("Hi")); + EXPECT_TRUE(m2.Matches("Wow Hi Hi")); + EXPECT_TRUE(m2.Matches("Super Hi")); + EXPECT_FALSE(m2.Matches("i")); + EXPECT_FALSE(m2.Matches("Hi ")); +} + +TEST(EndsWithTest, CanDescribeSelf) { + Matcher m = EndsWith("Hi"); + EXPECT_EQ("ends with \"Hi\"", Describe(m)); +} + +#ifdef GMOCK_HAS_REGEX + +// Tests MatchesRegex(). + +TEST(MatchesRegexTest, MatchesStringMatchingGivenRegex) { + const Matcher m1 = MatchesRegex("a.*z"); + EXPECT_TRUE(m1.Matches("az")); + EXPECT_TRUE(m1.Matches("abcz")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = MatchesRegex(new RE("a.*z")); + EXPECT_TRUE(m2.Matches("azbz")); + EXPECT_FALSE(m2.Matches("az1")); + EXPECT_FALSE(m2.Matches("1az")); +} + +TEST(MatchesRegexTest, CanDescribeSelf) { + Matcher m1 = MatchesRegex(string("Hi.*")); + EXPECT_EQ("matches regular expression \"Hi.*\"", Describe(m1)); + + Matcher m2 = MatchesRegex(new RE("[a-z].*")); + EXPECT_EQ("matches regular expression \"[a-z].*\"", Describe(m2)); +} + +// Tests ContainsRegex(). + +TEST(ContainsRegexTest, MatchesStringContainingGivenRegex) { + const Matcher m1 = ContainsRegex(string("a.*z")); + EXPECT_TRUE(m1.Matches("az")); + EXPECT_TRUE(m1.Matches("0abcz1")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = ContainsRegex(new RE("a.*z")); + EXPECT_TRUE(m2.Matches("azbz")); + EXPECT_TRUE(m2.Matches("az1")); + EXPECT_FALSE(m2.Matches("1a")); +} + +TEST(ContainsRegexTest, CanDescribeSelf) { + Matcher m1 = ContainsRegex("Hi.*"); + EXPECT_EQ("contains regular expression \"Hi.*\"", Describe(m1)); + + Matcher m2 = ContainsRegex(new RE("[a-z].*")); + EXPECT_EQ("contains regular expression \"[a-z].*\"", Describe(m2)); +} +#endif // GMOCK_HAS_REGEX + +// Tests for wide strings. +#if GTEST_HAS_STD_WSTRING +TEST(StdWideStrEqTest, MatchesEqual) { + Matcher m = StrEq(::std::wstring(L"Hello")); + EXPECT_TRUE(m.Matches(L"Hello")); + EXPECT_FALSE(m.Matches(L"hello")); + EXPECT_FALSE(m.Matches(NULL)); + + Matcher m2 = StrEq(L"Hello"); + EXPECT_TRUE(m2.Matches(L"Hello")); + EXPECT_FALSE(m2.Matches(L"Hi")); + + Matcher m3 = StrEq(L"\xD3\x576\x8D3\xC74D"); + EXPECT_TRUE(m3.Matches(L"\xD3\x576\x8D3\xC74D")); + EXPECT_FALSE(m3.Matches(L"\xD3\x576\x8D3\xC74E")); + + ::std::wstring str(L"01204500800"); + str[3] = L'\0'; + Matcher m4 = StrEq(str); + EXPECT_TRUE(m4.Matches(str)); + str[0] = str[6] = str[7] = str[9] = str[10] = L'\0'; + Matcher m5 = StrEq(str); + EXPECT_TRUE(m5.Matches(str)); +} + +TEST(StdWideStrEqTest, CanDescribeSelf) { + Matcher< ::std::wstring> m = StrEq(L"Hi-\'\"\?\\\a\b\f\n\r\t\v"); + EXPECT_EQ("is equal to L\"Hi-\'\\\"\\?\\\\\\a\\b\\f\\n\\r\\t\\v\"", + Describe(m)); + + Matcher< ::std::wstring> m2 = StrEq(L"\xD3\x576\x8D3\xC74D"); + EXPECT_EQ("is equal to L\"\\xD3\\x576\\x8D3\\xC74D\"", + Describe(m2)); + + ::std::wstring str(L"01204500800"); + str[3] = L'\0'; + Matcher m4 = StrEq(str); + EXPECT_EQ("is equal to L\"012\\04500800\"", Describe(m4)); + str[0] = str[6] = str[7] = str[9] = str[10] = L'\0'; + Matcher m5 = StrEq(str); + EXPECT_EQ("is equal to L\"\\012\\045\\0\\08\\0\\0\"", Describe(m5)); +} + +TEST(StdWideStrNeTest, MatchesUnequalString) { + Matcher m = StrNe(L"Hello"); + EXPECT_TRUE(m.Matches(L"")); + EXPECT_TRUE(m.Matches(NULL)); + EXPECT_FALSE(m.Matches(L"Hello")); + + Matcher< ::std::wstring> m2 = StrNe(::std::wstring(L"Hello")); + EXPECT_TRUE(m2.Matches(L"hello")); + EXPECT_FALSE(m2.Matches(L"Hello")); +} + +TEST(StdWideStrNeTest, CanDescribeSelf) { + Matcher m = StrNe(L"Hi"); + EXPECT_EQ("is not equal to L\"Hi\"", Describe(m)); +} + +TEST(StdWideStrCaseEqTest, MatchesEqualStringIgnoringCase) { + Matcher m = StrCaseEq(::std::wstring(L"Hello")); + EXPECT_TRUE(m.Matches(L"Hello")); + EXPECT_TRUE(m.Matches(L"hello")); + EXPECT_FALSE(m.Matches(L"Hi")); + EXPECT_FALSE(m.Matches(NULL)); + + Matcher m2 = StrCaseEq(L"Hello"); + EXPECT_TRUE(m2.Matches(L"hello")); + EXPECT_FALSE(m2.Matches(L"Hi")); +} + +TEST(StdWideStrCaseEqTest, MatchesEqualStringWith0IgnoringCase) { + ::std::wstring str1(L"oabocdooeoo"); + ::std::wstring str2(L"OABOCDOOEOO"); + Matcher m0 = StrCaseEq(str1); + EXPECT_FALSE(m0.Matches(str2 + ::std::wstring(1, L'\0'))); + + str1[3] = str2[3] = L'\0'; + Matcher m1 = StrCaseEq(str1); + EXPECT_TRUE(m1.Matches(str2)); + + str1[0] = str1[6] = str1[7] = str1[10] = L'\0'; + str2[0] = str2[6] = str2[7] = str2[10] = L'\0'; + Matcher m2 = StrCaseEq(str1); + str1[9] = str2[9] = L'\0'; + EXPECT_FALSE(m2.Matches(str2)); + + Matcher m3 = StrCaseEq(str1); + EXPECT_TRUE(m3.Matches(str2)); + + EXPECT_FALSE(m3.Matches(str2 + L"x")); + str2.append(1, L'\0'); + EXPECT_FALSE(m3.Matches(str2)); + EXPECT_FALSE(m3.Matches(::std::wstring(str2, 0, 9))); +} + +TEST(StdWideStrCaseEqTest, CanDescribeSelf) { + Matcher< ::std::wstring> m = StrCaseEq(L"Hi"); + EXPECT_EQ("is equal to (ignoring case) L\"Hi\"", Describe(m)); +} + +TEST(StdWideStrCaseNeTest, MatchesUnequalStringIgnoringCase) { + Matcher m = StrCaseNe(L"Hello"); + EXPECT_TRUE(m.Matches(L"Hi")); + EXPECT_TRUE(m.Matches(NULL)); + EXPECT_FALSE(m.Matches(L"Hello")); + EXPECT_FALSE(m.Matches(L"hello")); + + Matcher< ::std::wstring> m2 = StrCaseNe(::std::wstring(L"Hello")); + EXPECT_TRUE(m2.Matches(L"")); + EXPECT_FALSE(m2.Matches(L"Hello")); +} + +TEST(StdWideStrCaseNeTest, CanDescribeSelf) { + Matcher m = StrCaseNe(L"Hi"); + EXPECT_EQ("is not equal to (ignoring case) L\"Hi\"", Describe(m)); +} + +// Tests that HasSubstr() works for matching wstring-typed values. +TEST(StdWideHasSubstrTest, WorksForStringClasses) { + const Matcher< ::std::wstring> m1 = HasSubstr(L"foo"); + EXPECT_TRUE(m1.Matches(::std::wstring(L"I love food."))); + EXPECT_FALSE(m1.Matches(::std::wstring(L"tofo"))); + + const Matcher m2 = HasSubstr(L"foo"); + EXPECT_TRUE(m2.Matches(::std::wstring(L"I love food."))); + EXPECT_FALSE(m2.Matches(::std::wstring(L"tofo"))); +} + +// Tests that HasSubstr() works for matching C-wide-string-typed values. +TEST(StdWideHasSubstrTest, WorksForCStrings) { + const Matcher m1 = HasSubstr(L"foo"); + EXPECT_TRUE(m1.Matches(const_cast(L"I love food."))); + EXPECT_FALSE(m1.Matches(const_cast(L"tofo"))); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = HasSubstr(L"foo"); + EXPECT_TRUE(m2.Matches(L"I love food.")); + EXPECT_FALSE(m2.Matches(L"tofo")); + EXPECT_FALSE(m2.Matches(NULL)); +} + +// Tests that HasSubstr(s) describes itself properly. +TEST(StdWideHasSubstrTest, CanDescribeSelf) { + Matcher< ::std::wstring> m = HasSubstr(L"foo\n\""); + EXPECT_EQ("has substring L\"foo\\n\\\"\"", Describe(m)); +} + +// Tests StartsWith(s). + +TEST(StdWideStartsWithTest, MatchesStringWithGivenPrefix) { + const Matcher m1 = StartsWith(::std::wstring(L"")); + EXPECT_TRUE(m1.Matches(L"Hi")); + EXPECT_TRUE(m1.Matches(L"")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = StartsWith(L"Hi"); + EXPECT_TRUE(m2.Matches(L"Hi")); + EXPECT_TRUE(m2.Matches(L"Hi Hi!")); + EXPECT_TRUE(m2.Matches(L"High")); + EXPECT_FALSE(m2.Matches(L"H")); + EXPECT_FALSE(m2.Matches(L" Hi")); +} + +TEST(StdWideStartsWithTest, CanDescribeSelf) { + Matcher m = StartsWith(L"Hi"); + EXPECT_EQ("starts with L\"Hi\"", Describe(m)); +} + +// Tests EndsWith(s). + +TEST(StdWideEndsWithTest, MatchesStringWithGivenSuffix) { + const Matcher m1 = EndsWith(L""); + EXPECT_TRUE(m1.Matches(L"Hi")); + EXPECT_TRUE(m1.Matches(L"")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = EndsWith(::std::wstring(L"Hi")); + EXPECT_TRUE(m2.Matches(L"Hi")); + EXPECT_TRUE(m2.Matches(L"Wow Hi Hi")); + EXPECT_TRUE(m2.Matches(L"Super Hi")); + EXPECT_FALSE(m2.Matches(L"i")); + EXPECT_FALSE(m2.Matches(L"Hi ")); +} + +TEST(StdWideEndsWithTest, CanDescribeSelf) { + Matcher m = EndsWith(L"Hi"); + EXPECT_EQ("ends with L\"Hi\"", Describe(m)); +} + +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +TEST(GlobalWideStrEqTest, MatchesEqual) { + Matcher m = StrEq(::wstring(L"Hello")); + EXPECT_TRUE(m.Matches(L"Hello")); + EXPECT_FALSE(m.Matches(L"hello")); + EXPECT_FALSE(m.Matches(NULL)); + + Matcher m2 = StrEq(L"Hello"); + EXPECT_TRUE(m2.Matches(L"Hello")); + EXPECT_FALSE(m2.Matches(L"Hi")); + + Matcher m3 = StrEq(L"\xD3\x576\x8D3\xC74D"); + EXPECT_TRUE(m3.Matches(L"\xD3\x576\x8D3\xC74D")); + EXPECT_FALSE(m3.Matches(L"\xD3\x576\x8D3\xC74E")); + + ::wstring str(L"01204500800"); + str[3] = L'\0'; + Matcher m4 = StrEq(str); + EXPECT_TRUE(m4.Matches(str)); + str[0] = str[6] = str[7] = str[9] = str[10] = L'\0'; + Matcher m5 = StrEq(str); + EXPECT_TRUE(m5.Matches(str)); +} + +TEST(GlobalWideStrEqTest, CanDescribeSelf) { + Matcher< ::wstring> m = StrEq(L"Hi-\'\"\?\\\a\b\f\n\r\t\v"); + EXPECT_EQ("is equal to L\"Hi-\'\\\"\\?\\\\\\a\\b\\f\\n\\r\\t\\v\"", + Describe(m)); + + Matcher< ::wstring> m2 = StrEq(L"\xD3\x576\x8D3\xC74D"); + EXPECT_EQ("is equal to L\"\\xD3\\x576\\x8D3\\xC74D\"", + Describe(m2)); + + ::wstring str(L"01204500800"); + str[3] = L'\0'; + Matcher m4 = StrEq(str); + EXPECT_EQ("is equal to L\"012\\04500800\"", Describe(m4)); + str[0] = str[6] = str[7] = str[9] = str[10] = L'\0'; + Matcher m5 = StrEq(str); + EXPECT_EQ("is equal to L\"\\012\\045\\0\\08\\0\\0\"", Describe(m5)); +} + +TEST(GlobalWideStrNeTest, MatchesUnequalString) { + Matcher m = StrNe(L"Hello"); + EXPECT_TRUE(m.Matches(L"")); + EXPECT_TRUE(m.Matches(NULL)); + EXPECT_FALSE(m.Matches(L"Hello")); + + Matcher< ::wstring> m2 = StrNe(::wstring(L"Hello")); + EXPECT_TRUE(m2.Matches(L"hello")); + EXPECT_FALSE(m2.Matches(L"Hello")); +} + +TEST(GlobalWideStrNeTest, CanDescribeSelf) { + Matcher m = StrNe(L"Hi"); + EXPECT_EQ("is not equal to L\"Hi\"", Describe(m)); +} + +TEST(GlobalWideStrCaseEqTest, MatchesEqualStringIgnoringCase) { + Matcher m = StrCaseEq(::wstring(L"Hello")); + EXPECT_TRUE(m.Matches(L"Hello")); + EXPECT_TRUE(m.Matches(L"hello")); + EXPECT_FALSE(m.Matches(L"Hi")); + EXPECT_FALSE(m.Matches(NULL)); + + Matcher m2 = StrCaseEq(L"Hello"); + EXPECT_TRUE(m2.Matches(L"hello")); + EXPECT_FALSE(m2.Matches(L"Hi")); +} + +TEST(GlobalWideStrCaseEqTest, MatchesEqualStringWith0IgnoringCase) { + ::wstring str1(L"oabocdooeoo"); + ::wstring str2(L"OABOCDOOEOO"); + Matcher m0 = StrCaseEq(str1); + EXPECT_FALSE(m0.Matches(str2 + ::wstring(1, L'\0'))); + + str1[3] = str2[3] = L'\0'; + Matcher m1 = StrCaseEq(str1); + EXPECT_TRUE(m1.Matches(str2)); + + str1[0] = str1[6] = str1[7] = str1[10] = L'\0'; + str2[0] = str2[6] = str2[7] = str2[10] = L'\0'; + Matcher m2 = StrCaseEq(str1); + str1[9] = str2[9] = L'\0'; + EXPECT_FALSE(m2.Matches(str2)); + + Matcher m3 = StrCaseEq(str1); + EXPECT_TRUE(m3.Matches(str2)); + + EXPECT_FALSE(m3.Matches(str2 + L"x")); + str2.append(1, L'\0'); + EXPECT_FALSE(m3.Matches(str2)); + EXPECT_FALSE(m3.Matches(::wstring(str2, 0, 9))); +} + +TEST(GlobalWideStrCaseEqTest, CanDescribeSelf) { + Matcher< ::wstring> m = StrCaseEq(L"Hi"); + EXPECT_EQ("is equal to (ignoring case) L\"Hi\"", Describe(m)); +} + +TEST(GlobalWideStrCaseNeTest, MatchesUnequalStringIgnoringCase) { + Matcher m = StrCaseNe(L"Hello"); + EXPECT_TRUE(m.Matches(L"Hi")); + EXPECT_TRUE(m.Matches(NULL)); + EXPECT_FALSE(m.Matches(L"Hello")); + EXPECT_FALSE(m.Matches(L"hello")); + + Matcher< ::wstring> m2 = StrCaseNe(::wstring(L"Hello")); + EXPECT_TRUE(m2.Matches(L"")); + EXPECT_FALSE(m2.Matches(L"Hello")); +} + +TEST(GlobalWideStrCaseNeTest, CanDescribeSelf) { + Matcher m = StrCaseNe(L"Hi"); + EXPECT_EQ("is not equal to (ignoring case) L\"Hi\"", Describe(m)); +} + +// Tests that HasSubstr() works for matching wstring-typed values. +TEST(GlobalWideHasSubstrTest, WorksForStringClasses) { + const Matcher< ::wstring> m1 = HasSubstr(L"foo"); + EXPECT_TRUE(m1.Matches(::wstring(L"I love food."))); + EXPECT_FALSE(m1.Matches(::wstring(L"tofo"))); + + const Matcher m2 = HasSubstr(L"foo"); + EXPECT_TRUE(m2.Matches(::wstring(L"I love food."))); + EXPECT_FALSE(m2.Matches(::wstring(L"tofo"))); +} + +// Tests that HasSubstr() works for matching C-wide-string-typed values. +TEST(GlobalWideHasSubstrTest, WorksForCStrings) { + const Matcher m1 = HasSubstr(L"foo"); + EXPECT_TRUE(m1.Matches(const_cast(L"I love food."))); + EXPECT_FALSE(m1.Matches(const_cast(L"tofo"))); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = HasSubstr(L"foo"); + EXPECT_TRUE(m2.Matches(L"I love food.")); + EXPECT_FALSE(m2.Matches(L"tofo")); + EXPECT_FALSE(m2.Matches(NULL)); +} + +// Tests that HasSubstr(s) describes itself properly. +TEST(GlobalWideHasSubstrTest, CanDescribeSelf) { + Matcher< ::wstring> m = HasSubstr(L"foo\n\""); + EXPECT_EQ("has substring L\"foo\\n\\\"\"", Describe(m)); +} + +// Tests StartsWith(s). + +TEST(GlobalWideStartsWithTest, MatchesStringWithGivenPrefix) { + const Matcher m1 = StartsWith(::wstring(L"")); + EXPECT_TRUE(m1.Matches(L"Hi")); + EXPECT_TRUE(m1.Matches(L"")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = StartsWith(L"Hi"); + EXPECT_TRUE(m2.Matches(L"Hi")); + EXPECT_TRUE(m2.Matches(L"Hi Hi!")); + EXPECT_TRUE(m2.Matches(L"High")); + EXPECT_FALSE(m2.Matches(L"H")); + EXPECT_FALSE(m2.Matches(L" Hi")); +} + +TEST(GlobalWideStartsWithTest, CanDescribeSelf) { + Matcher m = StartsWith(L"Hi"); + EXPECT_EQ("starts with L\"Hi\"", Describe(m)); +} + +// Tests EndsWith(s). + +TEST(GlobalWideEndsWithTest, MatchesStringWithGivenSuffix) { + const Matcher m1 = EndsWith(L""); + EXPECT_TRUE(m1.Matches(L"Hi")); + EXPECT_TRUE(m1.Matches(L"")); + EXPECT_FALSE(m1.Matches(NULL)); + + const Matcher m2 = EndsWith(::wstring(L"Hi")); + EXPECT_TRUE(m2.Matches(L"Hi")); + EXPECT_TRUE(m2.Matches(L"Wow Hi Hi")); + EXPECT_TRUE(m2.Matches(L"Super Hi")); + EXPECT_FALSE(m2.Matches(L"i")); + EXPECT_FALSE(m2.Matches(L"Hi ")); +} + +TEST(GlobalWideEndsWithTest, CanDescribeSelf) { + Matcher m = EndsWith(L"Hi"); + EXPECT_EQ("ends with L\"Hi\"", Describe(m)); +} + +#endif // GTEST_HAS_GLOBAL_WSTRING + + +typedef ::std::tr1::tuple Tuple2; // NOLINT + +// Tests that Eq() matches a 2-tuple where the first field == the +// second field. +TEST(Eq2Test, MatchesEqualArguments) { + Matcher m = Eq(); + EXPECT_TRUE(m.Matches(Tuple2(5L, 5))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 6))); +} + +// Tests that Eq() describes itself properly. +TEST(Eq2Test, CanDescribeSelf) { + Matcher m = Eq(); + EXPECT_EQ("argument #0 is equal to argument #1", Describe(m)); +} + +// Tests that Ge() matches a 2-tuple where the first field >= the +// second field. +TEST(Ge2Test, MatchesGreaterThanOrEqualArguments) { + Matcher m = Ge(); + EXPECT_TRUE(m.Matches(Tuple2(5L, 4))); + EXPECT_TRUE(m.Matches(Tuple2(5L, 5))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 6))); +} + +// Tests that Ge() describes itself properly. +TEST(Ge2Test, CanDescribeSelf) { + Matcher m = Ge(); + EXPECT_EQ("argument #0 is greater than or equal to argument #1", + Describe(m)); +} + +// Tests that Gt() matches a 2-tuple where the first field > the +// second field. +TEST(Gt2Test, MatchesGreaterThanArguments) { + Matcher m = Gt(); + EXPECT_TRUE(m.Matches(Tuple2(5L, 4))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 5))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 6))); +} + +// Tests that Gt() describes itself properly. +TEST(Gt2Test, CanDescribeSelf) { + Matcher m = Gt(); + EXPECT_EQ("argument #0 is greater than argument #1", Describe(m)); +} + +// Tests that Le() matches a 2-tuple where the first field <= the +// second field. +TEST(Le2Test, MatchesLessThanOrEqualArguments) { + Matcher m = Le(); + EXPECT_TRUE(m.Matches(Tuple2(5L, 6))); + EXPECT_TRUE(m.Matches(Tuple2(5L, 5))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 4))); +} + +// Tests that Le() describes itself properly. +TEST(Le2Test, CanDescribeSelf) { + Matcher m = Le(); + EXPECT_EQ("argument #0 is less than or equal to argument #1", + Describe(m)); +} + +// Tests that Lt() matches a 2-tuple where the first field < the +// second field. +TEST(Lt2Test, MatchesLessThanArguments) { + Matcher m = Lt(); + EXPECT_TRUE(m.Matches(Tuple2(5L, 6))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 5))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 4))); +} + +// Tests that Lt() describes itself properly. +TEST(Lt2Test, CanDescribeSelf) { + Matcher m = Lt(); + EXPECT_EQ("argument #0 is less than argument #1", Describe(m)); +} + +// Tests that Ne() matches a 2-tuple where the first field != the +// second field. +TEST(Ne2Test, MatchesUnequalArguments) { + Matcher m = Ne(); + EXPECT_TRUE(m.Matches(Tuple2(5L, 6))); + EXPECT_TRUE(m.Matches(Tuple2(5L, 4))); + EXPECT_FALSE(m.Matches(Tuple2(5L, 5))); +} + +// Tests that Ne() describes itself properly. +TEST(Ne2Test, CanDescribeSelf) { + Matcher m = Ne(); + EXPECT_EQ("argument #0 is not equal to argument #1", Describe(m)); +} + +// Tests that Not(m) matches any value that doesn't match m. +TEST(NotTest, NegatesMatcher) { + Matcher m; + m = Not(Eq(2)); + EXPECT_TRUE(m.Matches(3)); + EXPECT_FALSE(m.Matches(2)); +} + +// Tests that Not(m) describes itself properly. +TEST(NotTest, CanDescribeSelf) { + Matcher m = Not(Eq(5)); + EXPECT_EQ("is not equal to 5", Describe(m)); +} + +// Tests that AllOf(m1, ..., mn) matches any value that matches all of +// the given matchers. +TEST(AllOfTest, MatchesWhenAllMatch) { + Matcher m; + m = AllOf(Le(2), Ge(1)); + EXPECT_TRUE(m.Matches(1)); + EXPECT_TRUE(m.Matches(2)); + EXPECT_FALSE(m.Matches(0)); + EXPECT_FALSE(m.Matches(3)); + + m = AllOf(Gt(0), Ne(1), Ne(2)); + EXPECT_TRUE(m.Matches(3)); + EXPECT_FALSE(m.Matches(2)); + EXPECT_FALSE(m.Matches(1)); + EXPECT_FALSE(m.Matches(0)); + + m = AllOf(Gt(0), Ne(1), Ne(2), Ne(3)); + EXPECT_TRUE(m.Matches(4)); + EXPECT_FALSE(m.Matches(3)); + EXPECT_FALSE(m.Matches(2)); + EXPECT_FALSE(m.Matches(1)); + EXPECT_FALSE(m.Matches(0)); + + m = AllOf(Ge(0), Lt(10), Ne(3), Ne(5), Ne(7)); + EXPECT_TRUE(m.Matches(0)); + EXPECT_TRUE(m.Matches(1)); + EXPECT_FALSE(m.Matches(3)); +} + +// Tests that AllOf(m1, ..., mn) describes itself properly. +TEST(AllOfTest, CanDescribeSelf) { + Matcher m; + m = AllOf(Le(2), Ge(1)); + EXPECT_EQ("(is less than or equal to 2) and " + "(is greater than or equal to 1)", + Describe(m)); + + m = AllOf(Gt(0), Ne(1), Ne(2)); + EXPECT_EQ("(is greater than 0) and " + "((is not equal to 1) and " + "(is not equal to 2))", + Describe(m)); + + + m = AllOf(Gt(0), Ne(1), Ne(2), Ne(3)); + EXPECT_EQ("(is greater than 0) and " + "((is not equal to 1) and " + "((is not equal to 2) and " + "(is not equal to 3)))", + Describe(m)); + + + m = AllOf(Ge(0), Lt(10), Ne(3), Ne(5), Ne(7)); + EXPECT_EQ("(is greater than or equal to 0) and " + "((is less than 10) and " + "((is not equal to 3) and " + "((is not equal to 5) and " + "(is not equal to 7))))", Describe(m)); +} + +// Tests that AnyOf(m1, ..., mn) matches any value that matches at +// least one of the given matchers. +TEST(AnyOfTest, MatchesWhenAnyMatches) { + Matcher m; + m = AnyOf(Le(1), Ge(3)); + EXPECT_TRUE(m.Matches(1)); + EXPECT_TRUE(m.Matches(4)); + EXPECT_FALSE(m.Matches(2)); + + m = AnyOf(Lt(0), Eq(1), Eq(2)); + EXPECT_TRUE(m.Matches(-1)); + EXPECT_TRUE(m.Matches(1)); + EXPECT_TRUE(m.Matches(2)); + EXPECT_FALSE(m.Matches(0)); + + m = AnyOf(Lt(0), Eq(1), Eq(2), Eq(3)); + EXPECT_TRUE(m.Matches(-1)); + EXPECT_TRUE(m.Matches(1)); + EXPECT_TRUE(m.Matches(2)); + EXPECT_TRUE(m.Matches(3)); + EXPECT_FALSE(m.Matches(0)); + + m = AnyOf(Le(0), Gt(10), 3, 5, 7); + EXPECT_TRUE(m.Matches(0)); + EXPECT_TRUE(m.Matches(11)); + EXPECT_TRUE(m.Matches(3)); + EXPECT_FALSE(m.Matches(2)); +} + +// Tests that AnyOf(m1, ..., mn) describes itself properly. +TEST(AnyOfTest, CanDescribeSelf) { + Matcher m; + m = AnyOf(Le(1), Ge(3)); + EXPECT_EQ("(is less than or equal to 1) or " + "(is greater than or equal to 3)", + Describe(m)); + + m = AnyOf(Lt(0), Eq(1), Eq(2)); + EXPECT_EQ("(is less than 0) or " + "((is equal to 1) or (is equal to 2))", + Describe(m)); + + m = AnyOf(Lt(0), Eq(1), Eq(2), Eq(3)); + EXPECT_EQ("(is less than 0) or " + "((is equal to 1) or " + "((is equal to 2) or " + "(is equal to 3)))", + Describe(m)); + + m = AnyOf(Le(0), Gt(10), 3, 5, 7); + EXPECT_EQ("(is less than or equal to 0) or " + "((is greater than 10) or " + "((is equal to 3) or " + "((is equal to 5) or " + "(is equal to 7))))", + Describe(m)); +} + +// The following predicate function and predicate functor are for +// testing the Truly(predicate) matcher. + +// Returns non-zero if the input is positive. Note that the return +// type of this function is not bool. It's OK as Truly() accepts any +// unary function or functor whose return type can be implicitly +// converted to bool. +int IsPositive(double x) { + return x > 0 ? 1 : 0; +} + +// This functor returns true if the input is greater than the given +// number. +class IsGreaterThan { + public: + explicit IsGreaterThan(int threshold) : threshold_(threshold) {} + + bool operator()(int n) const { return n > threshold_; } + private: + const int threshold_; +}; + +// For testing Truly(). +const int foo = 0; + +// This predicate returns true iff the argument references foo and has +// a zero value. +bool ReferencesFooAndIsZero(const int& n) { + return (&n == &foo) && (n == 0); +} + +// Tests that Truly(predicate) matches what satisfies the given +// predicate. +TEST(TrulyTest, MatchesWhatSatisfiesThePredicate) { + Matcher m = Truly(IsPositive); + EXPECT_TRUE(m.Matches(2.0)); + EXPECT_FALSE(m.Matches(-1.5)); +} + +// Tests that Truly(predicate_functor) works too. +TEST(TrulyTest, CanBeUsedWithFunctor) { + Matcher m = Truly(IsGreaterThan(5)); + EXPECT_TRUE(m.Matches(6)); + EXPECT_FALSE(m.Matches(4)); +} + +// Tests that Truly(predicate) can describe itself properly. +TEST(TrulyTest, CanDescribeSelf) { + Matcher m = Truly(IsPositive); + EXPECT_EQ("satisfies the given predicate", + Describe(m)); +} + +// Tests that Truly(predicate) works when the matcher takes its +// argument by reference. +TEST(TrulyTest, WorksForByRefArguments) { + Matcher m = Truly(ReferencesFooAndIsZero); + EXPECT_TRUE(m.Matches(foo)); + int n = 0; + EXPECT_FALSE(m.Matches(n)); +} + +// Tests that Matches(m) is a predicate satisfied by whatever that +// matches matcher m. +TEST(MatchesTest, IsSatisfiedByWhatMatchesTheMatcher) { + EXPECT_TRUE(Matches(Ge(0))(1)); + EXPECT_FALSE(Matches(Eq('a'))('b')); +} + +// Tests that Matches(m) works when the matcher takes its argument by +// reference. +TEST(MatchesTest, WorksOnByRefArguments) { + int m = 0, n = 0; + EXPECT_TRUE(Matches(AllOf(Ref(n), Eq(0)))(n)); + EXPECT_FALSE(Matches(Ref(m))(n)); +} + +// Tests that a Matcher on non-reference type can be used in +// Matches(). +TEST(MatchesTest, WorksWithMatcherOnNonRefType) { + Matcher eq5 = Eq(5); + EXPECT_TRUE(Matches(eq5)(5)); + EXPECT_FALSE(Matches(eq5)(2)); +} + +// Tests that ASSERT_THAT() and EXPECT_THAT() work when the value +// matches the matcher. +TEST(MatcherAssertionTest, WorksWhenMatcherIsSatisfied) { + ASSERT_THAT(5, Ge(2)) << "This should succeed."; + ASSERT_THAT("Foo", EndsWith("oo")); + EXPECT_THAT(2, AllOf(Le(7), Ge(0))) << "This should succeed too."; + EXPECT_THAT("Hello", StartsWith("Hell")); +} + +// Tests that ASSERT_THAT() and EXPECT_THAT() work when the value +// doesn't match the matcher. +TEST(MatcherAssertionTest, WorksWhenMatcherIsNotSatisfied) { + // 'n' must be static as it is used in an EXPECT_FATAL_FAILURE(), + // which cannot reference auto variables. + static int n; + n = 5; + EXPECT_FATAL_FAILURE(ASSERT_THAT(n, Gt(10)) << "This should fail.", + "Value of: n\n" + "Expected: is greater than 10\n" + " Actual: 5\n" + "This should fail."); + n = 0; + EXPECT_NONFATAL_FAILURE(EXPECT_THAT(n, AllOf(Le(7), Ge(5))), + "Value of: n\n" + "Expected: (is less than or equal to 7) and " + "(is greater than or equal to 5)\n" + " Actual: 0"); +} + +// Tests that ASSERT_THAT() and EXPECT_THAT() work when the argument +// has a reference type. +TEST(MatcherAssertionTest, WorksForByRefArguments) { + // We use a static variable here as EXPECT_FATAL_FAILURE() cannot + // reference auto variables. + static int n; + n = 0; + EXPECT_THAT(n, AllOf(Le(7), Ref(n))); + EXPECT_FATAL_FAILURE(ASSERT_THAT(n, Not(Ref(n))), + "Value of: n\n" + "Expected: does not reference the variable @"); + // Tests the "Actual" part. + EXPECT_FATAL_FAILURE(ASSERT_THAT(n, Not(Ref(n))), + "Actual: 0 (is located @"); +} + +// Tests that ASSERT_THAT() and EXPECT_THAT() work when the matcher is +// monomorphic. +TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { + Matcher starts_with_he = StartsWith("he"); + ASSERT_THAT("hello", starts_with_he); + + Matcher ends_with_ok = EndsWith("ok"); + ASSERT_THAT("book", ends_with_ok); + + Matcher is_greater_than_5 = Gt(5); + EXPECT_NONFATAL_FAILURE(EXPECT_THAT(5, is_greater_than_5), + "Value of: 5\n" + "Expected: is greater than 5\n" + " Actual: 5"); +} + +// Tests floating-point matchers. +template +class FloatingPointTest : public testing::Test { + protected: + typedef typename testing::internal::FloatingPoint Floating; + typedef typename Floating::Bits Bits; + + virtual void SetUp() { + const size_t max_ulps = Floating::kMaxUlps; + + // The bits that represent 0.0. + const Bits zero_bits = Floating(0).bits(); + + // Makes some numbers close to 0.0. + close_to_positive_zero_ = Floating::ReinterpretBits(zero_bits + max_ulps/2); + close_to_negative_zero_ = -Floating::ReinterpretBits( + zero_bits + max_ulps - max_ulps/2); + further_from_negative_zero_ = -Floating::ReinterpretBits( + zero_bits + max_ulps + 1 - max_ulps/2); + + // The bits that represent 1.0. + const Bits one_bits = Floating(1).bits(); + + // Makes some numbers close to 1.0. + close_to_one_ = Floating::ReinterpretBits(one_bits + max_ulps); + further_from_one_ = Floating::ReinterpretBits(one_bits + max_ulps + 1); + + // +infinity. + infinity_ = Floating::Infinity(); + + // The bits that represent +infinity. + const Bits infinity_bits = Floating(infinity_).bits(); + + // Makes some numbers close to infinity. + close_to_infinity_ = Floating::ReinterpretBits(infinity_bits - max_ulps); + further_from_infinity_ = Floating::ReinterpretBits( + infinity_bits - max_ulps - 1); + + // Makes some NAN's. + nan1_ = Floating::ReinterpretBits(Floating::kExponentBitMask | 1); + nan2_ = Floating::ReinterpretBits(Floating::kExponentBitMask | 200); + } + + void TestSize() { + EXPECT_EQ(sizeof(RawType), sizeof(Bits)); + } + + // A battery of tests for FloatingEqMatcher::Matches. + // matcher_maker is a pointer to a function which creates a FloatingEqMatcher. + void TestMatches( + testing::internal::FloatingEqMatcher (*matcher_maker)(RawType)) { + Matcher m1 = matcher_maker(0.0); + EXPECT_TRUE(m1.Matches(-0.0)); + EXPECT_TRUE(m1.Matches(close_to_positive_zero_)); + EXPECT_TRUE(m1.Matches(close_to_negative_zero_)); + EXPECT_FALSE(m1.Matches(1.0)); + + Matcher m2 = matcher_maker(close_to_positive_zero_); + EXPECT_FALSE(m2.Matches(further_from_negative_zero_)); + + Matcher m3 = matcher_maker(1.0); + EXPECT_TRUE(m3.Matches(close_to_one_)); + EXPECT_FALSE(m3.Matches(further_from_one_)); + + // Test commutativity: matcher_maker(0.0).Matches(1.0) was tested above. + EXPECT_FALSE(m3.Matches(0.0)); + + Matcher m4 = matcher_maker(-infinity_); + EXPECT_TRUE(m4.Matches(-close_to_infinity_)); + + Matcher m5 = matcher_maker(infinity_); + EXPECT_TRUE(m5.Matches(close_to_infinity_)); + + // This is interesting as the representations of infinity_ and nan1_ + // are only 1 DLP apart. + EXPECT_FALSE(m5.Matches(nan1_)); + + // matcher_maker can produce a Matcher, which is needed in + // some cases. + Matcher m6 = matcher_maker(0.0); + EXPECT_TRUE(m6.Matches(-0.0)); + EXPECT_TRUE(m6.Matches(close_to_positive_zero_)); + EXPECT_FALSE(m6.Matches(1.0)); + + // matcher_maker can produce a Matcher, which is needed in some + // cases. + Matcher m7 = matcher_maker(0.0); + RawType x = 0.0; + EXPECT_TRUE(m7.Matches(x)); + x = 0.01f; + EXPECT_FALSE(m7.Matches(x)); + } + + // Pre-calculated numbers to be used by the tests. + + static RawType close_to_positive_zero_; + static RawType close_to_negative_zero_; + static RawType further_from_negative_zero_; + + static RawType close_to_one_; + static RawType further_from_one_; + + static RawType infinity_; + static RawType close_to_infinity_; + static RawType further_from_infinity_; + + static RawType nan1_; + static RawType nan2_; +}; + +template +RawType FloatingPointTest::close_to_positive_zero_; + +template +RawType FloatingPointTest::close_to_negative_zero_; + +template +RawType FloatingPointTest::further_from_negative_zero_; + +template +RawType FloatingPointTest::close_to_one_; + +template +RawType FloatingPointTest::further_from_one_; + +template +RawType FloatingPointTest::infinity_; + +template +RawType FloatingPointTest::close_to_infinity_; + +template +RawType FloatingPointTest::further_from_infinity_; + +template +RawType FloatingPointTest::nan1_; + +template +RawType FloatingPointTest::nan2_; + +// Instantiate FloatingPointTest for testing floats. +typedef FloatingPointTest FloatTest; + +TEST_F(FloatTest, FloatEqApproximatelyMatchesFloats) { + TestMatches(&FloatEq); +} + +TEST_F(FloatTest, NanSensitiveFloatEqApproximatelyMatchesFloats) { + TestMatches(&NanSensitiveFloatEq); +} + +TEST_F(FloatTest, FloatEqCannotMatchNaN) { + // FloatEq never matches NaN. + Matcher m = FloatEq(nan1_); + EXPECT_FALSE(m.Matches(nan1_)); + EXPECT_FALSE(m.Matches(nan2_)); + EXPECT_FALSE(m.Matches(1.0)); +} + +TEST_F(FloatTest, NanSensitiveFloatEqCanMatchNaN) { + // NanSensitiveFloatEq will match NaN. + Matcher m = NanSensitiveFloatEq(nan1_); + EXPECT_TRUE(m.Matches(nan1_)); + EXPECT_TRUE(m.Matches(nan2_)); + EXPECT_FALSE(m.Matches(1.0)); +} + +TEST_F(FloatTest, FloatEqCanDescribeSelf) { + Matcher m1 = FloatEq(2.0f); + EXPECT_EQ("is approximately 2", Describe(m1)); + EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + + Matcher m2 = FloatEq(0.5f); + EXPECT_EQ("is approximately 0.5", Describe(m2)); + EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + + Matcher m3 = FloatEq(nan1_); + EXPECT_EQ("never matches", Describe(m3)); + EXPECT_EQ("is anything", DescribeNegation(m3)); +} + +TEST_F(FloatTest, NanSensitiveFloatEqCanDescribeSelf) { + Matcher m1 = NanSensitiveFloatEq(2.0f); + EXPECT_EQ("is approximately 2", Describe(m1)); + EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + + Matcher m2 = NanSensitiveFloatEq(0.5f); + EXPECT_EQ("is approximately 0.5", Describe(m2)); + EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + + Matcher m3 = NanSensitiveFloatEq(nan1_); + EXPECT_EQ("is NaN", Describe(m3)); + EXPECT_EQ("is not NaN", DescribeNegation(m3)); +} + +// Instantiate FloatingPointTest for testing doubles. +typedef FloatingPointTest DoubleTest; + +TEST_F(DoubleTest, DoubleEqApproximatelyMatchesDoubles) { + TestMatches(&DoubleEq); +} + +TEST_F(DoubleTest, NanSensitiveDoubleEqApproximatelyMatchesDoubles) { + TestMatches(&NanSensitiveDoubleEq); +} + +TEST_F(DoubleTest, DoubleEqCannotMatchNaN) { + // DoubleEq never matches NaN. + Matcher m = DoubleEq(nan1_); + EXPECT_FALSE(m.Matches(nan1_)); + EXPECT_FALSE(m.Matches(nan2_)); + EXPECT_FALSE(m.Matches(1.0)); +} + +TEST_F(DoubleTest, NanSensitiveDoubleEqCanMatchNaN) { + // NanSensitiveDoubleEq will match NaN. + Matcher m = NanSensitiveDoubleEq(nan1_); + EXPECT_TRUE(m.Matches(nan1_)); + EXPECT_TRUE(m.Matches(nan2_)); + EXPECT_FALSE(m.Matches(1.0)); +} + +TEST_F(DoubleTest, DoubleEqCanDescribeSelf) { + Matcher m1 = DoubleEq(2.0); + EXPECT_EQ("is approximately 2", Describe(m1)); + EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + + Matcher m2 = DoubleEq(0.5); + EXPECT_EQ("is approximately 0.5", Describe(m2)); + EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + + Matcher m3 = DoubleEq(nan1_); + EXPECT_EQ("never matches", Describe(m3)); + EXPECT_EQ("is anything", DescribeNegation(m3)); +} + +TEST_F(DoubleTest, NanSensitiveDoubleEqCanDescribeSelf) { + Matcher m1 = NanSensitiveDoubleEq(2.0); + EXPECT_EQ("is approximately 2", Describe(m1)); + EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + + Matcher m2 = NanSensitiveDoubleEq(0.5); + EXPECT_EQ("is approximately 0.5", Describe(m2)); + EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + + Matcher m3 = NanSensitiveDoubleEq(nan1_); + EXPECT_EQ("is NaN", Describe(m3)); + EXPECT_EQ("is not NaN", DescribeNegation(m3)); +} + +TEST(PointeeTest, RawPointer) { + const Matcher m = Pointee(Ge(0)); + + int n = 1; + EXPECT_TRUE(m.Matches(&n)); + n = -1; + EXPECT_FALSE(m.Matches(&n)); + EXPECT_FALSE(m.Matches(NULL)); +} + +TEST(PointeeTest, RawPointerToConst) { + const Matcher m = Pointee(Ge(0)); + + double x = 1; + EXPECT_TRUE(m.Matches(&x)); + x = -1; + EXPECT_FALSE(m.Matches(&x)); + EXPECT_FALSE(m.Matches(NULL)); +} + +TEST(PointeeTest, ReferenceToConstRawPointer) { + const Matcher m = Pointee(Ge(0)); + + int n = 1; + EXPECT_TRUE(m.Matches(&n)); + n = -1; + EXPECT_FALSE(m.Matches(&n)); + EXPECT_FALSE(m.Matches(NULL)); +} + +TEST(PointeeTest, ReferenceToNonConstRawPointer) { + const Matcher m = Pointee(Ge(0)); + + double x = 1.0; + double* p = &x; + EXPECT_TRUE(m.Matches(p)); + x = -1; + EXPECT_FALSE(m.Matches(p)); + p = NULL; + EXPECT_FALSE(m.Matches(p)); +} + +TEST(PointeeTest, NeverMatchesNull) { + const Matcher m = Pointee(_); + EXPECT_FALSE(m.Matches(NULL)); +} + +// Tests that we can write Pointee(value) instead of Pointee(Eq(value)). +TEST(PointeeTest, MatchesAgainstAValue) { + const Matcher m = Pointee(5); + + int n = 5; + EXPECT_TRUE(m.Matches(&n)); + n = -1; + EXPECT_FALSE(m.Matches(&n)); + EXPECT_FALSE(m.Matches(NULL)); +} + +TEST(PointeeTest, CanDescribeSelf) { + const Matcher m = Pointee(Gt(3)); + EXPECT_EQ("points to a value that is greater than 3", Describe(m)); + EXPECT_EQ("does not point to a value that is greater than 3", + DescribeNegation(m)); +} + +// For testing ExplainMatchResultTo(). +class GreaterThanMatcher : public MatcherInterface { + public: + explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} + + virtual bool Matches(int lhs) const { return lhs > rhs_; } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is greater than " << rhs_; + } + + virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { + const int diff = lhs - rhs_; + if (diff > 0) { + *os << "is " << diff << " more than " << rhs_; + } else if (diff == 0) { + *os << "is the same as " << rhs_; + } else { + *os << "is " << -diff << " less than " << rhs_; + } + } + private: + const int rhs_; +}; + +Matcher GreaterThan(int n) { + return MakeMatcher(new GreaterThanMatcher(n)); +} + +TEST(PointeeTest, CanExplainMatchResult) { + const Matcher m = Pointee(StartsWith("Hi")); + + EXPECT_EQ("", Explain(m, static_cast(NULL))); + + const Matcher m2 = Pointee(GreaterThan(1)); + int n = 3; + EXPECT_EQ("points to a value that is 2 more than 1", Explain(m2, &n)); +} + +// An uncopyable class. +class Uncopyable { + public: + explicit Uncopyable(int value) : value_(value) {} + + int value() const { return value_; } + private: + const int value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Uncopyable); +}; + +// Returns true iff x.value() is positive. +bool ValueIsPositive(const Uncopyable& x) { return x.value() > 0; } + +// A user-defined struct for testing Field(). +struct AStruct { + AStruct() : x(0), y(1.0), z(5), p(NULL) {} + AStruct(const AStruct& rhs) + : x(rhs.x), y(rhs.y), z(rhs.z.value()), p(rhs.p) {} + + int x; // A non-const field. + const double y; // A const field. + Uncopyable z; // An uncopyable field. + const char* p; // A pointer field. +}; + +// A derived struct for testing Field(). +struct DerivedStruct : public AStruct { + char ch; +}; + +// Tests that Field(&Foo::field, ...) works when field is non-const. +TEST(FieldTest, WorksForNonConstField) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + EXPECT_TRUE(m.Matches(a)); + a.x = -1; + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Field(&Foo::field, ...) works when field is const. +TEST(FieldTest, WorksForConstField) { + AStruct a; + + Matcher m = Field(&AStruct::y, Ge(0.0)); + EXPECT_TRUE(m.Matches(a)); + m = Field(&AStruct::y, Le(0.0)); + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Field(&Foo::field, ...) works when field is not copyable. +TEST(FieldTest, WorksForUncopyableField) { + AStruct a; + + Matcher m = Field(&AStruct::z, Truly(ValueIsPositive)); + EXPECT_TRUE(m.Matches(a)); + m = Field(&AStruct::z, Not(Truly(ValueIsPositive))); + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Field(&Foo::field, ...) works when field is a pointer. +TEST(FieldTest, WorksForPointerField) { + // Matching against NULL. + Matcher m = Field(&AStruct::p, static_cast(NULL)); + AStruct a; + EXPECT_TRUE(m.Matches(a)); + a.p = "hi"; + EXPECT_FALSE(m.Matches(a)); + + // Matching a pointer that is not NULL. + m = Field(&AStruct::p, StartsWith("hi")); + a.p = "hill"; + EXPECT_TRUE(m.Matches(a)); + a.p = "hole"; + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Field() works when the object is passed by reference. +TEST(FieldTest, WorksForByRefArgument) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + EXPECT_TRUE(m.Matches(a)); + a.x = -1; + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Field(&Foo::field, ...) works when the argument's type +// is a sub-type of Foo. +TEST(FieldTest, WorksForArgumentOfSubType) { + // Note that the matcher expects DerivedStruct but we say AStruct + // inside Field(). + Matcher m = Field(&AStruct::x, Ge(0)); + + DerivedStruct d; + EXPECT_TRUE(m.Matches(d)); + d.x = -1; + EXPECT_FALSE(m.Matches(d)); +} + +// Tests that Field(&Foo::field, m) works when field's type and m's +// argument type are compatible but not the same. +TEST(FieldTest, WorksForCompatibleMatcherType) { + // The field is an int, but the inner matcher expects a signed char. + Matcher m = Field(&AStruct::x, + Matcher(Ge(0))); + + AStruct a; + EXPECT_TRUE(m.Matches(a)); + a.x = -1; + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Field() can describe itself. +TEST(FieldTest, CanDescribeSelf) { + Matcher m = Field(&AStruct::x, Ge(0)); + + EXPECT_EQ("the given field is greater than or equal to 0", Describe(m)); + EXPECT_EQ("the given field is not greater than or equal to 0", + DescribeNegation(m)); +} + +// Tests that Field() can explain the match result. +TEST(FieldTest, CanExplainMatchResult) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + a.x = 1; + EXPECT_EQ("", Explain(m, a)); + + m = Field(&AStruct::x, GreaterThan(0)); + EXPECT_EQ("the given field is 1 more than 0", Explain(m, a)); +} + +// Tests that Field() works when the argument is a pointer to const. +TEST(FieldForPointerTest, WorksForPointerToConst) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + EXPECT_TRUE(m.Matches(&a)); + a.x = -1; + EXPECT_FALSE(m.Matches(&a)); +} + +// Tests that Field() works when the argument is a pointer to non-const. +TEST(FieldForPointerTest, WorksForPointerToNonConst) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + EXPECT_TRUE(m.Matches(&a)); + a.x = -1; + EXPECT_FALSE(m.Matches(&a)); +} + +// Tests that Field() does not match the NULL pointer. +TEST(FieldForPointerTest, DoesNotMatchNull) { + Matcher m = Field(&AStruct::x, _); + EXPECT_FALSE(m.Matches(NULL)); +} + +// Tests that Field(&Foo::field, ...) works when the argument's type +// is a sub-type of const Foo*. +TEST(FieldForPointerTest, WorksForArgumentOfSubType) { + // Note that the matcher expects DerivedStruct but we say AStruct + // inside Field(). + Matcher m = Field(&AStruct::x, Ge(0)); + + DerivedStruct d; + EXPECT_TRUE(m.Matches(&d)); + d.x = -1; + EXPECT_FALSE(m.Matches(&d)); +} + +// Tests that Field() can describe itself when used to match a pointer. +TEST(FieldForPointerTest, CanDescribeSelf) { + Matcher m = Field(&AStruct::x, Ge(0)); + + EXPECT_EQ("the given field is greater than or equal to 0", Describe(m)); + EXPECT_EQ("the given field is not greater than or equal to 0", + DescribeNegation(m)); +} + +// Tests that Field() can explain the result of matching a pointer. +TEST(FieldForPointerTest, CanExplainMatchResult) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + a.x = 1; + EXPECT_EQ("", Explain(m, static_cast(NULL))); + EXPECT_EQ("", Explain(m, &a)); + + m = Field(&AStruct::x, GreaterThan(0)); + EXPECT_EQ("the given field is 1 more than 0", Explain(m, &a)); +} + +// A user-defined class for testing Property(). +class AClass { + public: + AClass() : n_(0) {} + + // A getter that returns a non-reference. + int n() const { return n_; } + + void set_n(int new_n) { n_ = new_n; } + + // A getter that returns a reference to const. + const string& s() const { return s_; } + + void set_s(const string& new_s) { s_ = new_s; } + + // A getter that returns a reference to non-const. + double& x() const { return x_; } + private: + int n_; + string s_; + + static double x_; +}; + +double AClass::x_ = 0.0; + +// A derived class for testing Property(). +class DerivedClass : public AClass { + private: + int k_; +}; + +// Tests that Property(&Foo::property, ...) works when property() +// returns a non-reference. +TEST(PropertyTest, WorksForNonReferenceProperty) { + Matcher m = Property(&AClass::n, Ge(0)); + + AClass a; + a.set_n(1); + EXPECT_TRUE(m.Matches(a)); + + a.set_n(-1); + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Property(&Foo::property, ...) works when property() +// returns a reference to const. +TEST(PropertyTest, WorksForReferenceToConstProperty) { + Matcher m = Property(&AClass::s, StartsWith("hi")); + + AClass a; + a.set_s("hill"); + EXPECT_TRUE(m.Matches(a)); + + a.set_s("hole"); + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Property(&Foo::property, ...) works when property() +// returns a reference to non-const. +TEST(PropertyTest, WorksForReferenceToNonConstProperty) { + double x = 0.0; + AClass a; + + Matcher m = Property(&AClass::x, Ref(x)); + EXPECT_FALSE(m.Matches(a)); + + m = Property(&AClass::x, Not(Ref(x))); + EXPECT_TRUE(m.Matches(a)); +} + +// Tests that Property(&Foo::property, ...) works when the argument is +// passed by value. +TEST(PropertyTest, WorksForByValueArgument) { + Matcher m = Property(&AClass::s, StartsWith("hi")); + + AClass a; + a.set_s("hill"); + EXPECT_TRUE(m.Matches(a)); + + a.set_s("hole"); + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Property(&Foo::property, ...) works when the argument's +// type is a sub-type of Foo. +TEST(PropertyTest, WorksForArgumentOfSubType) { + // The matcher expects a DerivedClass, but inside the Property() we + // say AClass. + Matcher m = Property(&AClass::n, Ge(0)); + + DerivedClass d; + d.set_n(1); + EXPECT_TRUE(m.Matches(d)); + + d.set_n(-1); + EXPECT_FALSE(m.Matches(d)); +} + +// Tests that Property(&Foo::property, m) works when property()'s type +// and m's argument type are compatible but different. +TEST(PropertyTest, WorksForCompatibleMatcherType) { + // n() returns an int but the inner matcher expects a signed char. + Matcher m = Property(&AClass::n, + Matcher(Ge(0))); + + AClass a; + EXPECT_TRUE(m.Matches(a)); + a.set_n(-1); + EXPECT_FALSE(m.Matches(a)); +} + +// Tests that Property() can describe itself. +TEST(PropertyTest, CanDescribeSelf) { + Matcher m = Property(&AClass::n, Ge(0)); + + EXPECT_EQ("the given property is greater than or equal to 0", Describe(m)); + EXPECT_EQ("the given property is not greater than or equal to 0", + DescribeNegation(m)); +} + +// Tests that Property() can explain the match result. +TEST(PropertyTest, CanExplainMatchResult) { + Matcher m = Property(&AClass::n, Ge(0)); + + AClass a; + a.set_n(1); + EXPECT_EQ("", Explain(m, a)); + + m = Property(&AClass::n, GreaterThan(0)); + EXPECT_EQ("the given property is 1 more than 0", Explain(m, a)); +} + +// Tests that Property() works when the argument is a pointer to const. +TEST(PropertyForPointerTest, WorksForPointerToConst) { + Matcher m = Property(&AClass::n, Ge(0)); + + AClass a; + a.set_n(1); + EXPECT_TRUE(m.Matches(&a)); + + a.set_n(-1); + EXPECT_FALSE(m.Matches(&a)); +} + +// Tests that Property() works when the argument is a pointer to non-const. +TEST(PropertyForPointerTest, WorksForPointerToNonConst) { + Matcher m = Property(&AClass::s, StartsWith("hi")); + + AClass a; + a.set_s("hill"); + EXPECT_TRUE(m.Matches(&a)); + + a.set_s("hole"); + EXPECT_FALSE(m.Matches(&a)); +} + +// Tests that Property() does not match the NULL pointer. +TEST(PropertyForPointerTest, WorksForReferenceToNonConstProperty) { + Matcher m = Property(&AClass::x, _); + EXPECT_FALSE(m.Matches(NULL)); +} + +// Tests that Property(&Foo::property, ...) works when the argument's +// type is a sub-type of const Foo*. +TEST(PropertyForPointerTest, WorksForArgumentOfSubType) { + // The matcher expects a DerivedClass, but inside the Property() we + // say AClass. + Matcher m = Property(&AClass::n, Ge(0)); + + DerivedClass d; + d.set_n(1); + EXPECT_TRUE(m.Matches(&d)); + + d.set_n(-1); + EXPECT_FALSE(m.Matches(&d)); +} + +// Tests that Property() can describe itself when used to match a pointer. +TEST(PropertyForPointerTest, CanDescribeSelf) { + Matcher m = Property(&AClass::n, Ge(0)); + + EXPECT_EQ("the given property is greater than or equal to 0", Describe(m)); + EXPECT_EQ("the given property is not greater than or equal to 0", + DescribeNegation(m)); +} + +// Tests that Property() can explain the result of matching a pointer. +TEST(PropertyForPointerTest, CanExplainMatchResult) { + Matcher m = Property(&AClass::n, Ge(0)); + + AClass a; + a.set_n(1); + EXPECT_EQ("", Explain(m, static_cast(NULL))); + EXPECT_EQ("", Explain(m, &a)); + + m = Property(&AClass::n, GreaterThan(0)); + EXPECT_EQ("the given property is 1 more than 0", Explain(m, &a)); +} + +// Tests ResultOf. + +// Tests that ResultOf(f, ...) compiles and works as expected when f is a +// function pointer. +string IntToStringFunction(int input) { return input == 1 ? "foo" : "bar"; } + +TEST(ResultOfTest, WorksForFunctionPointers) { + Matcher matcher = ResultOf(&IntToStringFunction, Eq(string("foo"))); + + EXPECT_TRUE(matcher.Matches(1)); + EXPECT_FALSE(matcher.Matches(2)); +} + +// Tests that ResultOf() can describe itself. +TEST(ResultOfTest, CanDescribeItself) { + Matcher matcher = ResultOf(&IntToStringFunction, StrEq("foo")); + + EXPECT_EQ("result of the given callable is equal to \"foo\"", + Describe(matcher)); + EXPECT_EQ("result of the given callable is not equal to \"foo\"", + DescribeNegation(matcher)); +} + +// Tests that ResultOf() can explain the match result. +int IntFunction(int input) { return input == 42 ? 80 : 90; } + +TEST(ResultOfTest, CanExplainMatchResult) { + Matcher matcher = ResultOf(&IntFunction, Ge(85)); + EXPECT_EQ("", Explain(matcher, 36)); + + matcher = ResultOf(&IntFunction, GreaterThan(85)); + EXPECT_EQ("result of the given callable is 5 more than 85", + Explain(matcher, 36)); +} + +// Tests that ResultOf(f, ...) compiles and works as expected when f(x) +// returns a non-reference. +TEST(ResultOfTest, WorksForNonReferenceResults) { + Matcher matcher = ResultOf(&IntFunction, Eq(80)); + + EXPECT_TRUE(matcher.Matches(42)); + EXPECT_FALSE(matcher.Matches(36)); +} + +// Tests that ResultOf(f, ...) compiles and works as expected when f(x) +// returns a reference to non-const. +double& DoubleFunction(double& input) { return input; } + +Uncopyable& RefUncopyableFunction(Uncopyable& obj) { + return obj; +} + +TEST(ResultOfTest, WorksForReferenceToNonConstResults) { + double x = 3.14; + double x2 = x; + Matcher matcher = ResultOf(&DoubleFunction, Ref(x)); + + EXPECT_TRUE(matcher.Matches(x)); + EXPECT_FALSE(matcher.Matches(x2)); + + // Test that ResultOf works with uncopyable objects + Uncopyable obj(0); + Uncopyable obj2(0); + Matcher matcher2 = + ResultOf(&RefUncopyableFunction, Ref(obj)); + + EXPECT_TRUE(matcher2.Matches(obj)); + EXPECT_FALSE(matcher2.Matches(obj2)); +} + +// Tests that ResultOf(f, ...) compiles and works as expected when f(x) +// returns a reference to const. +const string& StringFunction(const string& input) { return input; } + +TEST(ResultOfTest, WorksForReferenceToConstResults) { + string s = "foo"; + string s2 = s; + Matcher matcher = ResultOf(&StringFunction, Ref(s)); + + EXPECT_TRUE(matcher.Matches(s)); + EXPECT_FALSE(matcher.Matches(s2)); +} + +// Tests that ResultOf(f, m) works when f(x) and m's +// argument types are compatible but different. +TEST(ResultOfTest, WorksForCompatibleMatcherTypes) { + // IntFunction() returns int but the inner matcher expects a signed char. + Matcher matcher = ResultOf(IntFunction, Matcher(Ge(85))); + + EXPECT_TRUE(matcher.Matches(36)); + EXPECT_FALSE(matcher.Matches(42)); +} + +#ifdef GTEST_HAS_DEATH_TEST +// Tests that the program aborts when ResultOf is passed +// a NULL function pointer. +TEST(ResultOfDeathTest, DiesOnNullFunctionPointers) { + EXPECT_DEATH( + ResultOf(static_cast(NULL), Eq(string("foo"))), + "NULL function pointer is passed into ResultOf\\(\\)\\."); +} +#endif // GTEST_HAS_DEATH_TEST + +// Tests that ResultOf(f, ...) compiles and works as expected when f is a +// function reference. +TEST(ResultOfTest, WorksForFunctionReferences) { + Matcher matcher = ResultOf(IntToStringFunction, StrEq("foo")); + EXPECT_TRUE(matcher.Matches(1)); + EXPECT_FALSE(matcher.Matches(2)); +} + +// Tests that ResultOf(f, ...) compiles and works as expected when f is a +// function object. +struct Functor : public ::std::unary_function { + result_type operator()(argument_type input) const { + return IntToStringFunction(input); + } +}; + +TEST(ResultOfTest, WorksForFunctors) { + Matcher matcher = ResultOf(Functor(), Eq(string("foo"))); + + EXPECT_TRUE(matcher.Matches(1)); + EXPECT_FALSE(matcher.Matches(2)); +} + +// Tests that ResultOf(f, ...) compiles and works as expected when f is a +// functor with more then one operator() defined. ResultOf() must work +// for each defined operator(). +struct PolymorphicFunctor { + typedef int result_type; + int operator()(int n) { return n; } + int operator()(const char* s) { return static_cast(strlen(s)); } +}; + +TEST(ResultOfTest, WorksForPolymorphicFunctors) { + Matcher matcher_int = ResultOf(PolymorphicFunctor(), Ge(5)); + + EXPECT_TRUE(matcher_int.Matches(10)); + EXPECT_FALSE(matcher_int.Matches(2)); + + Matcher matcher_string = ResultOf(PolymorphicFunctor(), Ge(5)); + + EXPECT_TRUE(matcher_string.Matches("long string")); + EXPECT_FALSE(matcher_string.Matches("shrt")); +} + +const int* ReferencingFunction(const int& n) { return &n; } + +struct ReferencingFunctor { + typedef const int* result_type; + result_type operator()(const int& n) { return &n; } +}; + +TEST(ResultOfTest, WorksForReferencingCallables) { + const int n = 1; + const int n2 = 1; + Matcher matcher2 = ResultOf(ReferencingFunction, Eq(&n)); + EXPECT_TRUE(matcher2.Matches(n)); + EXPECT_FALSE(matcher2.Matches(n2)); + + Matcher matcher3 = ResultOf(ReferencingFunctor(), Eq(&n)); + EXPECT_TRUE(matcher3.Matches(n)); + EXPECT_FALSE(matcher3.Matches(n2)); +} + + +class DivisibleByImpl { + public: + explicit DivisibleByImpl(int divider) : divider_(divider) {} + + template + bool Matches(const T& n) const { + return (n % divider_) == 0; + } + + void DescribeTo(::std::ostream* os) const { + *os << "is divisible by " << divider_; + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "is not divisible by " << divider_; + } + + int divider() const { return divider_; } + private: + const int divider_; +}; + +// For testing using ExplainMatchResultTo() with polymorphic matchers. +template +void ExplainMatchResultTo(const DivisibleByImpl& impl, const T& n, + ::std::ostream* os) { + *os << "is " << (n % impl.divider()) << " modulo " + << impl.divider(); +} + +PolymorphicMatcher DivisibleBy(int n) { + return MakePolymorphicMatcher(DivisibleByImpl(n)); +} + +// Tests that when AllOf() fails, only the first failing matcher is +// asked to explain why. +TEST(ExplainMatchResultTest, AllOf_False_False) { + const Matcher m = AllOf(DivisibleBy(4), DivisibleBy(3)); + EXPECT_EQ("is 1 modulo 4", Explain(m, 5)); +} + +// Tests that when AllOf() fails, only the first failing matcher is +// asked to explain why. +TEST(ExplainMatchResultTest, AllOf_False_True) { + const Matcher m = AllOf(DivisibleBy(4), DivisibleBy(3)); + EXPECT_EQ("is 2 modulo 4", Explain(m, 6)); +} + +// Tests that when AllOf() fails, only the first failing matcher is +// asked to explain why. +TEST(ExplainMatchResultTest, AllOf_True_False) { + const Matcher m = AllOf(Ge(1), DivisibleBy(3)); + EXPECT_EQ("is 2 modulo 3", Explain(m, 5)); +} + +// Tests that when AllOf() succeeds, all matchers are asked to explain +// why. +TEST(ExplainMatchResultTest, AllOf_True_True) { + const Matcher m = AllOf(DivisibleBy(2), DivisibleBy(3)); + EXPECT_EQ("is 0 modulo 2; is 0 modulo 3", Explain(m, 6)); +} + +TEST(ExplainMatchResultTest, AllOf_True_True_2) { + const Matcher m = AllOf(Ge(2), Le(3)); + EXPECT_EQ("", Explain(m, 2)); +} + +TEST(ExplainmatcherResultTest, MonomorphicMatcher) { + const Matcher m = GreaterThan(5); + EXPECT_EQ("is 1 more than 5", Explain(m, 6)); +} + +// The following two tests verify that values without a public copy +// ctor can be used as arguments to matchers like Eq(), Ge(), and etc +// with the help of ByRef(). + +class NotCopyable { + public: + explicit NotCopyable(int value) : value_(value) {} + + int value() const { return value_; } + + bool operator==(const NotCopyable& rhs) const { + return value() == rhs.value(); + } + + bool operator>=(const NotCopyable& rhs) const { + return value() >= rhs.value(); + } + private: + int value_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(NotCopyable); +}; + +TEST(ByRefTest, AllowsNotCopyableConstValueInMatchers) { + const NotCopyable const_value1(1); + const Matcher m = Eq(ByRef(const_value1)); + + const NotCopyable n1(1), n2(2); + EXPECT_TRUE(m.Matches(n1)); + EXPECT_FALSE(m.Matches(n2)); +} + +TEST(ByRefTest, AllowsNotCopyableValueInMatchers) { + NotCopyable value2(2); + const Matcher m = Ge(ByRef(value2)); + + NotCopyable n1(1), n2(2); + EXPECT_FALSE(m.Matches(n1)); + EXPECT_TRUE(m.Matches(n2)); +} + +} // namespace gmock_matchers_test +} // namespace testing diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc new file mode 100644 index 00000000..955961c5 --- /dev/null +++ b/test/gmock-nice-strict_test.cc @@ -0,0 +1,228 @@ +// 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) + +#include + +#include +#include +#include +#include + +namespace testing { +namespace gmock_nice_strict_test { + +using testing::internal::string; +using testing::GMOCK_FLAG(verbose); +using testing::HasSubstr; +using testing::NiceMock; +using testing::StrictMock; + +// Defines some mock classes needed by the tests. + +class Foo { + public: + virtual ~Foo() {} + + virtual void DoThis() = 0; + virtual int DoThat(bool flag) = 0; +}; + +class MockFoo : public Foo { + public: + void Delete() { delete this; } + + MOCK_METHOD0(DoThis, void()); + MOCK_METHOD1(DoThat, int(bool flag)); +}; + +class MockBar { + public: + explicit MockBar(const string& s) : str_(s) {} + + MockBar(char a1, char a2, string a3, string a4, int a5, int a6, + const string& a7, const string& a8, bool a9, bool a10) { + str_ = string() + a1 + a2 + a3 + a4 + static_cast(a5) + + static_cast(a6) + a7 + a8 + (a9 ? 'T' : 'F') + (a10 ? 'T' : 'F'); + } + + virtual ~MockBar() {} + + const string& str() const { return str_; } + + MOCK_METHOD0(This, int()); + MOCK_METHOD2(That, string(int, bool)); + + private: + string str_; +}; + +// TODO(wan@google.com): find a way to re-enable these tests. +#if 0 + +// Tests that a nice mock generates no warning for uninteresting calls. +TEST(NiceMockTest, NoWarningForUninterestingCall) { + NiceMock nice_foo; + + CaptureTestStdout(); + nice_foo.DoThis(); + nice_foo.DoThat(true); + EXPECT_EQ("", GetCapturedTestStdout()); +} + +// Tests that a nice mock generates no warning for uninteresting calls +// that delete the mock object. +TEST(NiceMockTest, NoWarningForUninterestingCallAfterDeath) { + NiceMock* const nice_foo = new NiceMock; + + ON_CALL(*nice_foo, DoThis()) + .WillByDefault(Invoke(nice_foo, &MockFoo::Delete)); + + CaptureTestStdout(); + nice_foo->DoThis(); + EXPECT_EQ("", GetCapturedTestStdout()); +} + +// Tests that a nice mock generates informational logs for +// uninteresting calls. +TEST(NiceMockTest, InfoForUninterestingCall) { + NiceMock nice_foo; + + GMOCK_FLAG(verbose) = "info"; + CaptureTestStdout(); + nice_foo.DoThis(); + EXPECT_THAT(GetCapturedTestStdout(), + HasSubstr("Uninteresting mock function call")); + + CaptureTestStdout(); + nice_foo.DoThat(true); + EXPECT_THAT(GetCapturedTestStdout(), + HasSubstr("Uninteresting mock function call")); +} + +#endif // 0 + +// Tests that a nice mock allows expected calls. +TEST(NiceMockTest, AllowsExpectedCall) { + NiceMock nice_foo; + + EXPECT_CALL(nice_foo, DoThis()); + nice_foo.DoThis(); +} + +// Tests that an unexpected call on a nice mock fails. +TEST(NiceMockTest, UnexpectedCallFails) { + NiceMock nice_foo; + + EXPECT_CALL(nice_foo, DoThis()).Times(0); + EXPECT_NONFATAL_FAILURE(nice_foo.DoThis(), "called more times than expected"); +} + +// Tests that NiceMock works with a mock class that has a non-default +// constructor. +TEST(NiceMockTest, NonDefaultConstructor) { + NiceMock nice_bar("hi"); + EXPECT_EQ("hi", nice_bar.str()); + + nice_bar.This(); + nice_bar.That(5, true); +} + +// Tests that NiceMock works with a mock class that has a 10-ary +// non-default constructor. +TEST(NiceMockTest, NonDefaultConstructor10) { + NiceMock nice_bar('a', 'b', "c", "d", 'e', 'f', + "g", "h", true, false); + EXPECT_EQ("abcdefghTF", nice_bar.str()); + + nice_bar.This(); + nice_bar.That(5, true); +} + +// Tests that a strict mock allows expected calls. +TEST(StrictMockTest, AllowsExpectedCall) { + StrictMock strict_foo; + + EXPECT_CALL(strict_foo, DoThis()); + strict_foo.DoThis(); +} + +// Tests that an unexpected call on a strict mock fails. +TEST(StrictMockTest, UnexpectedCallFails) { + StrictMock strict_foo; + + EXPECT_CALL(strict_foo, DoThis()).Times(0); + EXPECT_NONFATAL_FAILURE(strict_foo.DoThis(), + "called more times than expected"); +} + +// Tests that an uninteresting call on a strict mock fails. +TEST(StrictMockTest, UninterestingCallFails) { + StrictMock strict_foo; + + EXPECT_NONFATAL_FAILURE(strict_foo.DoThis(), + "Uninteresting mock function call"); +} + +// Tests that an uninteresting call on a strict mock fails, even if +// the call deletes the mock object. +TEST(StrictMockTest, UninterestingCallFailsAfterDeath) { + StrictMock* const strict_foo = new StrictMock; + + ON_CALL(*strict_foo, DoThis()) + .WillByDefault(Invoke(strict_foo, &MockFoo::Delete)); + + EXPECT_NONFATAL_FAILURE(strict_foo->DoThis(), + "Uninteresting mock function call"); +} + +// Tests that StrictMock works with a mock class that has a +// non-default constructor. +TEST(StrictMockTest, NonDefaultConstructor) { + StrictMock strict_bar("hi"); + EXPECT_EQ("hi", strict_bar.str()); + + EXPECT_NONFATAL_FAILURE(strict_bar.That(5, true), + "Uninteresting mock function call"); +} + +// Tests that StrictMock works with a mock class that has a 10-ary +// non-default constructor. +TEST(StrictMockTest, NonDefaultConstructor10) { + StrictMock strict_bar('a', 'b', "c", "d", 'e', 'f', + "g", "h", true, false); + EXPECT_EQ("abcdefghTF", strict_bar.str()); + + EXPECT_NONFATAL_FAILURE(strict_bar.That(5, true), + "Uninteresting mock function call"); +} + +} // namespace gmock_nice_strict_test +} // namespace testing diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc new file mode 100644 index 00000000..f35bc115 --- /dev/null +++ b/test/gmock-port_test.cc @@ -0,0 +1,95 @@ +// 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: vladl@google.com (Vlad Losev) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file tests the internal cross-platform support utilities. + +#include +#include + +TEST(GmockCheckSyntaxTest, BehavesLikeASingleStatement) { + if (false) + GMOCK_CHECK_(false) << "This should never be executed; " + "It's a compilation test only."; + + if (true) + GMOCK_CHECK_(true); + else + ; + + if (false) + ; + else + GMOCK_CHECK_(true) << ""; +} + +TEST(GmockCheckSyntaxTest, WorksWithSwitch) { + switch (0) { + case 1: + break; + default: + GMOCK_CHECK_(true); + } + + switch(0) + case 0: + GMOCK_CHECK_(true) << "Check failed in switch case"; +} + +#ifdef GTEST_HAS_DEATH_TEST + +TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { + const bool a_false_condition = false; + EXPECT_DEATH(GMOCK_CHECK_(a_false_condition) << "Extra info", + // MSVC and gcc use different formats to print source + // file locations. Google Mock's failure messages use + // the same format as used by the compiler, in order + // for the IDE to recognize them. Therefore we look + // for different patterns here depending on the + // compiler. +#ifdef _MSC_VER + "gmock-port_test\\.cc\\([0-9]+\\):" +#else + "gmock-port_test\\.cc:[0-9]+" +#endif // _MSC_VER + ".*a_false_condition.*Extra info"); +} + +TEST(GmockCheckDeathTest, LivesSilentlyOnSuccess) { + EXPECT_EXIT({ + GMOCK_CHECK_(true) << "Extra info"; + ::std::cerr << "Success\n"; + exit(0); }, + ::testing::ExitedWithCode(0), "Success"); +} + +#endif // GTEST_HAS_DEATH_TEST diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc new file mode 100644 index 00000000..7457af2b --- /dev/null +++ b/test/gmock-printers_test.cc @@ -0,0 +1,903 @@ +// 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 tests the universal value printer. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// hash_map and hash_set are available on Windows. +#ifdef GTEST_OS_WINDOWS +#define GMOCK_HAS_HASH_MAP_ // Indicates that hash_map is available. +#include // NOLINT +#define GMOCK_HAS_HASH_SET_ // Indicates that hash_set is available. +#include // NOLINT +#endif // GTEST_OS_WINDOWS + +// Some user-defined types for testing the universal value printer. + +// A user-defined unprintable class template in the global namespace. +template +class UnprintableTemplateInGlobal { + public: + UnprintableTemplateInGlobal() : value_() {} + private: + T value_; +}; + +// A user-defined streamable type in the global namespace. +class StreamableInGlobal { + public: + virtual ~StreamableInGlobal() {} +}; + +inline void operator<<(::std::ostream& os, const StreamableInGlobal& x) { + os << "StreamableInGlobal"; +} + +namespace foo { + +// A user-defined unprintable type in a user namespace. +class UnprintableInFoo { + public: + UnprintableInFoo() : x_(0x12EF), y_(0xAB34), z_(0) {} + private: + testing::internal::Int32 x_; + testing::internal::Int32 y_; + double z_; +}; + +// A user-defined printable type in a user-chosen namespace. +struct PrintableViaPrintTo { + PrintableViaPrintTo() : value() {} + int value; +}; + +void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { + *os << "PrintableViaPrintTo: " << x.value; +} + +// A user-defined printable class template in a user-chosen namespace. +template +class PrintableViaPrintToTemplate { + public: + explicit PrintableViaPrintToTemplate(const T& value) : value_(value) {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template +void PrintTo(const PrintableViaPrintToTemplate& x, ::std::ostream* os) { + *os << "PrintableViaPrintToTemplate: " << x.value(); +} + +// A user-defined streamable class template in a user namespace. +template +class StreamableTemplateInFoo { + public: + StreamableTemplateInFoo() : value_() {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template +inline ::std::ostream& operator<<(::std::ostream& os, + const StreamableTemplateInFoo& x) { + return os << "StreamableTemplateInFoo: " << x.value(); +} + +} // namespace foo + +namespace testing { +namespace gmock_printers_test { + +using ::std::deque; +using ::std::list; +using ::std::make_pair; +using ::std::map; +using ::std::multimap; +using ::std::multiset; +using ::std::pair; +using ::std::set; +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +using ::std::vector; +using ::testing::StartsWith; +using ::testing::internal::UniversalPrinter; +using ::testing::internal::string; + +#ifdef GTEST_OS_WINDOWS +// MSVC defines the following classes in the ::stdext namespace while +// gcc defines them in the :: namespace. Note that they are not part +// of the C++ standard. + +using ::stdext::hash_map; +using ::stdext::hash_set; +using ::stdext::hash_multimap; +using ::stdext::hash_multiset; + +#endif // GTEST_OS_WINDOWS + +// Prints a value to a string using the universal value printer. This +// is a helper for testing UniversalPrinter::Print() for various types. +template +string Print(const T& value) { + ::std::stringstream ss; + UniversalPrinter::Print(value, &ss); + return ss.str(); +} + +// Prints a value passed by reference to a string, using the universal +// value printer. This is a helper for testing +// UniversalPrinter::Print() for various types. +template +string PrintByRef(const T& value) { + ::std::stringstream ss; + UniversalPrinter::Print(value, &ss); + return ss.str(); +} + +// Tests printing various char types. + +// char. +TEST(PrintCharTest, PlainChar) { + EXPECT_EQ("'\\0'", Print('\0')); + EXPECT_EQ("'\\'' (39)", Print('\'')); + EXPECT_EQ("'\"' (34)", Print('"')); + EXPECT_EQ("'\\?' (63)", Print('\?')); + EXPECT_EQ("'\\\\' (92)", Print('\\')); + EXPECT_EQ("'\\a' (7)", Print('\a')); + EXPECT_EQ("'\\b' (8)", Print('\b')); + EXPECT_EQ("'\\f' (12)", Print('\f')); + EXPECT_EQ("'\\n' (10)", Print('\n')); + EXPECT_EQ("'\\r' (13)", Print('\r')); + EXPECT_EQ("'\\t' (9)", Print('\t')); + EXPECT_EQ("'\\v' (11)", Print('\v')); + EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); + EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); + EXPECT_EQ("' ' (32)", Print(' ')); + EXPECT_EQ("'a' (97)", Print('a')); +} + +// signed char. +TEST(PrintCharTest, SignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast('\0'))); + EXPECT_EQ("'\\xCE' (-50)", + Print(static_cast(-50))); +} + +// unsigned char. +TEST(PrintCharTest, UnsignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast('\0'))); + EXPECT_EQ("'b' (98)", + Print(static_cast('b'))); +} + +// Tests printing other simple, built-in types. + +// bool. +TEST(PrintBuiltInTypeTest, Bool) { + EXPECT_EQ("false", Print(false)); + EXPECT_EQ("true", Print(true)); +} + +// wchar_t. +TEST(PrintBuiltInTypeTest, Wchar_t) { + EXPECT_EQ("L'\\0'", Print(L'\0')); + EXPECT_EQ("L'\\'' (39)", Print(L'\'')); + EXPECT_EQ("L'\"' (34)", Print(L'"')); + EXPECT_EQ("L'\\?' (63)", Print(L'\?')); + EXPECT_EQ("L'\\\\' (92)", Print(L'\\')); + EXPECT_EQ("L'\\a' (7)", Print(L'\a')); + EXPECT_EQ("L'\\b' (8)", Print(L'\b')); + EXPECT_EQ("L'\\f' (12)", Print(L'\f')); + EXPECT_EQ("L'\\n' (10)", Print(L'\n')); + EXPECT_EQ("L'\\r' (13)", Print(L'\r')); + EXPECT_EQ("L'\\t' (9)", Print(L'\t')); + EXPECT_EQ("L'\\v' (11)", Print(L'\v')); + EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); + EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); + EXPECT_EQ("L' ' (32)", Print(L' ')); + EXPECT_EQ("L'a' (97)", Print(L'a')); + EXPECT_EQ("L'\\x576' (1398)", Print(L'\x576')); + EXPECT_EQ("L'\\xC74D' (51021)", Print(L'\xC74D')); +} + +// Test that Int64 provides more storage than wchar_t. +TEST(PrintTypeSizeTest, Wchar_t) { + EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); +} + +// Various integer types. +TEST(PrintBuiltInTypeTest, Integer) { + EXPECT_EQ("'\\xFF' (255)", Print(static_cast(255))); // uint8 + EXPECT_EQ("'\\x80' (-128)", Print(static_cast(-128))); // int8 + EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 + EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 + EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 + EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 + EXPECT_EQ("18446744073709551615", + Print(static_cast(-1))); // uint64 + EXPECT_EQ("-9223372036854775808", + Print(static_cast(1) << 63)); // int64 +} + +// Size types. +TEST(PrintBuiltInTypeTest, Size_t) { + EXPECT_EQ("1", Print(sizeof('a'))); // size_t. +#ifndef GTEST_OS_WINDOWS + // Windows has no ssize_t type. + EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. +#endif // GTEST_OS_WINDOWS +} + +// Floating-points. +TEST(PrintBuiltInTypeTest, FloatingPoints) { + EXPECT_EQ("1.5", Print(1.5f)); // float + EXPECT_EQ("-2.5", Print(-2.5)); // double +} + +// Since ::std::stringstream::operator<<(const void *) formats the pointer +// output differently with different compilers, we have to create the expected +// output first and use it as our expectation. +static string PrintPointer(const void *p) { + ::std::stringstream expected_result_stream; + expected_result_stream << p; + return expected_result_stream.str(); +} + +// Tests printing C strings. + +// const char*. +TEST(PrintCStringTest, Const) { + const char* p = "World"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); +} + +// char*. +TEST(PrintCStringTest, NonConst) { + char p[] = "Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", + Print(static_cast(p))); +} + +// NULL C string. +TEST(PrintCStringTest, Null) { + const char* p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that C strings are escaped properly. +TEST(PrintCStringTest, EscapesProperly) { + const char* p = "'\"\?\\\a\b\f\n\r\t\v\x7F\xFF a"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"\\?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\x7F\\xFF a\"", + Print(p)); +} + + + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + +// const wchar_t*. +TEST(PrintWideCStringTest, Const) { + const wchar_t* p = L"World"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); +} + +// wchar_t*. +TEST(PrintWideCStringTest, NonConst) { + wchar_t p[] = L"Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", + Print(static_cast(p))); +} + +// NULL wide C string. +TEST(PrintWideCStringTest, Null) { + const wchar_t* p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that wide C strings are escaped properly. +TEST(PrintWideCStringTest, EscapesProperly) { + const wchar_t* p = L"'\"\?\\\a\b\f\n\r\t\v\xD3\x576\x8D3\xC74D a"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"'\\\"\\?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", + Print(p)); +} +#endif // native wchar_t + +// Tests printing pointers to other char types. + +// signed char*. +TEST(PrintCharPointerTest, SignedChar) { + signed char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const signed char*. +TEST(PrintCharPointerTest, ConstSignedChar) { + signed char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// unsigned char*. +TEST(PrintCharPointerTest, UnsignedChar) { + unsigned char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const unsigned char*. +TEST(PrintCharPointerTest, ConstUnsignedChar) { + const unsigned char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to simple, built-in types. + +// bool*. +TEST(PrintPointerToBuiltInTypeTest, Bool) { + bool* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// void*. +TEST(PrintPointerToBuiltInTypeTest, Void) { + void* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const void*. +TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { + const void* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to pointers. +TEST(PrintPointerToPointerTest, IntPointerPointer) { + int** p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing (non-member) function pointers. + +void MyFunction(int n) {} + +TEST(PrintPointerTest, NonMemberFunctionPointer) { + EXPECT_EQ(PrintPointer(reinterpret_cast(&MyFunction)), + Print(&MyFunction)); + int (*p)(bool) = NULL; // NOLINT + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing member variable pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. + +struct Foo { + public: + virtual ~Foo() {} + int MyMethod(char x) { return x + 1; } + virtual char MyVirtualMethod(int n) { return 'a'; } + + int value; +}; + +TEST(PrintPointerTest, MemberVariablePointer) { + EXPECT_THAT(Print(&Foo::value), + StartsWith(Print(sizeof(&Foo::value)) + "-byte object ")); + int (Foo::*p) = NULL; // NOLINT + EXPECT_THAT(Print(p), + StartsWith(Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing member function pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. +TEST(PrintPointerTest, MemberFunctionPointer) { + EXPECT_THAT(Print(&Foo::MyMethod), + StartsWith(Print(sizeof(&Foo::MyMethod)) + "-byte object ")); + EXPECT_THAT(Print(&Foo::MyVirtualMethod), + StartsWith(Print(sizeof((&Foo::MyVirtualMethod))) + + "-byte object ")); + int (Foo::*p)(char) = NULL; // NOLINT + EXPECT_THAT(Print(p), + StartsWith(Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing C arrays. + +// One-dimensional array. + +void ArrayHelper1(int (&a)[5]) { // NOLINT + EXPECT_EQ("{ 1, 2, 3, 4, 5 }", Print(a)); +} + +TEST(PrintArrayTest, OneDimensionalArray) { + int a[5] = { 1, 2, 3, 4, 5 }; + ArrayHelper1(a); +} + +// Two-dimensional array. + +void ArrayHelper2(int (&a)[2][5]) { // NOLINT + EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", Print(a)); +} + +TEST(PrintArrayTest, TwoDimensionalArray) { + int a[2][5] = { + { 1, 2, 3, 4, 5 }, + { 6, 7, 8, 9, 0 } + }; + ArrayHelper2(a); +} + +// Array of const elements. + +void ArrayHelper3(const bool (&a)[1]) { // NOLINT + EXPECT_EQ("{ false }", Print(a)); +} + +TEST(PrintArrayTest, ConstArray) { + const bool a[1] = { false }; + ArrayHelper3(a); +} + +// Char array. + +void ArrayHelper4(char (&a)[3]) { // NOLINT + EXPECT_EQ(PrintPointer(a) + " pointing to \"Hi\"", Print(a)); +} + +TEST(PrintArrayTest, CharArray) { + char a[3] = "Hi"; + ArrayHelper4(a); +} + +// Const char array. + +void ArrayHelper5(const char (&a)[3]) { // NOLINT + EXPECT_EQ(Print(a), PrintPointer(a) + " pointing to \"Hi\""); +} + +TEST(PrintArrayTest, ConstCharArray) { + const char a[3] = "Hi"; + ArrayHelper5(a); +} + +// Array of objects. +TEST(PrintArrayTest, ObjectArray) { + string a[3] = { "Hi", "Hello", "Ni hao" }; + EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", Print(a)); +} + +// Array with many elements. +TEST(PrintArrayTest, BigArray) { + int a[100] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", + Print(a)); +} + +// Tests printing ::string and ::std::string. + +#if GTEST_HAS_GLOBAL_STRING +// ::string. +TEST(PrintStringTest, StringInGlobalNamespace) { + const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_STD_STRING +// ::std::string. +TEST(PrintStringTest, StringInStdNamespace) { + const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::std::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_STD_STRING + +// Tests printing ::wstring and ::std::wstring. + +#if GTEST_HAS_GLOBAL_WSTRING +// ::wstring. +TEST(PrintWideStringTest, StringInGlobalNamespace) { + const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +// ::std::wstring. +TEST(PrintWideStringTest, StringInStdNamespace) { + const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_STD_WSTRING + +// Tests printing STL containers. + +TEST(PrintStlContainerTest, EmptyDeque) { + deque empty; + EXPECT_EQ("{}", Print(empty)); +} + +TEST(PrintStlContainerTest, NonEmptyDeque) { + deque non_empty; + non_empty.push_back(1); + non_empty.push_back(3); + EXPECT_EQ("{ 1, 3 }", Print(non_empty)); +} + +#ifdef GMOCK_HAS_HASH_MAP_ + +TEST(PrintStlContainerTest, OneElementHashMap) { + hash_map map1; + map1[1] = 'a'; + EXPECT_EQ("{ (1, 'a' (97)) }", Print(map1)); +} + +TEST(PrintStlContainerTest, HashMultiMap) { + hash_multimap map1; + map1.insert(make_pair(5, true)); + map1.insert(make_pair(5, false)); + + // Elements of hash_multimap can be printed in any order. + const string result = Print(map1); + EXPECT_TRUE(result == "{ (5, true), (5, false) }" || + result == "{ (5, false), (5, true) }") + << " where Print(map1) returns \"" << result << "\"."; +} + +#endif // GMOCK_HAS_HASH_MAP_ + +#ifdef GMOCK_HAS_HASH_SET_ + +TEST(PrintStlContainerTest, HashSet) { + hash_set set1; + set1.insert("hello"); + EXPECT_EQ("{ \"hello\" }", Print(set1)); +} + +TEST(PrintStlContainerTest, HashMultiSet) { + const int kSize = 5; + int a[kSize] = { 1, 1, 2, 5, 1 }; + hash_multiset set1(a, a + kSize); + + // Elements of hash_multiset can be printed in any order. + const string result = Print(set1); + const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. + + // Verifies the result matches the expected pattern; also extracts + // the numbers in the result. + ASSERT_EQ(expected_pattern.length(), result.length()); + std::vector numbers; + for (size_t i = 0; i != result.length(); i++) { + if (expected_pattern[i] == 'd') { + ASSERT_TRUE(isdigit(result[i])); + numbers.push_back(result[i] - '0'); + } else { + EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " + << result; + } + } + + // Makes sure the result contains the right numbers. + std::sort(numbers.begin(), numbers.end()); + std::sort(a, a + kSize); + EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); +} + +#endif // GMOCK_HAS_HASH_SET_ + +TEST(PrintStlContainerTest, List) { + const char* a[] = { + "hello", + "world" + }; + const list strings(a, a + 2); + EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); +} + +TEST(PrintStlContainerTest, Map) { + map map1; + map1[1] = true; + map1[5] = false; + map1[3] = true; + EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); +} + +TEST(PrintStlContainerTest, MultiMap) { + multimap map1; + map1.insert(make_pair(true, 0)); + map1.insert(make_pair(true, 1)); + map1.insert(make_pair(false, 2)); + EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); +} + +TEST(PrintStlContainerTest, Set) { + const unsigned int a[] = { 3, 0, 5 }; + set set1(a, a + 3); + EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, MultiSet) { + const int a[] = { 1, 1, 2, 5, 1 }; + multiset set1(a, a + 5); + EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, Pair) { + pair p(true, 5); + EXPECT_EQ("(true, 5)", Print(p)); +} + +TEST(PrintStlContainerTest, Vector) { + vector v; + v.push_back(1); + v.push_back(2); + EXPECT_EQ("{ 1, 2 }", Print(v)); +} + +TEST(PrintStlContainerTest, LongSequence) { + const int a[100] = { 1, 2, 3 }; + const vector v(a, a + 100); + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " + "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v)); +} + +TEST(PrintStlContainerTest, NestedContainer) { + const int a1[] = { 1, 2 }; + const int a2[] = { 3, 4, 5 }; + const list l1(a1, a1 + 2); + const list l2(a2, a2 + 3); + + vector > v; + v.push_back(l1); + v.push_back(l2); + EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); +} + + +// Tests printing tuples. + +// Tuples of various arities. +TEST(PrintTupleTest, VariousSizes) { + tuple<> t0; + EXPECT_EQ("()", Print(t0)); + + tuple t1(5); + EXPECT_EQ("(5)", Print(t1)); + + tuple t2('a', true); + EXPECT_EQ("('a' (97), true)", Print(t2)); + + const char* const str = "8"; + tuple + t10(false, 'a', 3, 4, 5, 6.5F, 7.5, str, NULL, "10"); + EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 6.5, 7.5, " + PrintPointer(str) + + " pointing to \"8\", NULL, \"10\")", + Print(t10)); +} + +// Nested tuples. +TEST(PrintTupleTest, NestedTuple) { + tuple, char> nested(make_tuple(5, 9.5), 'a'); + EXPECT_EQ("((5, 9.5), 'a' (97))", Print(nested)); +} + +// Tests printing user-defined unprintable types. + +// Unprintable types in the global namespace. +TEST(PrintUnprintableTypeTest, InGlobalNamespace) { + EXPECT_EQ("1-byte object <00>", + Print(UnprintableTemplateInGlobal())); +} + +// Unprintable types in a user namespace. +TEST(PrintUnprintableTypeTest, InUserNamespace) { + EXPECT_EQ("16-byte object ", + Print(::foo::UnprintableInFoo())); +} + +// Unprintable types are that too big to be printed completely. + +struct Big { + Big() { memset(array, 0, sizeof(array)); } + char array[257]; +}; + +TEST(PrintUnpritableTypeTest, BigObject) { + EXPECT_EQ("257-byte object <0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 ... 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 00>", + Print(Big())); +} + +// Tests printing user-defined streamable types. + +// Streamable types in the global namespace. +TEST(PrintStreamableTypeTest, InGlobalNamespace) { + EXPECT_EQ("StreamableInGlobal", + Print(StreamableInGlobal())); +} + +// Printable template types in a user namespace. +TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { + EXPECT_EQ("StreamableTemplateInFoo: 0", + Print(::foo::StreamableTemplateInFoo())); +} + +// Tests printing user-defined types that have a PrintTo() function. +TEST(PrintPrintableTypeTest, InUserNamespace) { + EXPECT_EQ("PrintableViaPrintTo: 0", + Print(::foo::PrintableViaPrintTo())); +} + +// Tests printing user-defined class template that have a PrintTo() function. +TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { + EXPECT_EQ("PrintableViaPrintToTemplate: 5", + Print(::foo::PrintableViaPrintToTemplate(5))); +} + +#if GMOCK_HAS_PROTOBUF_ + +// Tests printing a protocol message. +TEST(PrintProtocolMessageTest, PrintsShortDebugString) { + testing::internal::TestMessage msg; + msg.set_member("yes"); + EXPECT_EQ("", Print(msg)); +} + +// Tests printing a proto2 message. +TEST(PrintProto2MessageTest, PrintsShortDebugString) { + testing::internal::FooMessage msg; + msg.set_int_field(2); + EXPECT_PRED2(RE::FullMatch, Print(msg), + ""); +} + +#endif // GMOCK_HAS_PROTOBUF_ + +// Tests that the universal printer prints both the address and the +// value of a reference. +TEST(PrintReferenceTest, PrintsAddressAndValue) { + int n = 5; + EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); + + int a[2][3] = { + { 0, 1, 2 }, + { 3, 4, 5 } + }; + EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", + PrintByRef(a)); + + const ::foo::UnprintableInFoo x; + EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " + "", + PrintByRef(x)); +} + +// Tests that the universal printer prints a function pointer passed by +// reference. +TEST(PrintReferenceTest, HandlesFunctionPointer) { + void (*fp)(int n) = &MyFunction; + const string fp_pointer_string = + PrintPointer(reinterpret_cast(&fp)); + const string fp_string = PrintPointer(reinterpret_cast(fp)); + EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, + PrintByRef(fp)); +} + +// Tests that the universal printer prints a member function pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { + int (Foo::*p)(char ch) = &Foo::MyMethod; + EXPECT_THAT(PrintByRef(p), + StartsWith("@" + PrintPointer(reinterpret_cast(&p)) + + " " + Print(sizeof(p)) + "-byte object ")); + + char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; + EXPECT_THAT(PrintByRef(p2), + StartsWith("@" + PrintPointer(reinterpret_cast(&p2)) + + " " + Print(sizeof(p2)) + "-byte object ")); +} + +// Tests that the universal printer prints a member variable pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + int (Foo::*p) = &Foo::value; // NOLINT + EXPECT_THAT(PrintByRef(p), + StartsWith("@" + PrintPointer(&p) + + " " + Print(sizeof(p)) + "-byte object ")); +} + +} // namespace gmock_printers_test +} // namespace testing diff --git a/test/gmock-sample.cc b/test/gmock-sample.cc new file mode 100644 index 00000000..44d72a10 --- /dev/null +++ b/test/gmock-sample.cc @@ -0,0 +1,32 @@ +// 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) + +#include "test/gmock-sample.h" diff --git a/test/gmock-sample.h b/test/gmock-sample.h new file mode 100644 index 00000000..2183f4f9 --- /dev/null +++ b/test/gmock-sample.h @@ -0,0 +1,49 @@ +// 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) + +#ifndef GMOCK_TEST_GMOCK_SAMPLE_H_ +#define GMOCK_TEST_GMOCK_SAMPLE_H_ + +#include + +class Sample { + public: + virtual ~Sample() {} + + virtual bool Foo(int n) = 0; +}; + +class MockSample : public Sample { + public: + MOCK_METHOD1(Foo, bool(int n)); +}; + +#endif // GMOCK_TEST_GMOCK_SAMPLE_H_ diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc new file mode 100644 index 00000000..3e27aa84 --- /dev/null +++ b/test/gmock-spec-builders_test.cc @@ -0,0 +1,1889 @@ +// 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 tests the spec builder syntax. + +#include + +#include // NOLINT +#include +#include + +#include +#include +#include +#include + +namespace testing { +namespace internal { + +// Helper class for testing the Expectation class template. +class ExpectationTester { + public: + // Sets the call count of the given expectation to the given number. + void SetCallCount(int n, ExpectationBase* exp) { + exp->call_count_ = n; + } +}; + +} // namespace internal +} // namespace testing + +namespace { + +using testing::_; +using testing::AnyNumber; +using testing::AtLeast; +using testing::AtMost; +using testing::Between; +using testing::Cardinality; +using testing::CardinalityInterface; +using testing::Const; +using testing::DoAll; +using testing::DoDefault; +using testing::GMOCK_FLAG(verbose); +using testing::InSequence; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::IsSubstring; +using testing::Lt; +using testing::Message; +using testing::Mock; +using testing::Return; +using testing::Sequence; +using testing::internal::g_gmock_mutex; +using testing::internal::kErrorVerbosity; +using testing::internal::kInfoVerbosity; +using testing::internal::kWarningVerbosity; +using testing::internal::Expectation; +using testing::internal::ExpectationTester; +using testing::internal::string; + +class Result {}; + +class MockA { + public: + MOCK_METHOD1(DoA, void(int n)); // NOLINT + MOCK_METHOD1(ReturnResult, Result(int n)); // NOLINT + MOCK_METHOD2(Binary, bool(int x, int y)); // NOLINT +}; + +class MockB { + public: + MOCK_CONST_METHOD0(DoB, int()); // NOLINT + MOCK_METHOD1(DoB, int(int n)); // NOLINT +}; + +// Tests that EXPECT_CALL and ON_CALL compile in a presence of macro +// redefining a mock method name. This could happen, for example, when +// the tested code #includes Win32 API headers which define many APIs +// as macros, e.g. #define TextOut TextOutW. + +#define Method MethodW + +class CC { + public: + virtual ~CC() {} + virtual int Method() = 0; +}; +class MockCC : public CC { + public: + MOCK_METHOD0(Method, int()); +}; + +// Tests that a method with expanded name compiles. +TEST(OnCallSyntaxTest, CompilesWithMethodNameExpandedFromMacro) { + MockCC cc; + ON_CALL(cc, Method()); +} + +// Tests that the method with expanded name not only compiles but runs +// and returns a correct value, too. +TEST(OnCallSyntaxTest, WorksWithMethodNameExpandedFromMacro) { + MockCC cc; + ON_CALL(cc, Method()).WillByDefault(Return(42)); + EXPECT_EQ(42, cc.Method()); +} + +// Tests that a method with expanded name compiles. +TEST(ExpectCallSyntaxTest, CompilesWithMethodNameExpandedFromMacro) { + MockCC cc; + EXPECT_CALL(cc, Method()); + cc.Method(); +} + +// Tests that it works, too. +TEST(ExpectCallSyntaxTest, WorksWithMethodNameExpandedFromMacro) { + MockCC cc; + EXPECT_CALL(cc, Method()).WillOnce(Return(42)); + EXPECT_EQ(42, cc.Method()); +} + +#undef Method // Done with macro redefinition tests. + +// Tests that ON_CALL evaluates its arguments exactly once as promised +// by Google Mock. +TEST(OnCallSyntaxTest, EvaluatesFirstArgumentOnce) { + MockA a; + MockA* pa = &a; + + ON_CALL(*pa++, DoA(_)); + EXPECT_EQ(&a + 1, pa); +} + +TEST(OnCallSyntaxTest, EvaluatesSecondArgumentOnce) { + MockA a; + int n = 0; + + ON_CALL(a, DoA(n++)); + EXPECT_EQ(1, n); +} + +// Tests that the syntax of ON_CALL() is enforced at run time. + +TEST(OnCallSyntaxTest, WithArgumentsIsOptional) { + MockA a; + + ON_CALL(a, DoA(5)) + .WillByDefault(Return()); + ON_CALL(a, DoA(_)) + .WithArguments(_) + .WillByDefault(Return()); +} + +TEST(OnCallSyntaxTest, WithArgumentsCanAppearAtMostOnce) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + ON_CALL(a, ReturnResult(_)) + .WithArguments(_) + .WithArguments(_) + .WillByDefault(Return(Result())); + }, ".WithArguments() cannot appear more than once in an ON_CALL()"); +} + +#ifdef GTEST_HAS_DEATH_TEST + +TEST(OnCallSyntaxTest, WillByDefaultIsMandatory) { + MockA a; + + EXPECT_DEATH({ // NOLINT + ON_CALL(a, DoA(5)); + a.DoA(5); + }, ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +TEST(OnCallSyntaxTest, WillByDefaultCanAppearAtMostOnce) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + ON_CALL(a, DoA(5)) + .WillByDefault(Return()) + .WillByDefault(Return()); + }, ".WillByDefault() must appear exactly once in an ON_CALL()"); +} + +// Tests that EXPECT_CALL evaluates its arguments exactly once as +// promised by Google Mock. +TEST(ExpectCallSyntaxTest, EvaluatesFirstArgumentOnce) { + MockA a; + MockA* pa = &a; + + EXPECT_CALL(*pa++, DoA(_)); + a.DoA(0); + EXPECT_EQ(&a + 1, pa); +} + +TEST(ExpectCallSyntaxTest, EvaluatesSecondArgumentOnce) { + MockA a; + int n = 0; + + EXPECT_CALL(a, DoA(n++)); + a.DoA(0); + EXPECT_EQ(1, n); +} + +// Tests that the syntax of EXPECT_CALL() is enforced at run time. + +TEST(ExpectCallSyntaxTest, WithArgumentsIsOptional) { + MockA a; + + EXPECT_CALL(a, DoA(5)) + .Times(0); + EXPECT_CALL(a, DoA(6)) + .WithArguments(_) + .Times(0); +} + +TEST(ExpectCallSyntaxTest, WithArgumentsCanAppearAtMostOnce) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(6)) + .WithArguments(_) + .WithArguments(_); + }, ".WithArguments() cannot appear more than once in " + "an EXPECT_CALL()"); + + a.DoA(6); +} + +TEST(ExpectCallSyntaxTest, WithArgumentsMustBeFirstClause) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .Times(1) + .WithArguments(_); + }, ".WithArguments() must be the first clause in an " + "EXPECT_CALL()"); + + a.DoA(1); + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(2)) + .WillOnce(Return()) + .WithArguments(_); + }, ".WithArguments() must be the first clause in an " + "EXPECT_CALL()"); + + a.DoA(2); +} + +TEST(ExpectCallSyntaxTest, TimesCanBeInferred) { + MockA a; + + EXPECT_CALL(a, DoA(1)) + .WillOnce(Return()); + + EXPECT_CALL(a, DoA(2)) + .WillOnce(Return()) + .WillRepeatedly(Return()); + + a.DoA(1); + a.DoA(2); + a.DoA(2); +} + +TEST(ExpectCallSyntaxTest, TimesCanAppearAtMostOnce) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .Times(1) + .Times(2); + }, ".Times() cannot appear more than once in an EXPECT_CALL()"); + + a.DoA(1); + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, TimesMustBeBeforeInSequence) { + MockA a; + Sequence s; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .InSequence(s) + .Times(1); + }, ".Times() cannot appear after "); + + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, InSequenceIsOptional) { + MockA a; + Sequence s; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(2)) + .InSequence(s); + + a.DoA(1); + a.DoA(2); +} + +TEST(ExpectCallSyntaxTest, InSequenceCanAppearMultipleTimes) { + MockA a; + Sequence s1, s2; + + EXPECT_CALL(a, DoA(1)) + .InSequence(s1, s2) + .InSequence(s1); + + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWill) { + MockA a; + Sequence s; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .WillOnce(Return()) + .InSequence(s); + }, ".InSequence() cannot appear after "); + + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, WillIsOptional) { + MockA a; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(2)) + .WillOnce(Return()); + + a.DoA(1); + a.DoA(2); +} + +TEST(ExpectCallSyntaxTest, WillCanAppearMultipleTimes) { + MockA a; + + EXPECT_CALL(a, DoA(1)) + .Times(AnyNumber()) + .WillOnce(Return()) + .WillOnce(Return()) + .WillOnce(Return()); +} + +TEST(ExpectCallSyntaxTest, WillMustBeBeforeWillRepeatedly) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .WillRepeatedly(Return()) + .WillOnce(Return()); + }, ".WillOnce() cannot appear after "); + + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, WillRepeatedlyIsOptional) { + MockA a; + + EXPECT_CALL(a, DoA(1)) + .WillOnce(Return()); + EXPECT_CALL(a, DoA(2)) + .WillOnce(Return()) + .WillRepeatedly(Return()); + + a.DoA(1); + a.DoA(2); + a.DoA(2); +} + +TEST(ExpectCallSyntaxTest, WillRepeatedlyCannotAppearMultipleTimes) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .WillRepeatedly(Return()) + .WillRepeatedly(Return()); + }, ".WillRepeatedly() cannot appear more than once in an " + "EXPECT_CALL()"); +} + +TEST(ExpectCallSyntaxTest, WillRepeatedlyMustBeBeforeRetiresOnSaturation) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .RetiresOnSaturation() + .WillRepeatedly(Return()); + }, ".WillRepeatedly() cannot appear after "); +} + +TEST(ExpectCallSyntaxTest, RetiresOnSaturationIsOptional) { + MockA a; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(1)) + .RetiresOnSaturation(); + + a.DoA(1); + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, RetiresOnSaturationCannotAppearMultipleTimes) { + MockA a; + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(1)) + .RetiresOnSaturation() + .RetiresOnSaturation(); + }, ".RetiresOnSaturation() cannot appear more than once"); + + a.DoA(1); +} + +TEST(ExpectCallSyntaxTest, DefaultCardinalityIsOnce) { + { + MockA a; + EXPECT_CALL(a, DoA(1)); + a.DoA(1); + } + EXPECT_NONFATAL_FAILURE({ // NOLINT + MockA a; + EXPECT_CALL(a, DoA(1)); + }, "to be called once"); + EXPECT_NONFATAL_FAILURE({ // NOLINT + MockA a; + EXPECT_CALL(a, DoA(1)); + a.DoA(1); + a.DoA(1); + }, "to be called once"); +} + +// TODO(wan@google.com): find a way to re-enable these tests. +#if 0 + +// Tests that Google Mock doesn't print a warning when the number of +// WillOnce() is adequate. +TEST(ExpectCallSyntaxTest, DoesNotWarnOnAdequateActionCount) { + CaptureTestStdout(); + { + MockB b; + + // It's always fine to omit WillOnce() entirely. + EXPECT_CALL(b, DoB()) + .Times(0); + EXPECT_CALL(b, DoB(1)) + .Times(AtMost(1)); + EXPECT_CALL(b, DoB(2)) + .Times(1) + .WillRepeatedly(Return(1)); + + // It's fine for the number of WillOnce()s to equal the upper bound. + EXPECT_CALL(b, DoB(3)) + .Times(Between(1, 2)) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + + // It's fine for the number of WillOnce()s to be smaller than the + // upper bound when there is a WillRepeatedly(). + EXPECT_CALL(b, DoB(4)) + .Times(AtMost(3)) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); + + // Satisfies the above expectations. + b.DoB(2); + b.DoB(3); + } + const string& output = GetCapturedTestStdout(); + EXPECT_EQ("", output); +} + +// Tests that Google Mock warns on having too many actions in an +// expectation compared to its cardinality. +TEST(ExpectCallSyntaxTest, WarnsOnTooManyActions) { + CaptureTestStdout(); + { + MockB b; + + // Warns when the number of WillOnce()s is larger than the upper bound. + EXPECT_CALL(b, DoB()) + .Times(0) + .WillOnce(Return(1)); // #1 + EXPECT_CALL(b, DoB()) + .Times(AtMost(1)) + .WillOnce(Return(1)) + .WillOnce(Return(2)); // #2 + EXPECT_CALL(b, DoB(1)) + .Times(1) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .RetiresOnSaturation(); // #3 + + // Warns when the number of WillOnce()s equals the upper bound and + // there is a WillRepeatedly(). + EXPECT_CALL(b, DoB()) + .Times(0) + .WillRepeatedly(Return(1)); // #4 + EXPECT_CALL(b, DoB(2)) + .Times(1) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); // #5 + + // Satisfies the above expectations. + b.DoB(1); + b.DoB(2); + } + const string& output = GetCapturedTestStdout(); + EXPECT_PRED_FORMAT2(IsSubstring, + "Too many actions specified.\n" + "Expected to be never called, but has 1 WillOnce().", + output); // #1 + EXPECT_PRED_FORMAT2(IsSubstring, + "Too many actions specified.\n" + "Expected to be called at most once, " + "but has 2 WillOnce()s.", + output); // #2 + EXPECT_PRED_FORMAT2(IsSubstring, + "Too many actions specified.\n" + "Expected to be called once, but has 2 WillOnce()s.", + output); // #3 + EXPECT_PRED_FORMAT2(IsSubstring, + "Too many actions specified.\n" + "Expected to be never called, but has 0 WillOnce()s " + "and a WillRepeatedly().", + output); // #4 + EXPECT_PRED_FORMAT2(IsSubstring, + "Too many actions specified.\n" + "Expected to be called once, but has 1 WillOnce() " + "and a WillRepeatedly().", + output); // #5 +} + +// Tests that Google Mock warns on having too few actions in an +// expectation compared to its cardinality. +TEST(ExpectCallSyntaxTest, WarnsOnTooFewActions) { + MockB b; + + EXPECT_CALL(b, DoB()) + .Times(Between(2, 3)) + .WillOnce(Return(1)); + + CaptureTestStdout(); + b.DoB(); + const string& output = GetCapturedTestStdout(); + EXPECT_PRED_FORMAT2(IsSubstring, + "Too few actions specified.\n" + "Expected to be called between 2 and 3 times, " + "but has only 1 WillOnce().", + output); + b.DoB(); +} + +#endif // 0 + +// Tests the semantics of ON_CALL(). + +// Tests that the built-in default action is taken when no ON_CALL() +// is specified. +TEST(OnCallTest, TakesBuiltInDefaultActionWhenNoOnCall) { + MockB b; + EXPECT_CALL(b, DoB()); + + EXPECT_EQ(0, b.DoB()); +} + +// Tests that the built-in default action is taken when no ON_CALL() +// matches the invocation. +TEST(OnCallTest, TakesBuiltInDefaultActionWhenNoOnCallMatches) { + MockB b; + ON_CALL(b, DoB(1)) + .WillByDefault(Return(1)); + EXPECT_CALL(b, DoB(_)); + + EXPECT_EQ(0, b.DoB(2)); +} + +// Tests that the last matching ON_CALL() action is taken. +TEST(OnCallTest, PicksLastMatchingOnCall) { + MockB b; + ON_CALL(b, DoB(_)) + .WillByDefault(Return(3)); + ON_CALL(b, DoB(2)) + .WillByDefault(Return(2)); + ON_CALL(b, DoB(1)) + .WillByDefault(Return(1)); + EXPECT_CALL(b, DoB(_)); + + EXPECT_EQ(2, b.DoB(2)); +} + +// Tests the semantics of EXPECT_CALL(). + +// Tests that any call is allowed when no EXPECT_CALL() is specified. +TEST(ExpectCallTest, AllowsAnyCallWhenNoSpec) { + MockB b; + EXPECT_CALL(b, DoB()); + // There is no expectation on DoB(int). + + b.DoB(); + + // DoB(int) can be called any number of times. + b.DoB(1); + b.DoB(2); +} + +// Tests that the last matching EXPECT_CALL() fires. +TEST(ExpectCallTest, PicksLastMatchingExpectCall) { + MockB b; + EXPECT_CALL(b, DoB(_)) + .WillRepeatedly(Return(2)); + EXPECT_CALL(b, DoB(1)) + .WillRepeatedly(Return(1)); + + EXPECT_EQ(1, b.DoB(1)); +} + +// Tests lower-bound violation. +TEST(ExpectCallTest, CatchesTooFewCalls) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + MockB b; + EXPECT_CALL(b, DoB(5)) + .Times(AtLeast(2)); + + b.DoB(5); + }, "Actual function call count doesn't match this expectation.\n" + " Expected: to be called at least twice\n" + " Actual: called once - unsatisfied and active"); +} + +// Tests that the cardinality can be inferred when no Times(...) is +// specified. +TEST(ExpectCallTest, InfersCardinalityWhenThereIsNoWillRepeatedly) { + { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + } + + EXPECT_NONFATAL_FAILURE({ // NOLINT + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + + EXPECT_EQ(1, b.DoB()); + }, "to be called twice"); + + { // NOLINT + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + EXPECT_NONFATAL_FAILURE(b.DoB(), "to be called twice"); + } +} + +TEST(ExpectCallTest, InfersCardinality1WhenThereIsWillRepeatedly) { + { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); + + EXPECT_EQ(1, b.DoB()); + } + + { // NOLINT + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); + + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + EXPECT_EQ(2, b.DoB()); + } + + EXPECT_NONFATAL_FAILURE({ // NOLINT + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); + }, "to be called at least once"); +} + +// Tests that the n-th action is taken for the n-th matching +// invocation. +TEST(ExpectCallTest, NthMatchTakesNthAction) { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .WillOnce(Return(3)); + + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + EXPECT_EQ(3, b.DoB()); +} + +// TODO(wan@google.com): find a way to re-enable these tests. +#if 0 + +// Tests that the default action is taken when the WillOnce(...) list is +// exhausted and there is no WillRepeatedly(). +TEST(ExpectCallTest, TakesDefaultActionWhenWillListIsExhausted) { + MockB b; + EXPECT_CALL(b, DoB(_)) + .Times(1); + EXPECT_CALL(b, DoB()) + .Times(AnyNumber()) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + + CaptureTestStdout(); + EXPECT_EQ(0, b.DoB(1)); // Shouldn't generate a warning as the + // expectation has no action clause at all. + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + const string& output1 = GetCapturedTestStdout(); + EXPECT_EQ("", output1); + + CaptureTestStdout(); + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB()); + const string& output2 = GetCapturedTestStdout(); + EXPECT_PRED2(RE::PartialMatch, output2, + "Actions ran out\\.\n" + "Called 3 times, but only 2 WillOnce\\(\\)s are specified - " + "returning default value\\."); + EXPECT_PRED2(RE::PartialMatch, output2, + "Actions ran out\\.\n" + "Called 4 times, but only 2 WillOnce\\(\\)s are specified - " + "returning default value\\."); +} + +#endif // 0 + +// Tests that the WillRepeatedly() action is taken when the WillOnce(...) +// list is exhausted. +TEST(ExpectCallTest, TakesRepeatedActionWhenWillListIsExhausted) { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); + + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + EXPECT_EQ(2, b.DoB()); +} + +// Tests that an uninteresting call performs the default action. +TEST(UninterestingCallTest, DoesDefaultAction) { + // When there is an ON_CALL() statement, the action specified by it + // should be taken. + MockA a; + ON_CALL(a, Binary(_, _)) + .WillByDefault(Return(true)); + EXPECT_TRUE(a.Binary(1, 2)); + + // When there is no ON_CALL(), the default value for the return type + // should be returned. + MockB b; + EXPECT_EQ(0, b.DoB()); +} + +// Tests that an unexpected call performs the default action. +TEST(UnexpectedCallTest, DoesDefaultAction) { + // When there is an ON_CALL() statement, the action specified by it + // should be taken. + MockA a; + ON_CALL(a, Binary(_, _)) + .WillByDefault(Return(true)); + EXPECT_CALL(a, Binary(0, 0)); + a.Binary(0, 0); + bool result = false; + EXPECT_NONFATAL_FAILURE(result = a.Binary(1, 2), + "Unexpected mock function call"); + EXPECT_TRUE(result); + + // When there is no ON_CALL(), the default value for the return type + // should be returned. + MockB b; + EXPECT_CALL(b, DoB(0)) + .Times(0); + int n = -1; + EXPECT_NONFATAL_FAILURE(n = b.DoB(1), + "Unexpected mock function call"); + EXPECT_EQ(0, n); +} + +// Tests that when an unexpected void function generates the right +// failure message. +TEST(UnexpectedCallTest, GeneratesFailureForVoidFunction) { + // First, tests the message when there is only one EXPECT_CALL(). + MockA a1; + EXPECT_CALL(a1, DoA(1)); + a1.DoA(1); + // Ideally we should match the failure message against a regex, but + // EXPECT_NONFATAL_FAILURE doesn't support that, so we test for + // multiple sub-strings instead. + EXPECT_NONFATAL_FAILURE( + a1.DoA(9), + "Unexpected mock function call - returning directly.\n" + " Function call: DoA(9)\n" + "Google Mock tried the following 1 expectation, but it didn't match:"); + EXPECT_NONFATAL_FAILURE( + a1.DoA(9), + " Expected arg #0: is equal to 1\n" + " Actual: 9\n" + " Expected: to be called once\n" + " Actual: called once - saturated and active"); + + // Next, tests the message when there are more than one EXPECT_CALL(). + MockA a2; + EXPECT_CALL(a2, DoA(1)); + EXPECT_CALL(a2, DoA(3)); + a2.DoA(1); + EXPECT_NONFATAL_FAILURE( + a2.DoA(2), + "Unexpected mock function call - returning directly.\n" + " Function call: DoA(2)\n" + "Google Mock tried the following 2 expectations, but none matched:"); + EXPECT_NONFATAL_FAILURE( + a2.DoA(2), + "tried expectation #0\n" + " Expected arg #0: is equal to 1\n" + " Actual: 2\n" + " Expected: to be called once\n" + " Actual: called once - saturated and active"); + EXPECT_NONFATAL_FAILURE( + a2.DoA(2), + "tried expectation #1\n" + " Expected arg #0: is equal to 3\n" + " Actual: 2\n" + " Expected: to be called once\n" + " Actual: never called - unsatisfied and active"); + a2.DoA(3); +} + +// Tests that an unexpected non-void function generates the right +// failure message. +TEST(UnexpectedCallTest, GeneartesFailureForNonVoidFunction) { + MockB b1; + EXPECT_CALL(b1, DoB(1)); + b1.DoB(1); + EXPECT_NONFATAL_FAILURE( + b1.DoB(2), + "Unexpected mock function call - returning default value.\n" + " Function call: DoB(2)\n" + " Returns: 0\n" + "Google Mock tried the following 1 expectation, but it didn't match:"); + EXPECT_NONFATAL_FAILURE( + b1.DoB(2), + " Expected arg #0: is equal to 1\n" + " Actual: 2\n" + " Expected: to be called once\n" + " Actual: called once - saturated and active"); +} + +// Tests that Google Mock explains that an retired expectation doesn't +// match the call. +TEST(UnexpectedCallTest, RetiredExpectation) { + MockB b; + EXPECT_CALL(b, DoB(1)) + .RetiresOnSaturation(); + + b.DoB(1); + EXPECT_NONFATAL_FAILURE( + b.DoB(1), + " Expected: the expectation is active\n" + " Actual: it is retired"); +} + +// Tests that Google Mock explains that an expectation that doesn't +// match the arguments doesn't match the call. +TEST(UnexpectedCallTest, UnmatchedArguments) { + MockB b; + EXPECT_CALL(b, DoB(1)); + + EXPECT_NONFATAL_FAILURE( + b.DoB(2), + " Expected arg #0: is equal to 1\n" + " Actual: 2\n"); + b.DoB(1); +} + +#ifdef GMOCK_HAS_REGEX + +// Tests that Google Mock explains that an expectation with +// unsatisfied pre-requisites doesn't match the call. +TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { + Sequence s1, s2; + MockB b; + EXPECT_CALL(b, DoB(1)) + .InSequence(s1); + EXPECT_CALL(b, DoB(2)) + .Times(AnyNumber()) + .InSequence(s1); + EXPECT_CALL(b, DoB(3)) + .InSequence(s2); + EXPECT_CALL(b, DoB(4)) + .InSequence(s1, s2); + + ::testing::TestPartResultArray failures; + { + ::testing::ScopedFakeTestPartResultReporter reporter(&failures); + b.DoB(4); + // Now 'failures' contains the Google Test failures generated by + // the above statement. + } + + // There should be one non-fatal failure. + ASSERT_EQ(1, failures.size()); + const ::testing::TestPartResult& r = failures.GetTestPartResult(0); + EXPECT_EQ(::testing::TPRT_NONFATAL_FAILURE, r.type()); + + // Verifies that the failure message contains the two unsatisfied + // pre-requisites but not the satisfied one. + const char* const pattern = +#if GMOCK_USES_PCRE + // PCRE has trouble using (.|\n) to match any character, but + // supports the (?s) prefix for using . to match any character. + "(?s)the following immediate pre-requisites are not satisfied:\n" + ".*: pre-requisite #0\n" + ".*: pre-requisite #1"; +#else + // POSIX RE doesn't understand the (?s) prefix, but has no trouble + // with (.|\n). + "the following immediate pre-requisites are not satisfied:\n" + "(.|\n)*: pre-requisite #0\n" + "(.|\n)*: pre-requisite #1"; +#endif // GMOCK_USES_PCRE + + EXPECT_TRUE( + ::testing::internal::RE::PartialMatch(r.message(), pattern)) + << " where the message is " << r.message(); + b.DoB(1); + b.DoB(3); + b.DoB(4); +} + +#endif // GMOCK_HAS_REGEX + +// Tests that an excessive call (one whose arguments match the +// matchers but is called too many times) performs the default action. +TEST(ExcessiveCallTest, DoesDefaultAction) { + // When there is an ON_CALL() statement, the action specified by it + // should be taken. + MockA a; + ON_CALL(a, Binary(_, _)) + .WillByDefault(Return(true)); + EXPECT_CALL(a, Binary(0, 0)); + a.Binary(0, 0); + bool result = false; + EXPECT_NONFATAL_FAILURE(result = a.Binary(0, 0), + "Mock function called more times than expected"); + EXPECT_TRUE(result); + + // When there is no ON_CALL(), the default value for the return type + // should be returned. + MockB b; + EXPECT_CALL(b, DoB(0)) + .Times(0); + int n = -1; + EXPECT_NONFATAL_FAILURE(n = b.DoB(0), + "Mock function called more times than expected"); + EXPECT_EQ(0, n); +} + +// Tests that when a void function is called too many times, +// the failure message contains the argument values. +TEST(ExcessiveCallTest, GeneratesFailureForVoidFunction) { + MockA a; + EXPECT_CALL(a, DoA(_)) + .Times(0); + EXPECT_NONFATAL_FAILURE( + a.DoA(9), + "Mock function called more times than expected - returning directly.\n" + " Function call: DoA(9)\n" + " Expected: to be never called\n" + " Actual: called once - over-saturated and active"); +} + +// Tests that when a non-void function is called too many times, the +// failure message contains the argument values and the return value. +TEST(ExcessiveCallTest, GeneratesFailureForNonVoidFunction) { + MockB b; + EXPECT_CALL(b, DoB(_)); + b.DoB(1); + EXPECT_NONFATAL_FAILURE( + b.DoB(2), + "Mock function called more times than expected - " + "returning default value.\n" + " Function call: DoB(2)\n" + " Returns: 0\n" + " Expected: to be called once\n" + " Actual: called twice - over-saturated and active"); +} + +// Tests using sequences. + +TEST(InSequenceTest, AllExpectationInScopeAreInSequence) { + MockA a; + { + InSequence dummy; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(2)); + } + + EXPECT_NONFATAL_FAILURE({ // NOLINT + a.DoA(2); + }, "Unexpected mock function call"); + + a.DoA(1); + a.DoA(2); +} + +TEST(InSequenceTest, NestedInSequence) { + MockA a; + { + InSequence dummy; + + EXPECT_CALL(a, DoA(1)); + { + InSequence dummy2; + + EXPECT_CALL(a, DoA(2)); + EXPECT_CALL(a, DoA(3)); + } + } + + EXPECT_NONFATAL_FAILURE({ // NOLINT + a.DoA(1); + a.DoA(3); + }, "Unexpected mock function call"); + + a.DoA(2); + a.DoA(3); +} + +TEST(InSequenceTest, ExpectationsOutOfScopeAreNotAffected) { + MockA a; + { + InSequence dummy; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(2)); + } + EXPECT_CALL(a, DoA(3)); + + EXPECT_NONFATAL_FAILURE({ // NOLINT + a.DoA(2); + }, "Unexpected mock function call"); + + a.DoA(3); + a.DoA(1); + a.DoA(2); +} + +// Tests that any order is allowed when no sequence is used. +TEST(SequenceTest, AnyOrderIsOkByDefault) { + { + MockA a; + MockB b; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(b, DoB()) + .Times(AnyNumber()); + + a.DoA(1); + b.DoB(); + } + + { // NOLINT + MockA a; + MockB b; + + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(b, DoB()) + .Times(AnyNumber()); + + b.DoB(); + a.DoA(1); + } +} + +#ifdef GTEST_HAS_DEATH_TEST + +// Tests that the calls must be in strict order when a complete order +// is specified. +TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo) { + MockA a; + Sequence s; + + EXPECT_CALL(a, ReturnResult(1)) + .InSequence(s) + .WillOnce(Return(Result())); + + EXPECT_CALL(a, ReturnResult(2)) + .InSequence(s) + .WillOnce(Return(Result())); + + EXPECT_CALL(a, ReturnResult(3)) + .InSequence(s) + .WillOnce(Return(Result())); + + EXPECT_DEATH({ // NOLINT + a.ReturnResult(1); + a.ReturnResult(3); + a.ReturnResult(2); + }, ""); + + EXPECT_DEATH({ // NOLINT + a.ReturnResult(2); + a.ReturnResult(1); + a.ReturnResult(3); + }, ""); + + a.ReturnResult(1); + a.ReturnResult(2); + a.ReturnResult(3); +} + +// Tests specifying a DAG using multiple sequences. +TEST(SequenceTest, CallsMustConformToSpecifiedDag) { + MockA a; + MockB b; + Sequence x, y; + + EXPECT_CALL(a, ReturnResult(1)) + .InSequence(x) + .WillOnce(Return(Result())); + + EXPECT_CALL(b, DoB()) + .Times(2) + .InSequence(y); + + EXPECT_CALL(a, ReturnResult(2)) + .InSequence(x, y) + .WillRepeatedly(Return(Result())); + + EXPECT_CALL(a, ReturnResult(3)) + .InSequence(x) + .WillOnce(Return(Result())); + + EXPECT_DEATH({ // NOLINT + a.ReturnResult(1); + b.DoB(); + a.ReturnResult(2); + }, ""); + + EXPECT_DEATH({ // NOLINT + a.ReturnResult(2); + }, ""); + + EXPECT_DEATH({ // NOLINT + a.ReturnResult(3); + }, ""); + + EXPECT_DEATH({ // NOLINT + a.ReturnResult(1); + b.DoB(); + b.DoB(); + a.ReturnResult(3); + a.ReturnResult(2); + }, ""); + + b.DoB(); + a.ReturnResult(1); + b.DoB(); + a.ReturnResult(3); +} + +#endif // GTEST_HAS_DEATH_TEST + +TEST(SequenceTest, Retirement) { + MockA a; + Sequence s; + + EXPECT_CALL(a, DoA(1)) + .InSequence(s); + EXPECT_CALL(a, DoA(_)) + .InSequence(s) + .RetiresOnSaturation(); + EXPECT_CALL(a, DoA(1)) + .InSequence(s); + + a.DoA(1); + a.DoA(2); + a.DoA(1); +} + +// Tests that Google Mock correctly handles calls to mock functions +// after a mock object owning one of their pre-requisites has died. + +// Tests that calls that satisfy the original spec are successful. +TEST(DeletingMockEarlyTest, Success1) { + MockB* const b1 = new MockB; + MockA* const a = new MockA; + MockB* const b2 = new MockB; + + { + InSequence dummy; + EXPECT_CALL(*b1, DoB(_)) + .WillOnce(Return(1)); + EXPECT_CALL(*a, Binary(_, _)) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(*b2, DoB(_)) + .Times(AnyNumber()) + .WillRepeatedly(Return(2)); + } + + EXPECT_EQ(1, b1->DoB(1)); + delete b1; + // a's pre-requisite has died. + EXPECT_TRUE(a->Binary(0, 1)); + delete b2; + // a's successor has died. + EXPECT_TRUE(a->Binary(1, 2)); + delete a; +} + +// Tests that calls that satisfy the original spec are successful. +TEST(DeletingMockEarlyTest, Success2) { + MockB* const b1 = new MockB; + MockA* const a = new MockA; + MockB* const b2 = new MockB; + + { + InSequence dummy; + EXPECT_CALL(*b1, DoB(_)) + .WillOnce(Return(1)); + EXPECT_CALL(*a, Binary(_, _)) + .Times(AnyNumber()); + EXPECT_CALL(*b2, DoB(_)) + .Times(AnyNumber()) + .WillRepeatedly(Return(2)); + } + + delete a; // a is trivially satisfied. + EXPECT_EQ(1, b1->DoB(1)); + EXPECT_EQ(2, b2->DoB(2)); + delete b1; + delete b2; +} + +// Tests that calls that violates the original spec yield failures. +TEST(DeletingMockEarlyTest, Failure1) { + MockB* const b1 = new MockB; + MockA* const a = new MockA; + MockB* const b2 = new MockB; + + { + InSequence dummy; + EXPECT_CALL(*b1, DoB(_)) + .WillOnce(Return(1)); + EXPECT_CALL(*a, Binary(_, _)) + .Times(AnyNumber()); + EXPECT_CALL(*b2, DoB(_)) + .Times(AnyNumber()) + .WillRepeatedly(Return(2)); + } + + delete a; // a is trivially satisfied. + EXPECT_NONFATAL_FAILURE({ + b2->DoB(2); + }, "Unexpected mock function call"); + EXPECT_EQ(1, b1->DoB(1)); + delete b1; + delete b2; +} + +// Tests that calls that violates the original spec yield failures. +TEST(DeletingMockEarlyTest, Failure2) { + MockB* const b1 = new MockB; + MockA* const a = new MockA; + MockB* const b2 = new MockB; + + { + InSequence dummy; + EXPECT_CALL(*b1, DoB(_)); + EXPECT_CALL(*a, Binary(_, _)) + .Times(AnyNumber()); + EXPECT_CALL(*b2, DoB(_)) + .Times(AnyNumber()); + } + + EXPECT_NONFATAL_FAILURE(delete b1, + "Actual: never called"); + EXPECT_NONFATAL_FAILURE(a->Binary(0, 1), + "Unexpected mock function call"); + EXPECT_NONFATAL_FAILURE(b2->DoB(1), + "Unexpected mock function call"); + delete a; + delete b2; +} + +class EvenNumberCardinality : public CardinalityInterface { + public: + // Returns true iff call_count calls will satisfy this cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const { + return call_count % 2 == 0; + } + + // Returns true iff call_count calls will saturate this cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const { return false; } + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const { + *os << "called even number of times"; + } +}; + +Cardinality EvenNumber() { + return Cardinality(new EvenNumberCardinality); +} + +TEST(ExpectationBaseTest, + AllPrerequisitesAreSatisfiedWorksForNonMonotonicCardinality) { + MockA* a = new MockA; + Sequence s; + + EXPECT_CALL(*a, DoA(1)) + .Times(EvenNumber()) + .InSequence(s); + EXPECT_CALL(*a, DoA(2)) + .Times(AnyNumber()) + .InSequence(s); + EXPECT_CALL(*a, DoA(3)) + .Times(AnyNumber()); + + a->DoA(3); + a->DoA(1); + EXPECT_NONFATAL_FAILURE(a->DoA(2), "Unexpected mock function call"); + EXPECT_NONFATAL_FAILURE(delete a, "to be called even number of times"); +} + +// The following tests verify the message generated when a mock +// function is called. + +struct Printable { +}; + +inline void operator<<(::std::ostream& os, const Printable&) { + os << "Printable"; +} + +struct Unprintable { + Unprintable() : value(0) {} + int value; +}; + +class MockC { + public: + MOCK_METHOD6(VoidMethod, void(bool cond, int n, string s, void* p, + const Printable& x, Unprintable y)); + MOCK_METHOD0(NonVoidMethod, int()); // NOLINT +}; + +// TODO(wan@google.com): find a way to re-enable these tests. +#if 0 + +// Tests that an uninteresting mock function call generates a warning +// containing the stack trace. +TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { + MockC c; + CaptureTestStdout(); + c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); + const string& output = GetCapturedTestStdout(); + EXPECT_PRED_FORMAT2(IsSubstring, "GMOCK WARNING", output); + EXPECT_PRED_FORMAT2(IsSubstring, "Stack trace:", output); +#ifndef NDEBUG + // We check the stack trace content in dbg-mode only, as opt-mode + // may inline the call we are interested in seeing. + + // Verifies that a void mock function's name appears in the stack + // trace. + EXPECT_PRED_FORMAT2(IsSubstring, "::MockC::VoidMethod(", output); + + // Verifies that a non-void mock function's name appears in the + // stack trace. + CaptureTestStdout(); + c.NonVoidMethod(); + const string& output2 = GetCapturedTestStdout(); + EXPECT_PRED_FORMAT2(IsSubstring, "::MockC::NonVoidMethod(", output2); +#endif // NDEBUG +} + +// Tests that an uninteresting mock function call causes the function +// arguments and return value to be printed. +TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { + // A non-void mock function. + MockB b; + CaptureTestStdout(); + b.DoB(); + const string& output1 = GetCapturedTestStdout(); + EXPECT_PRED_FORMAT2( + IsSubstring, + "Uninteresting mock function call - returning default value.\n" + " Function call: DoB()\n" + " Returns: 0\n", output1); + // Makes sure the return value is printed. + + // A void mock function. + MockC c; + CaptureTestStdout(); + c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); + const string& output2 = GetCapturedTestStdout(); + EXPECT_PRED2(RE::PartialMatch, output2, + "Uninteresting mock function call - returning directly\\.\n" + " Function call: VoidMethod" + "\\(false, 5, \"Hi\", NULL, @0x\\w+ " + "Printable, 4-byte object <0000 0000>\\)"); + // A void function has no return value to print. +} + +// Tests how the --gmock_verbose flag affects Google Mock's output. + +class GMockVerboseFlagTest : public testing::Test { + public: + // Verifies that the given Google Mock output is correct. (When + // should_print is true, the output should match the given regex and + // contain the given function name in the stack trace. When it's + // false, the output should be empty.) + void VerifyOutput(const string& output, bool should_print, + const string& regex, + const string& function_name) { + if (should_print) { + EXPECT_PRED2(RE::PartialMatch, output, regex); +#ifndef NDEBUG + // We check the stack trace content in dbg-mode only, as opt-mode + // may inline the call we are interested in seeing. + EXPECT_PRED_FORMAT2(IsSubstring, function_name, output); +#endif // NDEBUG + } else { + EXPECT_EQ("", output); + } + } + + // Tests how the flag affects expected calls. + void TestExpectedCall(bool should_print) { + MockA a; + EXPECT_CALL(a, DoA(5)); + EXPECT_CALL(a, Binary(_, 1)) + .WillOnce(Return(true)); + + // A void-returning function. + CaptureTestStdout(); + a.DoA(5); + VerifyOutput( + GetCapturedTestStdout(), + should_print, + "Expected mock function call\\.\n" + " Function call: DoA\\(5\\)\n" + "Stack trace:", + "MockA::DoA"); + + // A non-void-returning function. + CaptureTestStdout(); + a.Binary(2, 1); + VerifyOutput( + GetCapturedTestStdout(), + should_print, + "Expected mock function call\\.\n" + " Function call: Binary\\(2, 1\\)\n" + " Returns: true\n" + "Stack trace:", + "MockA::Binary"); + } + + // Tests how the flag affects uninteresting calls. + void TestUninterestingCall(bool should_print) { + MockA a; + + // A void-returning function. + CaptureTestStdout(); + a.DoA(5); + VerifyOutput( + GetCapturedTestStdout(), + should_print, + "\nGMOCK WARNING:\n" + "Uninteresting mock function call - returning directly\\.\n" + " Function call: DoA\\(5\\)\n" + "Stack trace:\n" + "[\\s\\S]*", + "MockA::DoA"); + + // A non-void-returning function. + CaptureTestStdout(); + a.Binary(2, 1); + VerifyOutput( + GetCapturedTestStdout(), + should_print, + "\nGMOCK WARNING:\n" + "Uninteresting mock function call - returning default value\\.\n" + " Function call: Binary\\(2, 1\\)\n" + " Returns: false\n" + "Stack trace:\n" + "[\\s\\S]*", + "MockA::Binary"); + } +}; + +// Tests that --gmock_verbose=info causes both expected and +// uninteresting calls to be reported. +TEST_F(GMockVerboseFlagTest, Info) { + GMOCK_FLAG(verbose) = kInfoVerbosity; + TestExpectedCall(true); + TestUninterestingCall(true); +} + +// Tests that --gmock_verbose=warning causes uninteresting calls to be +// reported. +TEST_F(GMockVerboseFlagTest, Warning) { + GMOCK_FLAG(verbose) = kWarningVerbosity; + TestExpectedCall(false); + TestUninterestingCall(true); +} + +// Tests that --gmock_verbose=warning causes neither expected nor +// uninteresting calls to be reported. +TEST_F(GMockVerboseFlagTest, Error) { + GMOCK_FLAG(verbose) = kErrorVerbosity; + TestExpectedCall(false); + TestUninterestingCall(false); +} + +// Tests that --gmock_verbose=SOME_INVALID_VALUE has the same effect +// as --gmock_verbose=warning. +TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { + GMOCK_FLAG(verbose) = "invalid"; // Treated as "warning". + TestExpectedCall(false); + TestUninterestingCall(true); +} + +#endif // 0 + + +// Tests that we can verify and clear a mock object's expectations +// when none of its methods has expectations. +TEST(VerifyAndClearExpectationsTest, NoMethodHasExpectations) { + MockB b; + ASSERT_TRUE(Mock::VerifyAndClearExpectations(&b)); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can verify and clear a mock object's expectations +// when some, but not all, of its methods have expectations *and* the +// verification succeeds. +TEST(VerifyAndClearExpectationsTest, SomeMethodsHaveExpectationsAndSucceed) { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)); + b.DoB(); + ASSERT_TRUE(Mock::VerifyAndClearExpectations(&b)); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can verify and clear a mock object's expectations +// when some, but not all, of its methods have expectations *and* the +// verification fails. +TEST(VerifyAndClearExpectationsTest, SomeMethodsHaveExpectationsAndFail) { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)); + bool result; + EXPECT_NONFATAL_FAILURE(result = Mock::VerifyAndClearExpectations(&b), + "Actual: never called"); + ASSERT_FALSE(result); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can verify and clear a mock object's expectations +// when all of its methods have expectations. +TEST(VerifyAndClearExpectationsTest, AllMethodsHaveExpectations) { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)); + EXPECT_CALL(b, DoB(_)) + .WillOnce(Return(2)); + b.DoB(); + b.DoB(1); + ASSERT_TRUE(Mock::VerifyAndClearExpectations(&b)); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can verify and clear a mock object's expectations +// when a method has more than one expectation. +TEST(VerifyAndClearExpectationsTest, AMethodHasManyExpectations) { + MockB b; + EXPECT_CALL(b, DoB(0)) + .WillOnce(Return(1)); + EXPECT_CALL(b, DoB(_)) + .WillOnce(Return(2)); + b.DoB(1); + bool result; + EXPECT_NONFATAL_FAILURE(result = Mock::VerifyAndClearExpectations(&b), + "Actual: never called"); + ASSERT_FALSE(result); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can call VerifyAndClearExpectations() on the same +// mock object multiple times. +TEST(VerifyAndClearExpectationsTest, CanCallManyTimes) { + MockB b; + EXPECT_CALL(b, DoB()); + b.DoB(); + Mock::VerifyAndClearExpectations(&b); + + EXPECT_CALL(b, DoB(_)) + .WillOnce(Return(1)); + b.DoB(1); + Mock::VerifyAndClearExpectations(&b); + Mock::VerifyAndClearExpectations(&b); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can clear a mock object's default actions when none +// of its methods has default actions. +TEST(VerifyAndClearTest, NoMethodHasDefaultActions) { + MockB b; + // If this crashes or generates a failure, the test will catch it. + Mock::VerifyAndClear(&b); + EXPECT_EQ(0, b.DoB()); +} + +// Tests that we can clear a mock object's default actions when some, +// but not all of its methods have default actions. +TEST(VerifyAndClearTest, SomeMethodsHaveDefaultActions) { + MockB b; + ON_CALL(b, DoB()) + .WillByDefault(Return(1)); + + Mock::VerifyAndClear(&b); + + // Verifies that the default action of int DoB() was removed. + EXPECT_EQ(0, b.DoB()); +} + +// Tests that we can clear a mock object's default actions when all of +// its methods have default actions. +TEST(VerifyAndClearTest, AllMethodsHaveDefaultActions) { + MockB b; + ON_CALL(b, DoB()) + .WillByDefault(Return(1)); + ON_CALL(b, DoB(_)) + .WillByDefault(Return(2)); + + Mock::VerifyAndClear(&b); + + // Verifies that the default action of int DoB() was removed. + EXPECT_EQ(0, b.DoB()); + + // Verifies that the default action of int DoB(int) was removed. + EXPECT_EQ(0, b.DoB(0)); +} + +// Tests that we can clear a mock object's default actions when a +// method has more than one ON_CALL() set on it. +TEST(VerifyAndClearTest, AMethodHasManyDefaultActions) { + MockB b; + ON_CALL(b, DoB(0)) + .WillByDefault(Return(1)); + ON_CALL(b, DoB(_)) + .WillByDefault(Return(2)); + + Mock::VerifyAndClear(&b); + + // Verifies that the default actions (there are two) of int DoB(int) + // were removed. + EXPECT_EQ(0, b.DoB(0)); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can call VerifyAndClear() on a mock object multiple +// times. +TEST(VerifyAndClearTest, CanCallManyTimes) { + MockB b; + ON_CALL(b, DoB()) + .WillByDefault(Return(1)); + Mock::VerifyAndClear(&b); + Mock::VerifyAndClear(&b); + + ON_CALL(b, DoB(_)) + .WillByDefault(Return(1)); + Mock::VerifyAndClear(&b); + + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that VerifyAndClear() works when the verification succeeds. +TEST(VerifyAndClearTest, Success) { + MockB b; + ON_CALL(b, DoB()) + .WillByDefault(Return(1)); + EXPECT_CALL(b, DoB(1)) + .WillOnce(Return(2)); + + b.DoB(); + b.DoB(1); + ASSERT_TRUE(Mock::VerifyAndClear(&b)); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that VerifyAndClear() works when the verification fails. +TEST(VerifyAndClearTest, Failure) { + MockB b; + ON_CALL(b, DoB(_)) + .WillByDefault(Return(1)); + EXPECT_CALL(b, DoB()) + .WillOnce(Return(2)); + + b.DoB(1); + bool result; + EXPECT_NONFATAL_FAILURE(result = Mock::VerifyAndClear(&b), + "Actual: never called"); + ASSERT_FALSE(result); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that VerifyAndClear() works when the default actions and +// expectations are set on a const mock object. +TEST(VerifyAndClearTest, Const) { + MockB b; + ON_CALL(Const(b), DoB()) + .WillByDefault(Return(1)); + + EXPECT_CALL(Const(b), DoB()) + .WillOnce(DoDefault()) + .WillOnce(Return(2)); + + b.DoB(); + b.DoB(); + ASSERT_TRUE(Mock::VerifyAndClear(&b)); + + // There should be no expectations on the methods now, so we can + // freely call them. + EXPECT_EQ(0, b.DoB()); + EXPECT_EQ(0, b.DoB(1)); +} + +// Tests that we can set default actions and expectations on a mock +// object after VerifyAndClear() has been called on it. +TEST(VerifyAndClearTest, CanSetDefaultActionsAndExpectationsAfterwards) { + MockB b; + ON_CALL(b, DoB()) + .WillByDefault(Return(1)); + EXPECT_CALL(b, DoB(_)) + .WillOnce(Return(2)); + b.DoB(1); + + Mock::VerifyAndClear(&b); + + EXPECT_CALL(b, DoB()) + .WillOnce(Return(3)); + ON_CALL(b, DoB(_)) + .WillByDefault(Return(4)); + + EXPECT_EQ(3, b.DoB()); + EXPECT_EQ(4, b.DoB(1)); +} + +// Tests that calling VerifyAndClear() on one mock object does not +// affect other mock objects (either of the same type or not). +TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) { + MockA a; + MockB b1; + MockB b2; + + ON_CALL(a, Binary(_, _)) + .WillByDefault(Return(true)); + EXPECT_CALL(a, Binary(_, _)) + .WillOnce(DoDefault()) + .WillOnce(Return(false)); + + ON_CALL(b1, DoB()) + .WillByDefault(Return(1)); + EXPECT_CALL(b1, DoB(_)) + .WillOnce(Return(2)); + + ON_CALL(b2, DoB()) + .WillByDefault(Return(3)); + EXPECT_CALL(b2, DoB(_)); + + b2.DoB(0); + Mock::VerifyAndClear(&b2); + + // Verifies that the default actions and expectations of a and b1 + // are still in effect. + EXPECT_TRUE(a.Binary(0, 0)); + EXPECT_FALSE(a.Binary(0, 0)); + + EXPECT_EQ(1, b1.DoB()); + EXPECT_EQ(2, b1.DoB(0)); +} + +// Tests that a mock function's action can call a mock function +// (either the same function or a different one) either as an explicit +// action or as a default action without causing a dead lock. It +// verifies that the action is not performed inside the critical +// section. + +void Helper(MockC* c) { + c->NonVoidMethod(); +} + +} // namespace diff --git a/test/gmock_link_test.cc b/test/gmock_link_test.cc new file mode 100644 index 00000000..8a60e8bf --- /dev/null +++ b/test/gmock_link_test.cc @@ -0,0 +1,37 @@ +// 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) + +// This file is for verifying that a header file defining a mock class +// can be included in multiple translation units without causing a +// link error. It doesn't have to actually do anything - we are only +// checking that the test links correctly. + +#include "test/gmock-sample.h" diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py new file mode 100755 index 00000000..f7f37abb --- /dev/null +++ b/test/gmock_output_test.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# +# 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. + +"""Tests the text output of Google C++ Mocking Framework. + +SYNOPSIS + gmock_output_test.py --gmock_build_dir=BUILD/DIR --gengolden + # where BUILD/DIR contains the built gmock_output_test_ file. + gmock_output_test.py --gengolden + gmock_output_test.py +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import gmock_test_utils +import os +import re +import string +import sys +import unittest + + +# The flag for generating the golden file +GENGOLDEN_FLAG = '--gengolden' + +IS_WINDOWS = os.name == 'nt' + +if IS_WINDOWS: + PROGRAM = r'..\build.dbg\gmock_output_test_.exe' +else: + PROGRAM = 'gmock_output_test_' + +PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) +COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0' +GOLDEN_NAME = 'gmock_output_test_golden.txt' +GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), + GOLDEN_NAME) + +def ToUnixLineEnding(s): + """Changes all Windows/Mac line endings in s to UNIX line endings.""" + + return s.replace('\r\n', '\n').replace('\r', '\n') + + +def RemoveReportHeaderAndFooter(output): + """Removes Google Test result report's header and footer from the output.""" + + output = re.sub(r'.*gtest_main.*\n', '', output) + output = re.sub(r'\[.*\d+ tests.*\n', '', output) + output = re.sub(r'\[.* test environment .*\n', '', output) + output = re.sub(r'\[=+\] \d+ tests .* ran.*', '', output) + output = re.sub(r'.* FAILED TESTS\n', '', output) + return output + + +def RemoveLocations(output): + """Removes all file location info from a Google Test program's output. + + Args: + output: the output of a Google Test program. + + Returns: + output with all file location info (in the form of + 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or + 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by + 'FILE:#: '. + """ + + return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\:', 'FILE:#:', output) + + +def NormalizeErrorMarker(output): + """Normalizes the error marker, which is different on Windows vs on Linux.""" + + return re.sub(r' error: ', ' Failure\n', output) + + +def RemoveMemoryAddresses(output): + """Removes memory addresses from the test output.""" + + return re.sub(r'@\w+', '@0x#', output) + + +def NormalizeOutput(output): + """Normalizes output (the output of gmock_output_test_.exe).""" + + output = ToUnixLineEnding(output) + output = RemoveReportHeaderAndFooter(output) + output = NormalizeErrorMarker(output) + output = RemoveLocations(output) + output = RemoveMemoryAddresses(output) + return output + + +def IterShellCommandOutput(cmd, stdin_string=None): + """Runs a command in a sub-process, and iterates the lines in its STDOUT. + + Args: + + cmd: The shell command. + stdin_string: The string to be fed to the STDIN of the sub-process; + If None, the sub-process will inherit the STDIN + from the parent process. + """ + + # Spawns cmd in a sub-process, and gets its standard I/O file objects. + stdin_file, stdout_file = os.popen2(cmd, 'b') + + # If the caller didn't specify a string for STDIN, gets it from the + # parent process. + if stdin_string is None: + stdin_string = sys.stdin.read() + + # Feeds the STDIN string to the sub-process. + stdin_file.write(stdin_string) + stdin_file.close() + + while True: + line = stdout_file.readline() + if not line: # EOF + stdout_file.close() + break + + yield line + + +def GetShellCommandOutput(cmd, stdin_string=None): + """Runs a command in a sub-process, and returns its STDOUT in a string. + + Args: + + cmd: The shell command. + stdin_string: The string to be fed to the STDIN of the sub-process; + If None, the sub-process will inherit the STDIN + from the parent process. + """ + + lines = list(IterShellCommandOutput(cmd, stdin_string)) + return string.join(lines, '') + + +def GetCommandOutput(cmd): + """Runs a command and returns its output with all file location + info stripped off. + + Args: + cmd: the shell command. + """ + + # Disables exception pop-ups on Windows. + os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' + return NormalizeOutput(GetShellCommandOutput(cmd, '')) + + +class GMockOutputTest(unittest.TestCase): + def testOutput(self): + output = GetCommandOutput(COMMAND) + golden_file = open(GOLDEN_PATH, 'rb') + golden = golden_file.read() + golden_file.close() + + self.assertEquals(golden, output) + + +if __name__ == '__main__': + if sys.argv[1:] == [GENGOLDEN_FLAG]: + output = GetCommandOutput(COMMAND) + golden_file = open(GOLDEN_PATH, 'wb') + golden_file.write(output) + golden_file.close() + else: + gmock_test_utils.Main() diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc new file mode 100644 index 00000000..bb56b7cd --- /dev/null +++ b/test/gmock_output_test_.cc @@ -0,0 +1,241 @@ +// 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) + +// Tests Google Mock's output in various scenarios. This ensures that +// Google Mock's messages are readable and useful. + +#include + +#include +#include + +#include + +using testing::_; +using testing::Ge; +using testing::InSequence; +using testing::Ref; +using testing::Return; +using testing::Sequence; + +class MockFoo { + public: + MOCK_METHOD3(Bar, char(const std::string& s, int i, double x)); + MOCK_METHOD2(Bar2, bool(int x, int y)); + MOCK_METHOD2(Bar3, void(int x, int y)); +}; + +class GMockOutputTest : public testing::Test { + protected: + MockFoo foo_; +}; + +TEST_F(GMockOutputTest, ExpectedCall) { + testing::GMOCK_FLAG(verbose) = "info"; + + EXPECT_CALL(foo_, Bar2(0, _)); + foo_.Bar2(0, 0); // Expected call + + testing::GMOCK_FLAG(verbose) = "warning"; +} + +TEST_F(GMockOutputTest, ExpectedCallToVoidFunction) { + testing::GMOCK_FLAG(verbose) = "info"; + + EXPECT_CALL(foo_, Bar3(0, _)); + foo_.Bar3(0, 0); // Expected call + + testing::GMOCK_FLAG(verbose) = "warning"; +} + +TEST_F(GMockOutputTest, ExplicitActionsRunOut) { + EXPECT_CALL(foo_, Bar2(_, _)) + .Times(2) + .WillOnce(Return(false)); + foo_.Bar2(2, 2); + foo_.Bar2(1, 1); // Explicit actions in EXPECT_CALL run out. +} + +TEST_F(GMockOutputTest, UnexpectedCall) { + EXPECT_CALL(foo_, Bar2(0, _)); + + foo_.Bar2(1, 0); // Unexpected call + foo_.Bar2(0, 0); // Expected call +} + +TEST_F(GMockOutputTest, UnexpectedCallToVoidFunction) { + EXPECT_CALL(foo_, Bar3(0, _)); + + foo_.Bar3(1, 0); // Unexpected call + foo_.Bar3(0, 0); // Expected call +} + +TEST_F(GMockOutputTest, ExcessiveCall) { + EXPECT_CALL(foo_, Bar2(0, _)); + + foo_.Bar2(0, 0); // Expected call + foo_.Bar2(0, 1); // Excessive call +} + +TEST_F(GMockOutputTest, ExcessiveCallToVoidFunction) { + EXPECT_CALL(foo_, Bar3(0, _)); + + foo_.Bar3(0, 0); // Expected call + foo_.Bar3(0, 1); // Excessive call +} + +TEST_F(GMockOutputTest, UninterestingCall) { + foo_.Bar2(0, 1); // Uninteresting call +} + +TEST_F(GMockOutputTest, UninterestingCallToVoidFunction) { + foo_.Bar3(0, 1); // Uninteresting call +} + +TEST_F(GMockOutputTest, RetiredExpectation) { + EXPECT_CALL(foo_, Bar2(_, _)) + .RetiresOnSaturation(); + EXPECT_CALL(foo_, Bar2(0, 0)); + + foo_.Bar2(1, 1); + foo_.Bar2(1, 1); // Matches a retired expectation + foo_.Bar2(0, 0); +} + +TEST_F(GMockOutputTest, UnsatisfiedPrerequisite) { + { + InSequence s; + EXPECT_CALL(foo_, Bar(_, 0, _)); + EXPECT_CALL(foo_, Bar2(0, 0)); + EXPECT_CALL(foo_, Bar2(1, _)); + } + + foo_.Bar2(1, 0); // Has one immediate unsatisfied pre-requisite + foo_.Bar("Hi", 0, 0); + foo_.Bar2(0, 0); + foo_.Bar2(1, 0); +} + +TEST_F(GMockOutputTest, UnsatisfiedPrerequisites) { + Sequence s1, s2; + + EXPECT_CALL(foo_, Bar(_, 0, _)) + .InSequence(s1); + EXPECT_CALL(foo_, Bar2(0, 0)) + .InSequence(s2); + EXPECT_CALL(foo_, Bar2(1, _)) + .InSequence(s1, s2); + + foo_.Bar2(1, 0); // Has two immediate unsatisfied pre-requisites + foo_.Bar("Hi", 0, 0); + foo_.Bar2(0, 0); + foo_.Bar2(1, 0); +} + +TEST_F(GMockOutputTest, UnsatisfiedExpectation) { + EXPECT_CALL(foo_, Bar(_, _, _)); + EXPECT_CALL(foo_, Bar2(0, _)) + .Times(2); + + foo_.Bar2(0, 1); +} + +TEST_F(GMockOutputTest, MismatchArguments) { + const std::string s = "Hi"; + EXPECT_CALL(foo_, Bar(Ref(s), _, Ge(0))); + + foo_.Bar("Ho", 0, -0.1); // Mismatch arguments + foo_.Bar(s, 0, 0); +} + +TEST_F(GMockOutputTest, MismatchWithArguments) { + EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1))) + .WithArguments(Ge()); + + foo_.Bar2(2, 3); // Mismatch WithArguments() + foo_.Bar2(2, 1); +} + +TEST_F(GMockOutputTest, MismatchArgumentsAndWithArguments) { + EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1))) + .WithArguments(Ge()); + + foo_.Bar2(1, 3); // Mismatch arguments and mismatch WithArguments() + foo_.Bar2(2, 1); +} + +TEST_F(GMockOutputTest, UnexpectedCallWithDefaultAction) { + ON_CALL(foo_, Bar2(_, _)) + .WillByDefault(Return(true)); // Default action #1 + ON_CALL(foo_, Bar2(1, _)) + .WillByDefault(Return(false)); // Default action #2 + + EXPECT_CALL(foo_, Bar2(2, 2)); + foo_.Bar2(1, 0); // Unexpected call, takes default action #2. + foo_.Bar2(0, 0); // Unexpected call, takes default action #1. + foo_.Bar2(2, 2); // Expected call. +} + +TEST_F(GMockOutputTest, ExcessiveCallWithDefaultAction) { + ON_CALL(foo_, Bar2(_, _)) + .WillByDefault(Return(true)); // Default action #1 + ON_CALL(foo_, Bar2(1, _)) + .WillByDefault(Return(false)); // Default action #2 + + EXPECT_CALL(foo_, Bar2(2, 2)); + EXPECT_CALL(foo_, Bar2(1, 1)); + + foo_.Bar2(2, 2); // Expected call. + foo_.Bar2(2, 2); // Excessive call, takes default action #1. + foo_.Bar2(1, 1); // Expected call. + foo_.Bar2(1, 1); // Excessive call, takes default action #2. +} + +TEST_F(GMockOutputTest, UninterestingCallWithDefaultAction) { + ON_CALL(foo_, Bar2(_, _)) + .WillByDefault(Return(true)); // Default action #1 + ON_CALL(foo_, Bar2(1, _)) + .WillByDefault(Return(false)); // Default action #2 + + foo_.Bar2(2, 2); // Uninteresting call, takes default action #1. + foo_.Bar2(1, 1); // Uninteresting call, takes default action #2. +} + +TEST_F(GMockOutputTest, ExplicitActionsRunOutWithDefaultAction) { + ON_CALL(foo_, Bar2(_, _)) + .WillByDefault(Return(true)); // Default action #1 + + EXPECT_CALL(foo_, Bar2(_, _)) + .Times(2) + .WillOnce(Return(false)); + foo_.Bar2(2, 2); + foo_.Bar2(1, 1); // Explicit actions in EXPECT_CALL run out. +} diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt new file mode 100644 index 00000000..374e6659 --- /dev/null +++ b/test/gmock_output_test_golden.txt @@ -0,0 +1,296 @@ +Running main() from gmock_main.cc +[ RUN ] GMockOutputTest.ExpectedCall + +FILE:#: EXPECT_CALL(foo_, Bar2(0, _)) invoked +Stack trace: + +FILE:#: Expected mock function call. + Function call: Bar2(0, 0) + Returns: false +Stack trace: +[ OK ] GMockOutputTest.ExpectedCall +[ RUN ] GMockOutputTest.ExpectedCallToVoidFunction + +FILE:#: EXPECT_CALL(foo_, Bar3(0, _)) invoked +Stack trace: + +FILE:#: Expected mock function call. + Function call: Bar3(0, 0) +Stack trace: +[ OK ] GMockOutputTest.ExpectedCallToVoidFunction +[ RUN ] GMockOutputTest.ExplicitActionsRunOut + +GMOCK WARNING: +FILE:#: Too few actions specified. +Expected to be called twice, but has only 1 WillOnce(). +GMOCK WARNING: +FILE:#: Actions ran out. +Called 2 times, but only 1 WillOnce() is specified - returning default value. +Stack trace: +[ OK ] GMockOutputTest.ExplicitActionsRunOut +[ RUN ] GMockOutputTest.UnexpectedCall +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar2(1, 0) + Returns: false +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected arg #0: is equal to 0 + Actual: 1 + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnexpectedCall +[ RUN ] GMockOutputTest.UnexpectedCallToVoidFunction +unknown file: Failure + +Unexpected mock function call - returning directly. + Function call: Bar3(1, 0) +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected arg #0: is equal to 0 + Actual: 1 + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnexpectedCallToVoidFunction +[ RUN ] GMockOutputTest.ExcessiveCall +FILE:#: Failure +Mock function called more times than expected - returning default value. + Function call: Bar2(0, 1) + Returns: false + Expected: to be called once + Actual: called twice - over-saturated and active +[ FAILED ] GMockOutputTest.ExcessiveCall +[ RUN ] GMockOutputTest.ExcessiveCallToVoidFunction +FILE:#: Failure +Mock function called more times than expected - returning directly. + Function call: Bar3(0, 1) + Expected: to be called once + Actual: called twice - over-saturated and active +[ FAILED ] GMockOutputTest.ExcessiveCallToVoidFunction +[ RUN ] GMockOutputTest.UninterestingCall + +GMOCK WARNING: +Uninteresting mock function call - returning default value. + Function call: Bar2(0, 1) + Returns: false +Stack trace: +[ OK ] GMockOutputTest.UninterestingCall +[ RUN ] GMockOutputTest.UninterestingCallToVoidFunction + +GMOCK WARNING: +Uninteresting mock function call - returning directly. + Function call: Bar3(0, 1) +Stack trace: +[ OK ] GMockOutputTest.UninterestingCallToVoidFunction +[ RUN ] GMockOutputTest.RetiredExpectation +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar2(1, 1) + Returns: false +Google Mock tried the following 2 expectations, but none matched: + +FILE:#: tried expectation #0 + Expected: the expectation is active + Actual: it is retired + Expected: to be called once + Actual: called once - saturated and retired +FILE:#: tried expectation #1 + Expected arg #0: is equal to 0 + Actual: 1 + Expected arg #1: is equal to 0 + Actual: 1 + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.RetiredExpectation +[ RUN ] GMockOutputTest.UnsatisfiedPrerequisite +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar2(1, 0) + Returns: false +Google Mock tried the following 2 expectations, but none matched: + +FILE:#: tried expectation #0 + Expected arg #0: is equal to 0 + Actual: 1 + Expected: to be called once + Actual: never called - unsatisfied and active +FILE:#: tried expectation #1 + Expected: all pre-requisites are satisfied + Actual: the following immediate pre-requisites are not satisfied: +FILE:#: pre-requisite #0 + (end of pre-requisites) + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnsatisfiedPrerequisite +[ RUN ] GMockOutputTest.UnsatisfiedPrerequisites +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar2(1, 0) + Returns: false +Google Mock tried the following 2 expectations, but none matched: + +FILE:#: tried expectation #0 + Expected arg #0: is equal to 0 + Actual: 1 + Expected: to be called once + Actual: never called - unsatisfied and active +FILE:#: tried expectation #1 + Expected: all pre-requisites are satisfied + Actual: the following immediate pre-requisites are not satisfied: +FILE:#: pre-requisite #0 +FILE:#: pre-requisite #1 + (end of pre-requisites) + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnsatisfiedPrerequisites +[ RUN ] GMockOutputTest.UnsatisfiedExpectation +FILE:#: Failure +Actual function call count doesn't match this expectation. + Expected: to be called twice + Actual: called once - unsatisfied and active +FILE:#: Failure +Actual function call count doesn't match this expectation. + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnsatisfiedExpectation +[ RUN ] GMockOutputTest.MismatchArguments +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar(@0x# "Ho", 0, -0.1) + Returns: '\0' +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected arg #0: references the variable @0x# "Hi" + Actual: "Ho" (is located @0x#) + Expected arg #2: is greater than or equal to 0 + Actual: -0.1 + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.MismatchArguments +[ RUN ] GMockOutputTest.MismatchWithArguments +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar2(2, 3) + Returns: false +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected: argument #0 is greater than or equal to argument #1 + Actual: false + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.MismatchWithArguments +[ RUN ] GMockOutputTest.MismatchArgumentsAndWithArguments +unknown file: Failure + +Unexpected mock function call - returning default value. + Function call: Bar2(1, 3) + Returns: false +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected arg #0: is greater than or equal to 2 + Actual: 1 + Expected: argument #0 is greater than or equal to argument #1 + Actual: false + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.MismatchArgumentsAndWithArguments +[ RUN ] GMockOutputTest.UnexpectedCallWithDefaultAction +unknown file: Failure + +Unexpected mock function call - taking default action specified at: +FILE:#: + Function call: Bar2(1, 0) + Returns: false +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected arg #0: is equal to 2 + Actual: 1 + Expected arg #1: is equal to 2 + Actual: 0 + Expected: to be called once + Actual: never called - unsatisfied and active +unknown file: Failure + +Unexpected mock function call - taking default action specified at: +FILE:#: + Function call: Bar2(0, 0) + Returns: true +Google Mock tried the following 1 expectation, but it didn't match: + +FILE:#: + Expected arg #0: is equal to 2 + Actual: 0 + Expected arg #1: is equal to 2 + Actual: 0 + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction +[ RUN ] GMockOutputTest.ExcessiveCallWithDefaultAction +FILE:#: Failure +Mock function called more times than expected - taking default action specified at: +FILE:#: + Function call: Bar2(2, 2) + Returns: true + Expected: to be called once + Actual: called twice - over-saturated and active +FILE:#: Failure +Mock function called more times than expected - taking default action specified at: +FILE:#: + Function call: Bar2(1, 1) + Returns: false + Expected: to be called once + Actual: called twice - over-saturated and active +[ FAILED ] GMockOutputTest.ExcessiveCallWithDefaultAction +[ RUN ] GMockOutputTest.UninterestingCallWithDefaultAction + +GMOCK WARNING: +Uninteresting mock function call - taking default action specified at: +FILE:#: + Function call: Bar2(2, 2) + Returns: true +Stack trace: + +GMOCK WARNING: +Uninteresting mock function call - taking default action specified at: +FILE:#: + Function call: Bar2(1, 1) + Returns: false +Stack trace: +[ OK ] GMockOutputTest.UninterestingCallWithDefaultAction +[ RUN ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction + +GMOCK WARNING: +FILE:#: Too few actions specified. +Expected to be called twice, but has only 1 WillOnce(). +GMOCK WARNING: +FILE:#: Actions ran out. +Called 2 times, but only 1 WillOnce() is specified - taking default action specified at: +FILE:#: +Stack trace: +[ OK ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction +[ FAILED ] GMockOutputTest.UnexpectedCall +[ FAILED ] GMockOutputTest.UnexpectedCallToVoidFunction +[ FAILED ] GMockOutputTest.ExcessiveCall +[ FAILED ] GMockOutputTest.ExcessiveCallToVoidFunction +[ FAILED ] GMockOutputTest.RetiredExpectation +[ FAILED ] GMockOutputTest.UnsatisfiedPrerequisite +[ FAILED ] GMockOutputTest.UnsatisfiedPrerequisites +[ FAILED ] GMockOutputTest.UnsatisfiedExpectation +[ FAILED ] GMockOutputTest.MismatchArguments +[ FAILED ] GMockOutputTest.MismatchWithArguments +[ FAILED ] GMockOutputTest.MismatchArgumentsAndWithArguments +[ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction +[ FAILED ] GMockOutputTest.ExcessiveCallWithDefaultAction + diff --git a/test/gmock_test.cc b/test/gmock_test.cc new file mode 100644 index 00000000..63c3fe8d --- /dev/null +++ b/test/gmock_test.cc @@ -0,0 +1,248 @@ +// 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) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file tests code in gmock.cc. + +#include + +#include +#include + +using testing::GMOCK_FLAG(verbose); +using testing::InitGoogleMock; +using testing::internal::g_init_gtest_count; + +// Verifies that calling InitGoogleMock() on argv results in new_argv, +// and the gmock_verbose flag's value is set to expected_gmock_verbose. +template +void TestInitGoogleMock(const Char* (&argv)[M], const Char* (&new_argv)[N], + const ::std::string& expected_gmock_verbose) { + const ::std::string old_verbose = GMOCK_FLAG(verbose); + + int argc = M; + InitGoogleMock(&argc, const_cast(argv)); + ASSERT_EQ(N, argc) << "The new argv has wrong number of elements."; + + for (int i = 0; i < N; i++) { + EXPECT_STREQ(new_argv[i], argv[i]); + } + + EXPECT_EQ(expected_gmock_verbose, GMOCK_FLAG(verbose).c_str()); + GMOCK_FLAG(verbose) = old_verbose; // Restores the gmock_verbose flag. +} + +TEST(InitGoogleMockTest, ParsesInvalidCommandLine) { + const char* argv[] = { + NULL + }; + + const char* new_argv[] = { + NULL + }; + + TestInitGoogleMock(argv, new_argv, GMOCK_FLAG(verbose)); +} + +TEST(InitGoogleMockTest, ParsesEmptyCommandLine) { + const char* argv[] = { + "foo.exe", + NULL + }; + + const char* new_argv[] = { + "foo.exe", + NULL + }; + + TestInitGoogleMock(argv, new_argv, GMOCK_FLAG(verbose)); +} + +TEST(InitGoogleMockTest, ParsesSingleFlag) { + const char* argv[] = { + "foo.exe", + "--gmock_verbose=info", + NULL + }; + + const char* new_argv[] = { + "foo.exe", + NULL + }; + + TestInitGoogleMock(argv, new_argv, "info"); +} + +TEST(InitGoogleMockTest, ParsesUnrecognizedFlag) { + const char* argv[] = { + "foo.exe", + "--non_gmock_flag=blah", + NULL + }; + + const char* new_argv[] = { + "foo.exe", + "--non_gmock_flag=blah", + NULL + }; + + TestInitGoogleMock(argv, new_argv, GMOCK_FLAG(verbose)); +} + +TEST(InitGoogleMockTest, ParsesGoogleMockFlagAndUnrecognizedFlag) { + const char* argv[] = { + "foo.exe", + "--non_gmock_flag=blah", + "--gmock_verbose=error", + NULL + }; + + const char* new_argv[] = { + "foo.exe", + "--non_gmock_flag=blah", + NULL + }; + + TestInitGoogleMock(argv, new_argv, "error"); +} + +TEST(InitGoogleMockTest, CallsInitGoogleTest) { + const int old_init_gtest_count = g_init_gtest_count; + const char* argv[] = { + "foo.exe", + "--non_gmock_flag=blah", + "--gmock_verbose=error", + NULL + }; + + const char* new_argv[] = { + "foo.exe", + "--non_gmock_flag=blah", + NULL + }; + + TestInitGoogleMock(argv, new_argv, "error"); + EXPECT_EQ(old_init_gtest_count + 1, g_init_gtest_count); +} + +TEST(WideInitGoogleMockTest, ParsesInvalidCommandLine) { + const wchar_t* argv[] = { + NULL + }; + + const wchar_t* new_argv[] = { + NULL + }; + + TestInitGoogleMock(argv, new_argv, GMOCK_FLAG(verbose)); +} + +TEST(WideInitGoogleMockTest, ParsesEmptyCommandLine) { + const wchar_t* argv[] = { + L"foo.exe", + NULL + }; + + const wchar_t* new_argv[] = { + L"foo.exe", + NULL + }; + + TestInitGoogleMock(argv, new_argv, GMOCK_FLAG(verbose)); +} + +TEST(WideInitGoogleMockTest, ParsesSingleFlag) { + const wchar_t* argv[] = { + L"foo.exe", + L"--gmock_verbose=info", + NULL + }; + + const wchar_t* new_argv[] = { + L"foo.exe", + NULL + }; + + TestInitGoogleMock(argv, new_argv, "info"); +} + +TEST(WideInitGoogleMockTest, ParsesUnrecognizedFlag) { + const wchar_t* argv[] = { + L"foo.exe", + L"--non_gmock_flag=blah", + NULL + }; + + const wchar_t* new_argv[] = { + L"foo.exe", + L"--non_gmock_flag=blah", + NULL + }; + + TestInitGoogleMock(argv, new_argv, GMOCK_FLAG(verbose)); +} + +TEST(WideInitGoogleMockTest, ParsesGoogleMockFlagAndUnrecognizedFlag) { + const wchar_t* argv[] = { + L"foo.exe", + L"--non_gmock_flag=blah", + L"--gmock_verbose=error", + NULL + }; + + const wchar_t* new_argv[] = { + L"foo.exe", + L"--non_gmock_flag=blah", + NULL + }; + + TestInitGoogleMock(argv, new_argv, "error"); +} + +TEST(WideInitGoogleMockTest, CallsInitGoogleTest) { + const int old_init_gtest_count = g_init_gtest_count; + const wchar_t* argv[] = { + L"foo.exe", + L"--non_gmock_flag=blah", + L"--gmock_verbose=error", + NULL + }; + + const wchar_t* new_argv[] = { + L"foo.exe", + L"--non_gmock_flag=blah", + NULL + }; + + TestInitGoogleMock(argv, new_argv, "error"); + EXPECT_EQ(old_init_gtest_count + 1, g_init_gtest_count); +} diff --git a/test/gmock_test_utils.py b/test/gmock_test_utils.py new file mode 100755 index 00000000..4c09e39d --- /dev/null +++ b/test/gmock_test_utils.py @@ -0,0 +1,126 @@ +#!/usr/bin/python2.4 +# +# Copyright 2006, 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. + +"""Unit test utilities for Google C++ Mocking Framework.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import sys +import unittest + + +# Initially maps a flag to its default value. After +# _ParseAndStripGMockFlags() is called, maps a flag to its actual +# value. +_flag_map = {'gmock_source_dir': os.path.dirname(sys.argv[0]), + 'gmock_build_dir': os.path.dirname(sys.argv[0])} +_gmock_flags_are_parsed = False + + +def _ParseAndStripGMockFlags(argv): + """Parses and strips Google Test flags from argv. This is idempotent.""" + + global _gmock_flags_are_parsed + if _gmock_flags_are_parsed: + return + + _gmock_flags_are_parsed = True + for flag in _flag_map: + # The environment variable overrides the default value. + if flag.upper() in os.environ: + _flag_map[flag] = os.environ[flag.upper()] + + # The command line flag overrides the environment variable. + i = 1 # Skips the program name. + while i < len(argv): + prefix = '--' + flag + '=' + if argv[i].startswith(prefix): + _flag_map[flag] = argv[i][len(prefix):] + del argv[i] + break + else: + # We don't increment i in case we just found a --gmock_* flag + # and removed it from argv. + i += 1 + + +def GetFlag(flag): + """Returns the value of the given flag.""" + + # In case GetFlag() is called before Main(), we always call + # _ParseAndStripGMockFlags() here to make sure the --gmock_* flags + # are parsed. + _ParseAndStripGMockFlags(sys.argv) + + return _flag_map[flag] + + +def GetSourceDir(): + """Returns the absolute path of the directory where the .py files are.""" + + return os.path.abspath(GetFlag('gmock_source_dir')) + + +def GetBuildDir(): + """Returns the absolute path of the directory where the test binaries are.""" + + return os.path.abspath(GetFlag('gmock_build_dir')) + + +def GetExitStatus(exit_code): + """Returns the argument to exit(), or -1 if exit() wasn't called. + + Args: + exit_code: the result value of os.system(command). + """ + + if os.name == 'nt': + # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns + # the argument to exit() directly. + return exit_code + else: + # On Unix, os.WEXITSTATUS() must be used to extract the exit status + # from the result of os.system(). + if os.WIFEXITED(exit_code): + return os.WEXITSTATUS(exit_code) + else: + return -1 + + +def Main(): + """Runs the unit test.""" + + # We must call _ParseAndStripGMockFlags() before calling + # unittest.main(). Otherwise the latter will be confused by the + # --gmock_* flags. + _ParseAndStripGMockFlags(sys.argv) + unittest.main() -- cgit v1.2.3 From c6cece77686b0c548043dd52feb9c345b5ae0a68 Mon Sep 17 00:00:00 2001 From: shiqian Date: Wed, 10 Dec 2008 07:50:41 +0000 Subject: Adds Visual Studio projects for building Google Mock. --- Makefile.am | 10 +- README | 36 +++++- msvc/gmock.sln | 44 +++++++ msvc/gmock.vcproj | 263 +++++++++++++++++++++++++++++++++++++++++ msvc/gmock_config.vsprops | 20 ++++ msvc/gmock_link_test.vcproj | 203 +++++++++++++++++++++++++++++++ msvc/gmock_main.vcproj | 187 +++++++++++++++++++++++++++++ msvc/gmock_output_test_.vcproj | 199 +++++++++++++++++++++++++++++++ msvc/gmock_test.vcproj | 247 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 1205 insertions(+), 4 deletions(-) create mode 100755 msvc/gmock.sln create mode 100755 msvc/gmock.vcproj create mode 100755 msvc/gmock_config.vsprops create mode 100755 msvc/gmock_link_test.vcproj create mode 100755 msvc/gmock_main.vcproj create mode 100755 msvc/gmock_output_test_.vcproj create mode 100755 msvc/gmock_test.vcproj diff --git a/Makefile.am b/Makefile.am index 6e6b6ec2..a0c3e9cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -178,4 +178,12 @@ EXTRA_DIST += \ scripts/generator/cpp/utils.py \ scripts/generator/gmock_gen.py -# TODO(wan@google.com): add the MSVC projects to EXTRA_DIST. +# Microsoft Visual Studio 2005 projects. +EXTRA_DIST += \ + msvc/gmock.sln \ + msvc/gmock.vcproj \ + msvc/gmock_config.vsprops \ + msvc/gmock_link_test.vcproj \ + msvc/gmock_main.vcproj \ + msvc/gmock_output_test_.vcproj \ + msvc/gmock_test.vcproj diff --git a/README b/README index 0f382147..77610e28 100644 --- a/README +++ b/README @@ -178,9 +178,39 @@ TODO(chandlerc@google.com): Fixes the above instructions to match the actual implementation. ### Windows ### -We don't have the Visual Studio project files for Google Mock ready -yet. Please see the next two sections on how you can integrate Google -Mock into your project's build system. +The msvc/ directory contains VC++ 2005 projects for building Google Mock and +selected tests. In order to build Google Mock you must have an implementation +of TR1 tuple. One library that provides such implementation is Boost. If you +choose to use Boost, download it from www.boost.org and install it on your +system. After that you have two options: either configure Boost as a system +library or modify the Google Mock project to point to your copy of Boost. The +former solution will let all your tests use the same copy of Boost while the +latter one will let each of your projects use its own copy of Boost. You can +also use a hybrid solution: your project settings will override the system-wide +one. + +For example, if you unpacked boost v1.36.0 into C:\boost: +To configure Boost as a system library. + * Assuming you are using the Visual Studio 2008 IDE, select Tools | + Options | Projects And Solutions | VC++ Directories. + * In the "Show directories for" drop-down select Include Files. Add + * C:\boost\boost_1_36_0\boost\tr1\tr1 and C:\boost\boost_1_36_0 + to the list of directories. + +To configure your project to point to that version of Boost, replace +the value of the BoostDir user macro with C:\boost\boost_1_36_0 in the +msvc/gtest_dep.vsprops file. You can use any text editor to edit that file. + +If you want to use a version of Google Test other then the one bundled with +Google Mock, change the value of the GTestDir macro in gmock_config.vsprop +to point to the new location. + +After configuring Boost, just open msvc/gmock.sln and build the library and +tests. 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 and select it. ### Using GNU Make ### The make/ directory contains a Makefile that you can use to build diff --git a/msvc/gmock.sln b/msvc/gmock.sln new file mode 100755 index 00000000..d084ee71 --- /dev/null +++ b/msvc/gmock.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock", "gmock.vcproj", "{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vcproj", "{F10D22F8-AC7B-4213-8720-608E7D878CD2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_link_test", "gmock_link_test.vcproj", "{ED597847-A714-4327-B569-70029D2311F0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_output_test_", "gmock_output_test_.vcproj", "{EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.Build.0 = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.ActiveCfg = Release|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.Build.0 = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.Build.0 = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.ActiveCfg = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.Build.0 = Release|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.ActiveCfg = Debug|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.Build.0 = Debug|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.ActiveCfg = Release|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.Build.0 = Release|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.ActiveCfg = Debug|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.Build.0 = Debug|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.ActiveCfg = Release|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.Build.0 = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/msvc/gmock.vcproj b/msvc/gmock.vcproj new file mode 100755 index 00000000..a58ed364 --- /dev/null +++ b/msvc/gmock.vcproj @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_config.vsprops b/msvc/gmock_config.vsprops new file mode 100755 index 00000000..93e28686 --- /dev/null +++ b/msvc/gmock_config.vsprops @@ -0,0 +1,20 @@ + + + + + + diff --git a/msvc/gmock_link_test.vcproj b/msvc/gmock_link_test.vcproj new file mode 100755 index 00000000..3f2eea1e --- /dev/null +++ b/msvc/gmock_link_test.vcproj @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_main.vcproj b/msvc/gmock_main.vcproj new file mode 100755 index 00000000..e9581158 --- /dev/null +++ b/msvc/gmock_main.vcproj @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_output_test_.vcproj b/msvc/gmock_output_test_.vcproj new file mode 100755 index 00000000..bcbd96f0 --- /dev/null +++ b/msvc/gmock_output_test_.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj new file mode 100755 index 00000000..5263d867 --- /dev/null +++ b/msvc/gmock_test.vcproj @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From a92e49620ed85276824511302e9703a8093759e7 Mon Sep 17 00:00:00 2001 From: shiqian Date: Wed, 10 Dec 2008 18:34:33 +0000 Subject: More tweaks to the build systems. --- Makefile.am | 4 ++++ configure.ac | 52 ++++++++++++++++++++++++++++------------------- msvc/gmock_config.vsprops | 2 +- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Makefile.am b/Makefile.am index a0c3e9cf..e58f7fee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,10 @@ # Nonstandard package files for distribution. EXTRA_DIST = +# We may need to build our internally packaged gtest. If so, it will be +# included in the 'subdirs' variable. +SUBDIRS = $(subdirs) + # Scripts and utilities to be installed by 'make install'. dist_bin_SCRIPTS = scripts/gmock_doctor.py diff --git a/configure.ac b/configure.ac index daacfdd8..60742504 100644 --- a/configure.ac +++ b/configure.ac @@ -48,8 +48,14 @@ AC_ARG_WITH([gtest], 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([ + [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 @@ -78,35 +84,39 @@ HAVE_BUILT_GTEST="no" # at that point it will become more meaningful. GTEST_MIN_VERSION="1.0.0" -# 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([ +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 with 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 "${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])])])]) -# TODO(chandlerc@google.com): Need to add support for passing a custom prefix -# into the gtest-config script.. 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_MSG_ERROR([TODO(chandlerc@google.com): Need to add support for - building the internal gtest.])]) + [AC_CONFIG_SUBDIRS([gtest]) + GTEST_CONFIG='$(builddir)/gtest/scripts/gtest-config' + GTEST_CPPFLAGS='-I$(srcdir)/gtest/include -I$(srcdir)/gtest' + GTEST_CXXFLAGS='-g' + GTEST_LDFLAGS='' + GTEST_LIBS='$(builddir)/gtest/lib/libgtest.la' + GTEST_VERSION="${GTEST_MIN_VERSION}"]) # TODO(chandlerc@google.com) Check the types, structures, and other compiler # and architecture characteristics. diff --git a/msvc/gmock_config.vsprops b/msvc/gmock_config.vsprops index 93e28686..89b50aa7 100755 --- a/msvc/gmock_config.vsprops +++ b/msvc/gmock_config.vsprops @@ -15,6 +15,6 @@ /> -- cgit v1.2.3 From 281b1d21dbd77bdf60c3d1c61a4e82420951268d Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 11 Dec 2008 00:13:55 +0000 Subject: More tweaks to the build script. --- Makefile.am | 4 + README | 31 ++--- configure.ac | 14 +-- scripts/gmock-config.in | 303 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 330 insertions(+), 22 deletions(-) create mode 100755 scripts/gmock-config.in diff --git a/Makefile.am b/Makefile.am index e58f7fee..4a5a3fd6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,10 @@ SUBDIRS = $(subdirs) # Scripts and utilities to be installed by 'make install'. dist_bin_SCRIPTS = scripts/gmock_doctor.py +bin_SCRIPTS = scripts/gmock-config + +# 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. diff --git a/README b/README index 77610e28..47d10edb 100644 --- a/README +++ b/README @@ -40,10 +40,8 @@ testing framework for writing tests. Currently Google Mock only works with Google Test (http://code.google.com/p/googletest/), although eventually we plan to support other C++ testing frameworks. You can use either the copy of Google Test that comes with Google Mock, or a -compatible version you already have. - -TODO(wan@google.com): describe which Google Test versions are -compatible with the latest Google Mock release. +compatible version you already have. This version of Google Mock +requires Google Test 1.2.1. Google Mock depends on advanced C++ features and thus requires a more modern compiler. The following are needed to use Google Mock: @@ -101,20 +99,23 @@ or for a release version X.Y.*'s branch: Next you will need to prepare the GNU Autotools build system, if you are using Linux or Mac OS X. Enter the target directory of the checkout command you used ('gmock-svn' or 'gmock-X.Y-svn' above) and -proceed with the following commands: +proceed with the following command: + + $ autoreconf -fvi + +Once you have completed this step, you are ready to build the library. +Note that you should need to complete this step only once. The sub- +sequent `make' invocations will automatically re-generate the bits of +the build system that need to be changed. - $ aclocal-1.9 # Where "1.9" must match the following automake command. - $ libtoolize -c # Use "glibtoolize -c" instead on Mac OS X. - $ autoheader - $ automake-1.9 -ac # See Automake version requirements above. - $ autoconf +If your system uses older versions of the autotools, the above command will +fail. You may need to explicitly specify a version to use. For instance, if +you have both GNU Automake 1.4 and 1.9 installed and `automake' would invoke +the 1.4, use instead: -While this is a bit complicated, it will most often be automatically re-run by -your "make" invocations, so in practice you shouldn't need to worry too much. -Once you have completed these steps, you are ready to build the library. + $ AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi -TODO(chandlerc@google.com): Update the above with instructions on -preparing the build system for Google Test. +Make sure you're using the same version of automake and aclocal. ### Source Package: ### Google Mock is also released in source packages which can be downloaded from diff --git a/configure.ac b/configure.ac index 60742504..65a48b4a 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ AC_CONFIG_SRCDIR([./COPYING]) 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 @@ -79,10 +80,7 @@ AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" -# TODO(chandlerc@google.com): This is arbitrary, but we will need to introduce -# some features to the GoogleTest build system to help support GoogleMock, and -# at that point it will become more meaningful. -GTEST_MIN_VERSION="1.0.0" +GTEST_MIN_VERSION="1.2.1" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. @@ -111,11 +109,13 @@ AS_IF([test "x${HAVE_BUILT_GTEST}" = "xyes"], GTEST_LIBS=`${GTEST_CONFIG} --libs` GTEST_VERSION=`${GTEST_CONFIG} --version`], [AC_CONFIG_SUBDIRS([gtest]) - GTEST_CONFIG='$(builddir)/gtest/scripts/gtest-config' - GTEST_CPPFLAGS='-I$(srcdir)/gtest/include -I$(srcdir)/gtest' + # 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`/gtest/scripts/gtest-config" + GTEST_CPPFLAGS='-I$(top_srcdir)/gtest/include' GTEST_CXXFLAGS='-g' GTEST_LDFLAGS='' - GTEST_LIBS='$(builddir)/gtest/lib/libgtest.la' + GTEST_LIBS='$(top_builddir)/gtest/lib/libgtest.la' GTEST_VERSION="${GTEST_MIN_VERSION}"]) # TODO(chandlerc@google.com) Check the types, structures, and other compiler diff --git a/scripts/gmock-config.in b/scripts/gmock-config.in new file mode 100755 index 00000000..540faff7 --- /dev/null +++ b/scripts/gmock-config.in @@ -0,0 +1,303 @@ +#!/bin/sh + +# These variables are automatically filled in by the configure script. +name="@PACKAGE_TARNAME@" +version="@PACKAGE_VERSION@" + +show_usage() +{ + echo "Usage: gmock-config [OPTIONS...]" +} + +show_help() +{ + show_usage + cat <<\EOF + +The `gmock-config' script provides access to the necessary compile and linking +flags to connect with Google C++ Mocking Framework, both in a build prior to +installation, and on the system proper after installation. The installation +overrides may be issued in combination with any other queries, but will only +affect installation queries if called on a built but not installed gmock. The +installation queries may not be issued with any other types of queries, and +only one installation query may be made at a time. The version queries and +compiler flag queries may be combined as desired but not mixed. Different +version queries are always combined with logical "and" semantics, and only the +last of any particular query is used while all previous ones ignored. All +versions must be specified as a sequence of numbers separated by periods. +Compiler flag queries output the union of the sets of flags when combined. + + Examples: + gmock-config --min-version=1.0 || echo "Insufficient Google Mock version." + + g++ $(gmock-config --cppflags --cxxflags) -o foo.o -c foo.cpp + g++ $(gmock-config --ldflags --libs) -o foo foo.o + + # When using a built but not installed Google Mock: + g++ $(../../my_gmock_build/scripts/gtest-config ...) ... + + # When using an installed Google Mock, but with installation overrides: + export GMOCK_PREFIX="/opt" + g++ $(gmock-config --libdir="/opt/lib64" ...) ... + + Help: + --usage brief usage information + --help display this help message + + Installation Overrides: + --prefix= overrides the installation prefix + --exec-prefix= overrides the executable installation prefix + --libdir= overrides the library installation prefix + --includedir= overrides the header file installation prefix + + Installation Queries: + --prefix installation prefix + --exec-prefix executable installation prefix + --libdir library installation directory + --includedir header file installation directory + --version the version of the Google Mock installation + + Version Queries: + --min-version=VERSION return 0 if the version is at least VERSION + --exact-version=VERSION return 0 if the version is exactly VERSION + --max-version=VERSION return 0 if the version is at most VERSION + + Compilation Flag Queries: + --cppflags compile flags specific to the C-like preprocessors + --cxxflags compile flags appropriate for C++ programs + --ldflags linker flags + --libs libraries for linking + +EOF +} + +# This function bounds our version with a min and a max. It uses some clever +# POSIX-compliant variable expansion to portably do all the work in the shell +# and avoid any dependency on a particular "sed" or "awk" implementation. +# Notable is that it will only ever compare the first 3 components of versions. +# Further components will be cleanly stripped off. All versions must be +# unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and +# the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should +# investigate expanding this via autom4te from AS_VERSION_COMPARE rather than +# continuing to maintain our own shell version. +check_versions() +{ + major_version=${version%%.*} + minor_version="0" + point_version="0" + if test "${version#*.}" != "${version}"; then + minor_version=${version#*.} + minor_version=${minor_version%%.*} + fi + if test "${version#*.*.}" != "${version}"; then + point_version=${version#*.*.} + point_version=${point_version%%.*} + fi + + min_version="$1" + min_major_version=${min_version%%.*} + min_minor_version="0" + min_point_version="0" + if test "${min_version#*.}" != "${min_version}"; then + min_minor_version=${min_version#*.} + min_minor_version=${min_minor_version%%.*} + fi + if test "${min_version#*.*.}" != "${min_version}"; then + min_point_version=${min_version#*.*.} + min_point_version=${min_point_version%%.*} + fi + + max_version="$2" + max_major_version=${max_version%%.*} + max_minor_version="0" + max_point_version="0" + if test "${max_version#*.}" != "${max_version}"; then + max_minor_version=${max_version#*.} + max_minor_version=${max_minor_version%%.*} + fi + if test "${max_version#*.*.}" != "${max_version}"; then + max_point_version=${max_version#*.*.} + max_point_version=${max_point_version%%.*} + fi + + test $(($major_version)) -lt $(($min_major_version)) && exit 1 + if test $(($major_version)) -eq $(($min_major_version)); then + test $(($minor_version)) -lt $(($min_minor_version)) && exit 1 + if test $(($minor_version)) -eq $(($min_minor_version)); then + test $(($point_version)) -lt $(($min_point_version)) && exit 1 + fi + fi + + test $(($major_version)) -gt $(($max_major_version)) && exit 1 + if test $(($major_version)) -eq $(($max_major_version)); then + test $(($minor_version)) -gt $(($max_minor_version)) && exit 1 + if test $(($minor_version)) -eq $(($max_minor_version)); then + test $(($point_version)) -gt $(($max_point_version)) && exit 1 + fi + fi + + exit 0 +} + +# Show the usage line when no arguments are specified. +if test $# -eq 0; then + show_usage + exit 1 +fi + +while test $# -gt 0; do + case $1 in + --usage) show_usage; exit 0;; + --help) show_help; exit 0;; + + # Installation overrides + --prefix=*) GMOCK_PREFIX=${1#--prefix=};; + --exec-prefix=*) GMOCK_EXEC_PREFIX=${1#--exec-prefix=};; + --libdir=*) GMOCK_LIBDIR=${1#--libdir=};; + --includedir=*) GMOCK_INCLUDEDIR=${1#--includedir=};; + + # Installation queries + --prefix|--exec-prefix|--libdir|--includedir|--version) + if test -n "${do_query}"; then + show_usage + exit 1 + fi + do_query=${1#--} + ;; + + # Version checking + --min-version=*) + do_check_versions=yes + min_version=${1#--min-version=} + ;; + --max-version=*) + do_check_versions=yes + max_version=${1#--max-version=} + ;; + --exact-version=*) + do_check_versions=yes + exact_version=${1#--exact-version=} + ;; + + # Compiler flag output + --cppflags) echo_cppflags=yes;; + --cxxflags) echo_cxxflags=yes;; + --ldflags) echo_ldflags=yes;; + --libs) echo_libs=yes;; + + # Everything else is an error + *) show_usage; exit 1;; + esac + shift +done + +# These have defaults filled in by the configure script but can also be +# overridden by environment variables or command line parameters. +prefix="${GMOCK_PREFIX:-@prefix@}" +exec_prefix="${GMOCK_EXEC_PREFIX:-@exec_prefix@}" +libdir="${GMOCK_LIBDIR:-@libdir@}" +includedir="${GMOCK_INCLUDEDIR:-@includedir@}" + +# We try and detect if our binary is not located at its installed location. If +# it's not, we provide variables pointing to the source and build tree rather +# than to the install tree. We also locate Google Test using the configured +# gtest-config script rather than searching the PATH and our bindir for one. +# This allows building against a just-built gmock rather than an installed +# gmock. +bindir="@bindir@" +this_relative_bindir=`dirname $0` +this_bindir=`cd ${this_relative_bindir}; pwd -P` +if test "${this_bindir}" = "${this_bindir%${bindir}}"; then + # The path to the script doesn't end in the bindir sequence from Autoconf, + # assume that we are in a build tree. + build_dir=`dirname ${this_bindir}` + src_dir=`cd ${this_bindir}/@top_srcdir@; pwd -P` + + # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we + # should work to remove it, and/or remove libtool altogether, replacing it + # with direct references to the library and a link path. + gmock_libs="${build_dir}/lib/libgtest.la" + gmock_ldflags="" + + # We provide hooks to include from either the source or build dir, where the + # build dir is always preferred. This will potentially allow us to write + # build rules for generated headers and have them automatically be preferred + # over provided versions. + gmock_cppflags="-I${build_dir}/include -I${src_dir}/include" + gmock_cxxflags="" + + # Directly invoke the gtest-config script used during the build process. + gtest_config="@GTEST_CONFIG@" +else + # We're using an installed gmock, although it may be staged under some + # prefix. Assume (as our own libraries do) that we can resolve the prefix, + # and are present in the dynamic link paths. + gmock_ldflags="-L${libdir}" + gmock_libs="-l${name}" + gmock_cppflags="-I${includedir}" + gmock_cxxflags="" + + # We also prefer any gtest-config script installed in our prefix. Lacking + # one, we look in the PATH for one. + gtest_config="${bindir}/gtest-config" + if test ! -x "${gtest_config}"; then + gtest_config=`which gtest-config` + fi +fi + +# Ensure that we have located a Google Test to link against. +if ! test -x "${gtest_config}"; then + echo "Unable to locate Google Test, check your Google Mock configuration" \ + "and installation" >&2 + exit 1 +elif ! "${gtest_config}" "--exact-version=@GTEST_VERSION@"; then + echo "The Google Test found is not the same version as Google Mock was " \ + "built against" >&2 + exit 1 +fi + +# Add the necessary Google Test bits into the various flag variables +gmock_cppflags="${gmock_cppflags} `${gtest_config} --cppflags`" +gmock_cxxflags="${gmock_cxxflags} `${gtest_config} --cxxflags`" +gmock_ldflags="${gmock_ldflags}`${gtest_config} --ldflags`" +gmock_libs="${gmock_libs} `${gtest_config} --libs`" + +# Do an installation query if requested. +if test -n "$do_query"; then + case $do_query in + prefix) echo $prefix; exit 0;; + exec-prefix) echo $exec_prefix; exit 0;; + libdir) echo $libdir; exit 0;; + includedir) echo $includedir; exit 0;; + version) echo $version; exit 0;; + *) show_usage; exit 1;; + esac +fi + +# Do a version check if requested. +if test "$do_check_versions" = "yes"; then + # Make sure we didn't receive a bad combination of parameters. + test "$echo_cppflags" = "yes" && show_usage && exit 1 + test "$echo_cxxflags" = "yes" && show_usage && exit 1 + test "$echo_ldflags" = "yes" && show_usage && exit 1 + test "$echo_libs" = "yes" && show_usage && exit 1 + + if test "$exact_version" != ""; then + check_versions $exact_version $exact_version + # unreachable + else + check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999} + # unreachable + fi +fi + +# Do the output in the correct order so that these can be used in-line of +# a compiler invocation. +output="" +test "$echo_cppflags" = "yes" && output="$output $gmock_cppflags" +test "$echo_cxxflags" = "yes" && output="$output $gmock_cxxflags" +test "$echo_ldflags" = "yes" && output="$output $gmock_ldflags" +test "$echo_libs" = "yes" && output="$output $gmock_libs" +echo $output + +exit 0 -- cgit v1.2.3 From c50af1ab55b4067d919c1a83a5093000e7cf5e57 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 11 Dec 2008 05:22:15 +0000 Subject: Improves the documentation. --- README | 150 ++++++++++++++++++++++++++++++++---------------- scripts/gmock-config.in | 2 +- 2 files changed, 103 insertions(+), 49 deletions(-) diff --git a/README b/README index 47d10edb..f51c9ba7 100644 --- a/README +++ b/README @@ -31,7 +31,7 @@ OFTC (irc.oftc.net) #gtest available. Please join us! Please note that code under scripts/generator/ is from the cppclean project (http://code.google.com/p/cppclean/) and under the Apache -License. +License, which is different from Google Mock's license. Requirements ------------ @@ -89,11 +89,11 @@ much more active and have the latest features, but the latter provides much more stability and predictability. Choose whichever fits your needs best, and proceed with the following Subversion commands: - $ svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn + svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn or for a release version X.Y.*'s branch: - $ svn checkout http://googlemock.googlecode.com/svn/branches/release-X.Y/ \ + svn checkout http://googlemock.googlecode.com/svn/branches/release-X.Y/ \ gmock-X.Y-svn Next you will need to prepare the GNU Autotools build system, if you @@ -101,27 +101,28 @@ are using Linux or Mac OS X. Enter the target directory of the checkout command you used ('gmock-svn' or 'gmock-X.Y-svn' above) and proceed with the following command: - $ autoreconf -fvi + autoreconf -fvi -Once you have completed this step, you are ready to build the library. -Note that you should need to complete this step only once. The sub- -sequent `make' invocations will automatically re-generate the bits of -the build system that need to be changed. +Once you have completed this step, you are ready to build the library. Note +that you should only need to complete this step once. The subsequent `make' +invocations will automatically re-generate the bits of the build system that +need to be changed. If your system uses older versions of the autotools, the above command will -fail. You may need to explicitly specify a version to use. For instance, if -you have both GNU Automake 1.4 and 1.9 installed and `automake' would invoke -the 1.4, use instead: +fail. You may need to explicitly specify a version to use. For instance, if you +have both GNU Automake 1.4 and 1.9 installed and `automake' would invoke the +1.4, use instead: - $ AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi + AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi Make sure you're using the same version of automake and aclocal. ### Source Package: ### Google Mock is also released in source packages which can be downloaded from its Google Code download page[1]. Several different archive formats are -provided, but the only difference is the tools used to manipulate them, and the -size of the resulting file. Download whichever you are most comfortable with. +provided, but the only difference is the tools needed to extract their +contents, and the size of the resulting file. Download whichever you are most +comfortable with. [1] Google Mock Downloads: http://code.google.com/p/googlemock/downloads/list @@ -129,9 +130,9 @@ Once downloaded expand the archive using whichever tools you prefer for that type. This will always result in a new directory with the name "gmock-X.Y.Z" which contains all of the source code. Here are some examples in Linux: - $ tar -xvzf gmock-X.Y.Z.tar.gz - $ tar -xvjf gmock-X.Y.Z.tar.bz2 - $ unzip gmock-X.Y.Z.zip + tar -xvzf gmock-X.Y.Z.tar.gz + tar -xvjf gmock-X.Y.Z.tar.bz2 + unzip gmock-X.Y.Z.zip Building the Source ------------------- @@ -148,35 +149,83 @@ either approach by simply substituting the shell variable SRCDIR with "." for building inside the source directory, and the relative path to the source directory otherwise. - $ ${SRCDIR}/configure # Standard GNU configure script, --help for more info - $ make # Standard makefile following GNU conventions - $ make check # Builds and runs all tests - all should pass + ${SRCDIR}/configure # Standard GNU configure script, --help for more info + +The default behavior of the configure script with respect to locating and using +Google Test is to first search for a 'gtest-config' in the system path, and +lacking this, build an internal copy of Google Test. You may optionally specify +a custom Google Test you wish to build Google Mock against, provided it is +a new enough version. + + # Configure against an installation in '/opt' with '/opt/bin/gtest-config'. + ${SRCDIR}/configure --with-gtest=/opt + +This can also be used to specify a Google Test which hasn't yet been installed. +However, it must have been configured and built as described in the Google Test +README before you configure Google Mock. To enable this feature, simply pass +the directory where you configured and built Google Test (which is not +necessarily its source directory) to Google Mock's configure script. + + # Configure against a build of Google Test in an arbitrary directory. + ${SRCDIR}/configure --with-gtest=../../my_gtest_build + +Finally, if you have a version of Google Test installed but for some reason +wish to forcibly prevent it from being used, we provide a special option. +Typically this is not needed as we fall back to the internal Google Test +packaged with Google Mock if an installed version is either unavailable or too +old to build Google Mock. When using the internally packaged Google Test, the +user does *not* need to configure or build it, that is automatically handled by +Google Mock's build system. + + # Force the use of the internally packaged Google Test, despite + # 'gtest-config' being in your PATH. + ${SRCDIR}/configure --disable-external-gtest + +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 Other programs will only be able to use Google Mock's functionality if you install it in a location which they can access, in Linux this is typically under '/usr/local'. The following command will install all of the Google Mock libraries, public headers, and utilities necessary for other programs and -libraries to leverage it: +libraries to leverage it. Note that if Google Mock was unable to find an +external Google Test to build against, it will also install the internally +packaged Google Test in order to allow the installed Google Mock to function +properly. This Google Test install will be fully functional, and if installed +will also be uninstalled by uninstalling Google Mock. + + sudo make install # Not necessary, but allows use by other programs - $ sudo make install # Not necessary, but allows use by other programs +Should you need to remove Google Mock from your system after having installed +it, run the following command, and it will back out its changes. However, note +carefully that you must run this command on the *same* Google Mock build that +you ran the install from, or the results are not predictable. If you install +Google Mock on your system, and are working from a VCS checkout, make sure you +run this *before* updating your checkout of the source in order to uninstall +the same version which you installed. -TODO(chandlerc@google.com): This section needs to be expanded when the -'gmock-config' script is finished and Autoconf macro's are provided (or not -provided) in order to properly reflect the process for other programs to -locate, include, and link against Google Mock. + sudo make uninstall # Must be run against the exact same build as "install" -Finally, should you need to remove Google Mock from your system after having -installed it, run the following command, and it will back out its changes. -However, note carefully that you must run this command on the *same* Google -Mock build that you ran the install from, or the results are not predictable. -If you install Google Mock on your system, and are working from a VCS checkout, -make sure you run this *before* updating your checkout of the source in order -to uninstall the same version which you installed. +Your project can build against Google Mock and Google Test simply by leveraging +the 'gmock-config' script. This script can be invoked directly out of the +'scripts' subdirectory of the build tree, and it will be installed in the +binary directory specified during the 'configure'. Here are some examples of +its use, see 'gmock-config --help' for more detailed information. - $ sudo make uninstall # Must be run against the exact same build as "install" + gmock-config --min-version=1.0 || echo "Insufficient Google Mock version." -TODO(chandlerc@google.com): Fixes the above instructions to match the -actual implementation. + g++ $(gmock-config --cppflags --cxxflags) -o foo.o -c foo.cpp + g++ $(gmock-config --ldflags --libs) -o foo foo.o + + # When using a built but not installed Google Mock: + g++ $(../../my_gmock_build/scripts/gmock-config ...) ... + +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. ### Windows ### The msvc/ directory contains VC++ 2005 projects for building Google Mock and @@ -192,11 +241,11 @@ one. For example, if you unpacked boost v1.36.0 into C:\boost: To configure Boost as a system library. - * Assuming you are using the Visual Studio 2008 IDE, select Tools | + * Assuming you are using the Visual Studio 2005 IDE, select Tools | Options | Projects And Solutions | VC++ Directories. * In the "Show directories for" drop-down select Include Files. Add - * C:\boost\boost_1_36_0\boost\tr1\tr1 and C:\boost\boost_1_36_0 - to the list of directories. + C:\boost\v_1_36_0\boost\tr1\tr1 and C:\boost\v_1_36_0 to the list of + directories. To configure your project to point to that version of Boost, replace the value of the BoostDir user macro with C:\boost\boost_1_36_0 in the @@ -209,9 +258,14 @@ to point to the new location. After configuring Boost, just open msvc/gmock.sln and build the library and tests. 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) + * 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 and select it. + * In Project Properties | Configuration Properties | General | Additional + Include Directories, type /include. + +TODO(wan@google.com): update the .vsprops and .vcproj files such that the +last step is unnecessary. ### Using GNU Make ### The make/ directory contains a Makefile that you can use to build @@ -223,9 +277,9 @@ use it as a starting point for your own Makefile. If the default settings are correct for your environment, the following commands should succeed: - $ cd ${SRCDIR}/make - $ make - $ ./gmock_test + cd ${SRCDIR}/make + make + ./gmock_test If you see errors, try to tweak the contents of make/Makefile to make them go away. There are instructions in make/Makefile on how to do @@ -239,13 +293,13 @@ the Google Test source tree) and src/gmock-all.cc into a library and link your tests with it. Assuming a Linux-like system and gcc, something like the following will do: - $ cd ${SRCDIR} - $ g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ + cd ${SRCDIR} + g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ -c {GTEST_SRCDIR}/src/gtest-all.cc - $ g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ + g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ -c src/gmock-all.cc - $ ar -rv libgmock.a gtest-all.o gmock-all.o - $ g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ + ar -rv libgmock.a gtest-all.o gmock-all.o + g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ path/to/your_test.cc libgmock.a -o your_test On Windows, you'll also need to add the include path for the boost diff --git a/scripts/gmock-config.in b/scripts/gmock-config.in index 540faff7..016ad611 100755 --- a/scripts/gmock-config.in +++ b/scripts/gmock-config.in @@ -34,7 +34,7 @@ Compiler flag queries output the union of the sets of flags when combined. g++ $(gmock-config --ldflags --libs) -o foo foo.o # When using a built but not installed Google Mock: - g++ $(../../my_gmock_build/scripts/gtest-config ...) ... + g++ $(../../my_gmock_build/scripts/gmock-config ...) ... # When using an installed Google Mock, but with installation overrides: export GMOCK_PREFIX="/opt" -- cgit v1.2.3 From c97f2f560bc6893b0b535b4312a161917c07854b Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 11 Dec 2008 17:22:59 +0000 Subject: Fixes compatibility with gcc 4.3's tuple implementation. --- include/gmock/gmock-printers.h | 82 +++++++++++++++++++++++++++++++++++++----- test/gmock-printers_test.cc | 23 ++++++++++++ 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 628fc744..eae6e52d 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -365,19 +365,85 @@ struct TuplePrefixPrinter<1> { } }; -// We support tuples of up-to 10 fields. Note that an N-tuple type is -// just an (N + 1)-tuple type where the last field has a special, -// unused type. +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + template void PrintTo( const ::std::tr1::tuple& t, ::std::ostream* os) { - typedef ::std::tr1::tuple Tuple; - *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); - *os << ")"; + PrintTupleTo(t, os); } // Overload for std::pair. diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 7457af2b..9677491a 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -754,6 +754,29 @@ TEST(PrintTupleTest, VariousSizes) { tuple t2('a', true); EXPECT_EQ("('a' (97), true)", Print(t2)); + tuple t3(false, 2, 3); + EXPECT_EQ("(false, 2, 3)", Print(t3)); + + tuple t4(false, 2, 3, 4); + EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); + + tuple t5(false, 2, 3, 4, true); + EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); + + tuple t6(false, 2, 3, 4, true, 6); + EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); + + tuple t7(false, 2, 3, 4, true, 6, 7); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); + + tuple t8( + false, 2, 3, 4, true, 6, 7, true); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); + + tuple t9( + false, 2, 3, 4, true, 6, 7, true, 9); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); + const char* const str = "8"; tuple -- cgit v1.2.3 From 9dd55ad3667efe016ad3d4ada955915fe4e5f66a Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 11 Dec 2008 19:44:55 +0000 Subject: Fixes incorrect build instructions on Windows. --- README | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README b/README index f51c9ba7..5327768e 100644 --- a/README +++ b/README @@ -248,8 +248,9 @@ To configure Boost as a system library. directories. To configure your project to point to that version of Boost, replace -the value of the BoostDir user macro with C:\boost\boost_1_36_0 in the -msvc/gtest_dep.vsprops file. You can use any text editor to edit that file. +the value of the BoostDir user macro with C:\boost\v_1_36_0 in the +msvc/gmock_config.vsprops file. You can use any text editor to edit +that file. If you want to use a version of Google Test other then the one bundled with Google Mock, change the value of the GTestDir macro in gmock_config.vsprop -- cgit v1.2.3 From 44a8cf19bc84f996cf16b49b24b44333a73cdd43 Mon Sep 17 00:00:00 2001 From: shiqian Date: Mon, 22 Dec 2008 23:06:35 +0000 Subject: Fixes Windows build instructions in README. --- README | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/README b/README index 5327768e..d89d525f 100644 --- a/README +++ b/README @@ -228,27 +228,32 @@ against Google Test as well. There is no need to configure Google Test separately. ### Windows ### -The msvc/ directory contains VC++ 2005 projects for building Google Mock and -selected tests. In order to build Google Mock you must have an implementation -of TR1 tuple. One library that provides such implementation is Boost. If you -choose to use Boost, download it from www.boost.org and install it on your -system. After that you have two options: either configure Boost as a system -library or modify the Google Mock project to point to your copy of Boost. The -former solution will let all your tests use the same copy of Boost while the -latter one will let each of your projects use its own copy of Boost. You can -also use a hybrid solution: your project settings will override the system-wide -one. +The msvc/ directory contains VC++ 2005 projects for building Google +Mock and selected tests. In order to build Google Mock you must have +an implementation of TR1 tuple. One library that provides such +implementation is Boost. If you choose to use Boost, download it from +www.boost.org and install it on your system. Note that Boost TR1 tuple +is a header-only library, so the installation only involves unpacking +it to a suitable location - you don't need to compile it or download a +pre-compiled Boost binary. + +After that you have two options: either set up Boost globally or +modify the Google Mock project to point to your copy of Boost. The +former will let all your tests use the same Boost library while the +latter will allow each of your projects use its own copy. You can also +use a hybrid solution: your project settings will override the +system-wide one. For example, if you unpacked boost v1.36.0 into C:\boost: -To configure Boost as a system library. +To set up Boost such that all projects can use it: * Assuming you are using the Visual Studio 2005 IDE, select Tools | Options | Projects And Solutions | VC++ Directories. * In the "Show directories for" drop-down select Include Files. Add - C:\boost\v_1_36_0\boost\tr1\tr1 and C:\boost\v_1_36_0 to the list of - directories. + C:\boost\boost_1_36_0\boost\tr1\tr1 and C:\boost\boost_1_36_0 to the + list of directories. To configure your project to point to that version of Boost, replace -the value of the BoostDir user macro with C:\boost\v_1_36_0 in the +the value of the BoostDir user macro with C:\boost\boost_1_36_0 in the msvc/gmock_config.vsprops file. You can use any text editor to edit that file. -- cgit v1.2.3 From 326aa564127acf095f6f0952b2f54d149a10d824 Mon Sep 17 00:00:00 2001 From: shiqian Date: Fri, 9 Jan 2009 21:43:57 +0000 Subject: Implements the ACTION* macros. --- include/gmock/gmock-generated-actions.h | 972 +++++++++++++++++++++++++++ include/gmock/gmock-generated-actions.h.pump | 208 ++++++ test/gmock-generated-actions_test.cc | 338 ++++++++++ 3 files changed, 1518 insertions(+) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index ec696b30..04771419 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -971,6 +971,126 @@ class DoBothAction { Action2 action2_; }; +// 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 ::std::tr1::tuple<>& args) { + using ::std::tr1::get; + return impl->gmock_PerformImpl(args, ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->gmock_PerformImpl(args, get<0>(args), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->gmock_PerformImpl(args, get<0>(args), get<1>(args), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + } + + template + static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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 ::std::tr1::tuple& args) { + using ::std::tr1::get; + return impl->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(). @@ -1326,4 +1446,856 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, } // 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. + +#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;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl());\ + }\ + };\ + inline name##Action name() {\ + return name##Action();\ + }\ + template \ + template \ + typename ::testing::internal::Function::Result\ + name##Action::\ + gmock_Impl::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 + +#define ACTION_P(name, p0)\ + template \ + class name##ActionP {\ + public:\ + 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;\ + const p0##_type p0;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0));\ + }\ + const p0##_type p0;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + const p7##_type p7;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + const p7##_type p7;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + const p7##_type p7;\ + const p8##_type p8;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + const p7##_type p7;\ + const p8##_type p8;\ + };\ + 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(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 + +#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;\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + const p7##_type p7;\ + const p8##_type p8;\ + const p9##_type p9;\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ + p6, p7, p8, p9));\ + }\ + const p0##_type p0;\ + const p1##_type p1;\ + const p2##_type p2;\ + const p3##_type p3;\ + const p4##_type p4;\ + const p5##_type p5;\ + const p6##_type p6;\ + const p7##_type p7;\ + const p8##_type p8;\ + const p9##_type p9;\ + };\ + 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(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 + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index d3dfac09..121c2c1b 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -395,6 +395,49 @@ class DoBothAction { Action2 action2_; }; +// 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 ::std::tr1::tuple<$As>& args) { + using ::std::tr1::get; + return impl->gmock_PerformImpl(args, $arg_list); + } + +]] +}; + } // namespace internal // Various overloads for Invoke(). @@ -564,4 +607,169 @@ $range j2 2..i } // 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 +$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 const_param_field_decls = [[$for j +[[ + + const p$j##_type p$j;\ +]]]] +$var const_param_field_decls2 = [[$for j +[[ + + const p$j##_type p$j;\ +]]]] +$var params = [[$for j, [[p$j]]]] +$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] +$range k 0..n-1 +$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:\ + $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;\$const_param_field_decls + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(new gmock_Impl($params));\ + }\$const_param_field_decls2 + };\$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(const args_type& args, [[]] +$arg_types_and_names) const +]] + + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 4f2e877a..adf1f82a 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -58,6 +58,7 @@ using testing::Invoke; using testing::InvokeArgument; using testing::Return; using testing::SetArgumentPointee; +using testing::StaticAssertTypeEq; using testing::Unused; using testing::WithArg; using testing::WithArgs; @@ -942,5 +943,342 @@ TEST(DoAllTest, TenActions) { EXPECT_EQ('g', g); } +// Tests the ACTION*() macro family. + +// Tests that ACTION() can define an action that doesn't reference the +// mock function arguments. +ACTION(Return5) { return 5; } + +TEST(ActionMacroTest, WorksWhenNotReferencingArguments) { + Action a1 = Return5(); + EXPECT_DOUBLE_EQ(5, a1.Perform(make_tuple())); + + Action a2 = Return5(); + EXPECT_EQ(5, a2.Perform(make_tuple(1, true))); +} + +// Tests that ACTION() can define an action that returns void. +ACTION(IncrementArg1) { (*arg1)++; } + +TEST(ActionMacroTest, WorksWhenReturningVoid) { + Action a1 = IncrementArg1(); + int n = 0; + a1.Perform(make_tuple(5, &n)); + EXPECT_EQ(1, n); +} + +// Tests that the body of ACTION() can reference the type of the +// argument. +ACTION(IncrementArg2) { + StaticAssertTypeEq(); + arg2_type temp = arg2; + (*temp)++; +} + +TEST(ActionMacroTest, CanReferenceArgumentType) { + Action a1 = IncrementArg2(); + int n = 0; + a1.Perform(make_tuple(5, false, &n)); + EXPECT_EQ(1, n); +} + +// Tests that the body of ACTION() can reference the argument tuple +// via args_type and args. +ACTION(Sum2) { + StaticAssertTypeEq< ::std::tr1::tuple, args_type>(); + args_type args_copy = args; + return get<0>(args_copy) + get<1>(args_copy); +} + +TEST(ActionMacroTest, CanReferenceArgumentTuple) { + Action a1 = Sum2(); + int dummy = 0; + EXPECT_EQ(11, a1.Perform(make_tuple(5, static_cast(6), &dummy))); +} + +// Tests that the body of ACTION() can reference the mock function +// type. +int Dummy(bool flag) { return flag? 1 : 0; } + +ACTION(InvokeDummy) { + StaticAssertTypeEq(); + function_type* fp = &Dummy; + return (*fp)(true); +} + +TEST(ActionMacroTest, CanReferenceMockFunctionType) { + Action a1 = InvokeDummy(); + EXPECT_EQ(1, a1.Perform(make_tuple(true))); + EXPECT_EQ(1, a1.Perform(make_tuple(false))); +} + +// Tests that the body of ACTION() can reference the mock function's +// return type. +ACTION(InvokeDummy2) { + StaticAssertTypeEq(); + return_type result = Dummy(true); + return result; +} + +TEST(ActionMacroTest, CanReferenceMockFunctionReturnType) { + Action a1 = InvokeDummy2(); + EXPECT_EQ(1, a1.Perform(make_tuple(true))); + EXPECT_EQ(1, a1.Perform(make_tuple(false))); +} + +// Tests that ACTION() can be used in a namespace. +namespace action_test { +ACTION(Sum) { return arg0 + arg1; } +} // namespace action_test + +TEST(ActionMacroTest, WorksInNamespace) { + Action a1 = action_test::Sum(); + EXPECT_EQ(3, a1.Perform(make_tuple(1, 2))); +} + +// Tests that the same ACTION definition works for mock functions with +// different argument numbers. +ACTION(PlusTwo) { return arg0 + 2; } + +TEST(ActionMacroTest, WorksForDifferentArgumentNumbers) { + Action a1 = PlusTwo(); + EXPECT_EQ(4, a1.Perform(make_tuple(2))); + + Action a2 = PlusTwo(); + int dummy; + EXPECT_DOUBLE_EQ(6, a2.Perform(make_tuple(4.0f, &dummy))); +} + +// Tests that ACTION_P can define a parameterized action. +ACTION_P(Plus, n) { return arg0 + n; } + +TEST(ActionPMacroTest, DefinesParameterizedAction) { + Action a1 = Plus(9); + EXPECT_EQ(10, a1.Perform(make_tuple(1, true))); +} + +// Tests that the body of ACTION_P can reference the argument types +// and the parameter type. +ACTION_P(TypedPlus, n) { + arg0_type t1 = arg0; + n_type t2 = n; + return t1 + t2; +} + +TEST(ActionPMacroTest, CanReferenceArgumentAndParameterTypes) { + Action a1 = TypedPlus(9); + EXPECT_EQ(10, a1.Perform(make_tuple(static_cast(1), true))); +} + +// Tests that a parameterized action can be used in any mock function +// whose type is compatible. +TEST(ActionPMacroTest, WorksInCompatibleMockFunction) { + Action a1 = Plus("tail"); + const std::string re = "re"; + EXPECT_EQ("retail", a1.Perform(make_tuple(re))); +} + +// Tests that we can use ACTION*() to define actions overloaded on the +// number of parameters. + +ACTION(OverloadedAction) { return arg0 ? arg1 : "hello"; } + +ACTION_P(OverloadedAction, default_value) { + return arg0 ? arg1 : default_value; +} + +ACTION_P2(OverloadedAction, true_value, false_value) { + return arg0 ? true_value : false_value; +} + +TEST(ActionMacroTest, CanDefineOverloadedActions) { + typedef Action MyAction; + + const MyAction a1 = OverloadedAction(); + EXPECT_STREQ("hello", a1.Perform(make_tuple(false, "world"))); + EXPECT_STREQ("world", a1.Perform(make_tuple(true, "world"))); + + const MyAction a2 = OverloadedAction("hi"); + EXPECT_STREQ("hi", a2.Perform(make_tuple(false, "world"))); + EXPECT_STREQ("world", a2.Perform(make_tuple(true, "world"))); + + const MyAction a3 = OverloadedAction("hi", "you"); + EXPECT_STREQ("hi", a3.Perform(make_tuple(true, "world"))); + EXPECT_STREQ("you", a3.Perform(make_tuple(false, "world"))); +} + +// Tests ACTION_Pn where n >= 3. + +ACTION_P3(Plus, m, n, k) { return arg0 + m + n + k; } + +TEST(ActionPnMacroTest, WorksFor3Parameters) { + Action a1 = Plus(100, 20, 3.4); + EXPECT_DOUBLE_EQ(3123.4, a1.Perform(make_tuple(3000, true))); + + Action a2 = Plus("tail", "-", ">"); + const std::string re = "re"; + EXPECT_EQ("retail->", a2.Perform(make_tuple(re))); +} + +ACTION_P4(Plus, p0, p1, p2, p3) { return arg0 + p0 + p1 + p2 + p3; } + +TEST(ActionPnMacroTest, WorksFor4Parameters) { + Action a1 = Plus(1, 2, 3, 4); + EXPECT_EQ(10 + 1 + 2 + 3 + 4, a1.Perform(make_tuple(10))); +} + +ACTION_P5(Plus, p0, p1, p2, p3, p4) { return arg0 + p0 + p1 + p2 + p3 + p4; } + +TEST(ActionPnMacroTest, WorksFor5Parameters) { + Action a1 = Plus(1, 2, 3, 4, 5); + EXPECT_EQ(10 + 1 + 2 + 3 + 4 + 5, a1.Perform(make_tuple(10))); +} + +ACTION_P6(Plus, p0, p1, p2, p3, p4, p5) { + return arg0 + p0 + p1 + p2 + p3 + p4 + p5; +} + +TEST(ActionPnMacroTest, WorksFor6Parameters) { + Action a1 = Plus(1, 2, 3, 4, 5, 6); + EXPECT_EQ(10 + 1 + 2 + 3 + 4 + 5 + 6, a1.Perform(make_tuple(10))); +} + +ACTION_P7(Plus, p0, p1, p2, p3, p4, p5, p6) { + return arg0 + p0 + p1 + p2 + p3 + p4 + p5 + p6; +} + +TEST(ActionPnMacroTest, WorksFor7Parameters) { + Action a1 = Plus(1, 2, 3, 4, 5, 6, 7); + EXPECT_EQ(10 + 1 + 2 + 3 + 4 + 5 + 6 + 7, a1.Perform(make_tuple(10))); +} + +ACTION_P8(Plus, p0, p1, p2, p3, p4, p5, p6, p7) { + return arg0 + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7; +} + +TEST(ActionPnMacroTest, WorksFor8Parameters) { + Action a1 = Plus(1, 2, 3, 4, 5, 6, 7, 8); + EXPECT_EQ(10 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, a1.Perform(make_tuple(10))); +} + +ACTION_P9(Plus, p0, p1, p2, p3, p4, p5, p6, p7, p8) { + return arg0 + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8; +} + +TEST(ActionPnMacroTest, WorksFor9Parameters) { + Action a1 = Plus(1, 2, 3, 4, 5, 6, 7, 8, 9); + EXPECT_EQ(10 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9, a1.Perform(make_tuple(10))); +} + +ACTION_P10(Plus, p0, p1, p2, p3, p4, p5, p6, p7, p8, last_param) { + arg0_type t0 = arg0; + last_param_type t9 = last_param; + return t0 + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + t9; +} + +TEST(ActionPnMacroTest, WorksFor10Parameters) { + Action a1 = Plus(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + EXPECT_EQ(10 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10, + a1.Perform(make_tuple(10))); +} + +// Tests that the action body can promote the parameter types. + +ACTION_P2(PadArgument, prefix, suffix) { + // The following lines promote the two parameters to desired types. + std::string prefix_str(prefix); + char suffix_char(suffix); + return prefix_str + arg0 + suffix_char; +} + +TEST(ActionPnMacroTest, SimpleTypePromotion) { + Action no_promo = + PadArgument(std::string("foo"), 'r'); + Action promo = + PadArgument("foo", static_cast('r')); + EXPECT_EQ("foobar", no_promo.Perform(make_tuple("ba"))); + EXPECT_EQ("foobar", promo.Perform(make_tuple("ba"))); +} + +// Tests that we can partially restrict parameter types using a +// straight-forward pattern. + +// Defines a generic action that doesn't restrict the types of its +// parameters. +ACTION_P3(ConcatImpl, a, b, c) { + std::stringstream ss; + ss << a << b << c; + return ss.str(); +} + +// Next, we try to restrict that either the first parameter is a +// string, or the second parameter is an int. + +// Defines a partially specialized wrapper that restricts the first +// parameter to std::string. +template +// ConcatImplActionP3 is the class template ACTION_P3 uses to +// implement ConcatImpl. We shouldn't change the name as this +// pattern requires the user to use it directly. +ConcatImplActionP3 +Concat(const std::string& a, T1 b, T2 c) { + if (true) { + // This branch verifies that ConcatImpl() can be invoked without + // explicit template arguments. + return ConcatImpl(a, b, c); + } else { + // This branch verifies that ConcatImpl() can also be invoked with + // explicit template arguments. It doesn't really need to be + // executed as this is a compile-time verification. + return ConcatImpl(a, b, c); + } +} + +// Defines another partially specialized wrapper that restricts the +// second parameter to int. +template +ConcatImplActionP3 +Concat(T1 a, int b, T2 c) { + return ConcatImpl(a, b, c); +} + +TEST(ActionPnMacroTest, CanPartiallyRestrictParameterTypes) { + Action a1 = Concat("Hello", "1", 2); + EXPECT_EQ("Hello12", a1.Perform(make_tuple())); + + a1 = Concat(1, 2, 3); + EXPECT_EQ("123", a1.Perform(make_tuple())); +} + +// Verifies the type of an ACTION*. + +ACTION(DoFoo) {} +ACTION_P(DoFoo, p) {} +ACTION_P2(DoFoo, p0, p1) {} + +TEST(ActionPnMacroTest, TypesAreCorrect) { + // DoFoo() must be assignable to a DoFooAction variable. + DoFooAction a0 = DoFoo(); + + // DoFoo(1) must be assignable to a DoFooActionP variable. + DoFooActionP a1 = DoFoo(1); + + // DoFoo(p1, ..., pk) must be assignable to a DoFooActionPk + // variable, and so on. + DoFooActionP2 a2 = DoFoo(1, '2'); + PlusActionP3 a3 = Plus(1, 2, '3'); + PlusActionP4 a4 = Plus(1, 2, 3, '4'); + PlusActionP5 a5 = Plus(1, 2, 3, 4, '5'); + PlusActionP6 a6 = Plus(1, 2, 3, 4, 5, '6'); + PlusActionP7 a7 = + Plus(1, 2, 3, 4, 5, 6, '7'); + PlusActionP8 a8 = + Plus(1, 2, 3, 4, 5, 6, 7, '8'); + PlusActionP9 a9 = + Plus(1, 2, 3, 4, 5, 6, 7, 8, '9'); + PlusActionP10 a10 = + Plus(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); +} + } // namespace gmock_generated_actions_test } // namespace testing -- cgit v1.2.3 From 19e49afd7dbde90d45920b1ce56de20cd011a964 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 14 Jan 2009 21:09:22 +0000 Subject: Updates README with instructions on downloading TR1 tuple without the rest of Boost. --- README | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README b/README index d89d525f..9498041a 100644 --- a/README +++ b/README @@ -52,7 +52,8 @@ package (as described below): * GNU-compatible Make or "gmake" * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) - * gcc 4.0 or newer + * gcc 4.0 or newer, or gcc 3.4 or newer with the tr1 tuple library + (from Boost or other vendors). Furthermore, if you are building Google Mock from a VCS Checkout (also described below), there are further requirements: @@ -63,11 +64,12 @@ described below), there are further requirements: ### Windows Requirements ### * Microsoft Visual C++ 8.0 SP1 or newer - * An implementation of the tr1 C++ library (You can get it for free - from http://www.boost.org/. We have verified that version 1.36.0 - works. One caveat is this implementation exposes a bug in Visual - C++'s header when exceptions are disabled. Therefore - your project must enable exceptions for this configuration to work.) + * An implementation of the tr1 tuple C++ library (You can get it for + free from http://www.boost.org/. We have verified that version + 1.36.0 works. One caveat is this implementation exposes a bug in + Visual C++'s header when exceptions are disabled. + Therefore your project must enable exceptions for this + configuration to work.) ### Mac OS X Requirements ### * Mac OS X 10.4 Tiger or newer @@ -237,6 +239,11 @@ is a header-only library, so the installation only involves unpacking it to a suitable location - you don't need to compile it or download a pre-compiled Boost binary. +Since Boost is quite large, you may prefer to only install the files +actually needed by Google Mock. If so, you can download TR1 tuple +without other parts of Boost from +http://code.google.com/p/googlemock/downloads/list. + After that you have two options: either set up Boost globally or modify the Google Mock project to point to your copy of Boost. The former will let all your tests use the same Boost library while the -- cgit v1.2.3 From 6a896b5ec607a54d86bbd2efdbc0248754b042e1 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 16 Jan 2009 01:13:50 +0000 Subject: Implements ContainerEq. --- include/gmock/gmock-matchers.h | 78 ++++++++++++++++++++++ test/gmock-matchers_test.cc | 146 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 223 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 69879a48..9113d178 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -38,6 +38,7 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#include #include // NOLINT #include #include @@ -1635,6 +1636,73 @@ void ExplainMatchResultTo(const ResultOfMatcher& matcher, matcher.ExplainMatchResultTo(obj, os); } +// Implements an equality matcher for any STL-style container whose elements +// support ==. This matcher is like Eq(), but its failure explanations provide +// more detailed information that is useful when the container is used as a set. +// The failure message reports elements that are in one of the operands but not +// the other. The failure messages do not report duplicate or out-of-order +// elements in the containers (which don't properly matter to sets, but can +// occur if the containers are vectors or lists, for example). +// +// Uses the container's const_iterator, value_type, operator ==, +// begin(), and end(). +template +class ContainerEqMatcher { + public: + explicit ContainerEqMatcher(const Container& rhs) : rhs_(rhs) {} + bool Matches(const Container& lhs) const { return lhs == rhs_; } + void DescribeTo(::std::ostream* os) const { + *os << "equals "; + UniversalPrinter::Print(rhs_, os); + } + void DescribeNegationTo(::std::ostream* os) const { + *os << "does not equal "; + UniversalPrinter::Print(rhs_, os); + } + + void ExplainMatchResultTo(const Container& lhs, + ::std::ostream* os) const { + // Something is different. Check for missing values first. + bool printed_header = false; + for (typename Container::const_iterator it = lhs.begin(); + it != lhs.end(); ++it) { + if (std::find(rhs_.begin(), rhs_.end(), *it) == rhs_.end()) { + if (printed_header) { + *os << ", "; + } else { + *os << "Only in actual: "; + printed_header = true; + } + UniversalPrinter::Print(*it, os); + } + } + + // Now check for extra values. + bool printed_header2 = false; + for (typename Container::const_iterator it = rhs_.begin(); + it != rhs_.end(); ++it) { + if (std::find(lhs.begin(), lhs.end(), *it) == lhs.end()) { + if (printed_header2) { + *os << ", "; + } else { + *os << (printed_header ? "; not" : "Not") << " in actual: "; + printed_header2 = true; + } + UniversalPrinter::Print(*it, os); + } + } + } + private: + const Container rhs_; +}; + +template +void ExplainMatchResultTo(const ContainerEqMatcher& matcher, + const Container& lhs, + ::std::ostream* os) { + matcher.ExplainMatchResultTo(lhs, os); +} + } // namespace internal // Implements MatcherCast(). @@ -2073,6 +2141,16 @@ Truly(Predicate pred) { return MakePolymorphicMatcher(internal::TrulyMatcher(pred)); } +// Returns a matcher that matches an equal container. +// This matcher behaves like Eq(), but in the event of mismatch lists the +// values that are included in one container but not the other. (Duplicate +// values and order differences are not explained.) +template +inline PolymorphicMatcher > + ContainerEq(const Container& rhs) { + return MakePolymorphicMatcher(internal::ContainerEqMatcher(rhs)); +} + // Returns a predicate that is satisfied by anything that matches the // given matcher. template diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 29b038e4..e9d12b29 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -37,8 +37,12 @@ #include #include -#include +#include +#include +#include #include +#include +#include #include #include #include @@ -2625,5 +2629,145 @@ TEST(ByRefTest, AllowsNotCopyableValueInMatchers) { EXPECT_TRUE(m.Matches(n2)); } +// Tests ContainerEq with different container types, and +// different element types. + +template +class ContainerEqTest : public testing::Test { + public: +}; + +typedef testing::Types< + std::set, + std::vector, + std::multiset, + std::list > + ContainerEqTestTypes; + +TYPED_TEST_CASE(ContainerEqTest, ContainerEqTestTypes); + +// Tests that the filled container is equal to itself. +TYPED_TEST(ContainerEqTest, EqualsSelf) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + TypeParam my_set(vals, vals + 6); + const Matcher m = ContainerEq(my_set); + EXPECT_TRUE(m.Matches(my_set)); + EXPECT_EQ("", Explain(m, my_set)); +} + +// Tests that missing values are reported. +TYPED_TEST(ContainerEqTest, ValueMissing) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {2, 1, 8, 5}; + TypeParam my_set(vals, vals + 6); + TypeParam test_set(test_vals, test_vals + 4); + const Matcher m = ContainerEq(my_set); + EXPECT_FALSE(m.Matches(test_set)); + EXPECT_EQ("Not in actual: 3", Explain(m, test_set)); +} + +// Tests that added values are reported. +TYPED_TEST(ContainerEqTest, ValueAdded) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {1, 2, 3, 5, 8, 46}; + TypeParam my_set(vals, vals + 6); + TypeParam test_set(test_vals, test_vals + 6); + const Matcher m = ContainerEq(my_set); + EXPECT_FALSE(m.Matches(test_set)); + EXPECT_EQ("Only in actual: 46", Explain(m, test_set)); +} + +// Tests that added and missing values are reported together. +TYPED_TEST(ContainerEqTest, ValueAddedAndRemoved) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {1, 2, 3, 8, 46}; + TypeParam my_set(vals, vals + 6); + TypeParam test_set(test_vals, test_vals + 5); + const Matcher m = ContainerEq(my_set); + EXPECT_FALSE(m.Matches(test_set)); + EXPECT_EQ("Only in actual: 46; not in actual: 5", Explain(m, test_set)); +} + +// Tests duplicated value -- expect no explanation. +TYPED_TEST(ContainerEqTest, DuplicateDifference) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {1, 2, 3, 5, 8}; + TypeParam my_set(vals, vals + 6); + TypeParam test_set(test_vals, test_vals + 5); + const Matcher m = ContainerEq(my_set); + // Depending on the container, match may be true or false + // But in any case there should be no explanation. + EXPECT_EQ("", Explain(m, test_set)); +} + +// Tests that mutliple missing values are reported. +// Using just vector here, so order is predicatble. +TEST(ContainerEqExtraTest, MultipleValuesMissing) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {2, 1, 5}; + std::vector my_set(vals, vals + 6); + std::vector test_set(test_vals, test_vals + 3); + const Matcher > m = ContainerEq(my_set); + EXPECT_FALSE(m.Matches(test_set)); + EXPECT_EQ("Not in actual: 3, 8", Explain(m, test_set)); +} + +// Tests that added values are reported. +// Using just vector here, so order is predicatble. +TEST(ContainerEqExtraTest, MultipleValuesAdded) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {1, 2, 92, 3, 5, 8, 46}; + std::list my_set(vals, vals + 6); + std::list test_set(test_vals, test_vals + 7); + const Matcher&> m = ContainerEq(my_set); + EXPECT_FALSE(m.Matches(test_set)); + EXPECT_EQ("Only in actual: 92, 46", Explain(m, test_set)); +} + +// Tests that added and missing values are reported together. +TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {1, 2, 3, 92, 46}; + std::list my_set(vals, vals + 6); + std::list test_set(test_vals, test_vals + 5); + const Matcher > m = ContainerEq(my_set); + EXPECT_FALSE(m.Matches(test_set)); + EXPECT_EQ("Only in actual: 92, 46; not in actual: 5, 8", + Explain(m, test_set)); +} + +// Tests to see that duplicate elements are detected, +// but (as above) not reported in the explanation. +TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) { + static const int vals[] = {1, 1, 2, 3, 5, 8}; + static const int test_vals[] = {1, 2, 3, 5, 8}; + std::vector my_set(vals, vals + 6); + std::vector test_set(test_vals, test_vals + 5); + const Matcher > m = ContainerEq(my_set); + EXPECT_TRUE(m.Matches(my_set)); + EXPECT_FALSE(m.Matches(test_set)); + // There is nothing to report when both sets contain all the same values. + EXPECT_EQ("", Explain(m, test_set)); +} + +// Tests that ContainerEq works for non-trivial associative containers, +// like maps. +TEST(ContainerEqExtraTest, WorksForMaps) { + std::map my_map; + my_map[0] = "a"; + my_map[1] = "b"; + + std::map test_map; + test_map[0] = "aa"; + test_map[1] = "b"; + + const Matcher&> m = ContainerEq(my_map); + EXPECT_TRUE(m.Matches(my_map)); + EXPECT_FALSE(m.Matches(test_map)); + + EXPECT_EQ("Only in actual: (0, \"aa\"); not in actual: (0, \"a\")", + Explain(m, test_map)); +} + } // namespace gmock_matchers_test } // namespace testing -- cgit v1.2.3 From 5b95fa7b16023c1e1ab0b00f7ce73a2d46a95911 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 27 Jan 2009 22:28:45 +0000 Subject: Improves error messages for undefined return value (by Sverre Sundsdal); improves gmock_doctor. --- include/gmock/gmock-actions.h | 18 +++++++++ include/gmock/gmock-spec-builders.h | 30 +++++++++------ scripts/gmock_doctor.py | 19 +++++++++ test/gmock-actions_test.cc | 77 +++++++++++++++++++++++++++++++++++++ test/gmock-spec-builders_test.cc | 12 ++++++ 5 files changed, 144 insertions(+), 12 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index a4327588..95e075d2 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -69,6 +69,8 @@ class ActionAdaptor; template class BuiltInDefaultValue { public: + // This function returns true iff type T has a built-in default value. + static bool Exists() { return false; } static T Get() { Assert(false, __FILE__, __LINE__, "Default action undefined for the function return type."); @@ -83,6 +85,7 @@ class BuiltInDefaultValue { template class BuiltInDefaultValue { public: + static bool Exists() { return BuiltInDefaultValue::Exists(); } static T Get() { return BuiltInDefaultValue::Get(); } }; @@ -91,6 +94,7 @@ class BuiltInDefaultValue { template class BuiltInDefaultValue { public: + static bool Exists() { return true; } static T* Get() { return NULL; } }; @@ -100,6 +104,7 @@ class BuiltInDefaultValue { template <> \ class BuiltInDefaultValue { \ public: \ + static bool Exists() { return true; } \ static type Get() { return value; } \ } @@ -191,6 +196,12 @@ class DefaultValue { // Returns true iff the user has set the default value for type T. static bool IsSet() { return value_ != 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. @@ -220,6 +231,12 @@ class DefaultValue { // 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. @@ -236,6 +253,7 @@ class DefaultValue { template <> class DefaultValue { public: + static bool Exists() { return true; } static void Get() {} }; diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 84e0b513..0364b570 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1061,15 +1061,21 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { return NULL; } - // Performs the default action of this mock function on the given - // arguments and returns the result. This method doesn't depend on - // the mutable state of this object, and thus can be called - // concurrently without locking. + // Performs the default action of this mock function on the given arguments + // and returns the result. Asserts with a helpful call descrption if there is + // no valid return value. This method doesn't depend on the mutable state of + // this object, and thus can be called concurrently without locking. // L = * - Result PerformDefaultAction(const ArgumentTuple& args) const { + Result PerformDefaultAction(const ArgumentTuple& args, + const string& call_description) const { const DefaultActionSpec* const spec = FindDefaultActionSpec(args); - return (spec != NULL) ? spec->GetAction().Perform(args) - : DefaultValue::Get(); + if (spec != NULL) { + return spec->GetAction().Perform(args); + } + Assert(DefaultValue::Exists(), "", -1, + call_description + "\n The mock function has no default action " + "set, and its return type has no default value set."); + return DefaultValue::Get(); } // Registers this function mocker and the mock object owning it; @@ -1407,7 +1413,7 @@ class InvokeWithHelper { Mock::GetReactionOnUninterestingCalls(mocker->MockObject()); // Calculates the function result. - Result result = mocker->PerformDefaultAction(args); + Result result = mocker->PerformDefaultAction(args, ss.str()); // Prints the function result. ss << "\n Returns: "; @@ -1429,8 +1435,8 @@ class InvokeWithHelper { args, &exp, &action, &is_excessive, &ss, &why); ss << " Function call: " << mocker->Name(); UniversalPrinter::Print(args, &ss); - Result result = - action.IsDoDefault() ? mocker->PerformDefaultAction(args) + Result result = action.IsDoDefault() ? + mocker->PerformDefaultAction(args, ss.str()) : action.Perform(args); ss << "\n Returns: "; UniversalPrinter::Print(result, &ss); @@ -1480,7 +1486,7 @@ class InvokeWithHelper { const CallReaction reaction = Mock::GetReactionOnUninterestingCalls(mocker->MockObject()); - mocker->PerformDefaultAction(args); + mocker->PerformDefaultAction(args, ss.str()); ReportUninterestingCall(reaction, ss.str()); return; } @@ -1499,7 +1505,7 @@ class InvokeWithHelper { UniversalPrinter::Print(args, &ss); ss << "\n" << why.str(); if (action.IsDoDefault()) { - mocker->PerformDefaultAction(args); + mocker->PerformDefaultAction(args, ss.str()); } else { action.Perform(args); } diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index ce8ec498..ca7935ca 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -55,6 +55,7 @@ _COMMON_GMOCK_SYMBOLS = [ 'Ge', 'Gt', 'HasSubstr', + 'IsInitializedProto', 'Le', 'Lt', 'MatcherCast', @@ -63,6 +64,7 @@ _COMMON_GMOCK_SYMBOLS = [ 'Not', 'NotNull', 'Pointee', + 'PointeeIsInitializedProto', 'Property', 'Ref', 'StartsWith', @@ -307,12 +309,29 @@ Did you forget to write yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) +def _NeedToUseReturnNullDiagnoser(msg): + """Diagnoses the NRNULL disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: invalid conversion from ' + r'\'long int\' to \'(?P.+\*)') + + diagnosis = """%(file)s:%(line)s: +You are probably calling Return(NULL) and the compiler isn't sure how to turn +NULL into a %(type)s*. Use ReturnNull() instead. +Note: the line number may be off; please fix all instances of Return(NULL).""" + return _GenericDiagnoser('NRNULL', 'Need to use ReturnNull', + regex, diagnosis, msg) + + + _DIAGNOSERS = [ _IncompleteByReferenceArgumentDiagnoser, _MockObjectPointerDiagnoser, _NeedToReturnNothingDiagnoser, _NeedToReturnReferenceDiagnoser, _NeedToReturnSomethingDiagnoser, + _NeedToUseReturnNullDiagnoser, _NeedToUseSymbolDiagnoser, _OverloadedFunctionActionDiagnoser, _OverloadedFunctionMatcherDiagnoser, diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 1000e306..6fb47bca 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -82,6 +82,13 @@ TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) { EXPECT_TRUE(BuiltInDefaultValue::Get() == NULL); } +// Tests that BuiltInDefaultValue::Exists() return true. +TEST(BuiltInDefaultValueTest, ExistsForPointerTypes) { + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); +} + // Tests that BuiltInDefaultValue::Get() returns 0 when T is a // built-in numeric type. TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { @@ -108,11 +115,42 @@ TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { EXPECT_EQ(0, BuiltInDefaultValue::Get()); } +// Tests that BuiltInDefaultValue::Exists() returns true when T is a +// built-in numeric type. +TEST(BuiltInDefaultValueTest, ExistsForNumericTypes) { + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); +#ifndef GTEST_OS_WINDOWS + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); +#endif // GTEST_OS_WINDOWS + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT + EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT + EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT + EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT + EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); + EXPECT_TRUE(BuiltInDefaultValue::Exists()); +} + // Tests that BuiltInDefaultValue::Get() returns false. TEST(BuiltInDefaultValueTest, IsFalseForBool) { EXPECT_FALSE(BuiltInDefaultValue::Get()); } +// Tests that BuiltInDefaultValue::Exists() returns true. +TEST(BuiltInDefaultValueTest, BoolExists) { + EXPECT_TRUE(BuiltInDefaultValue::Exists()); +} + // Tests that BuiltInDefaultValue::Get() returns "" when T is a // string type. TEST(BuiltInDefaultValueTest, IsEmptyStringForString) { @@ -125,6 +163,18 @@ TEST(BuiltInDefaultValueTest, IsEmptyStringForString) { #endif // GTEST_HAS_STD_STRING } +// Tests that BuiltInDefaultValue::Exists() returns true when T is a +// string type. +TEST(BuiltInDefaultValueTest, ExistsForString) { +#if GTEST_HAS_GLOBAL_STRING + EXPECT_TRUE(BuiltInDefaultValue< ::string>::Exists()); +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_STD_STRING + EXPECT_TRUE(BuiltInDefaultValue< ::std::string>::Exists()); +#endif // GTEST_HAS_STD_STRING +} + // Tests that BuiltInDefaultValue::Get() returns the same // value as BuiltInDefaultValue::Get() does. TEST(BuiltInDefaultValueTest, WorksForConstTypes) { @@ -142,6 +192,10 @@ struct UserType { int value; }; +TEST(BuiltInDefaultValueTest, UserTypeHasNoDefault) { + EXPECT_FALSE(BuiltInDefaultValue::Exists()); +} + #ifdef GTEST_HAS_DEATH_TEST // Tests that BuiltInDefaultValue::Get() aborts the program. @@ -170,17 +224,26 @@ TEST(DefaultValueTest, IsInitiallyUnset) { // Tests that DefaultValue can be set and then unset. TEST(DefaultValueTest, CanBeSetAndUnset) { + EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); + DefaultValue::Set(1); DefaultValue::Set(UserType()); EXPECT_EQ(1, DefaultValue::Get()); EXPECT_EQ(0, DefaultValue::Get().value); + EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_TRUE(DefaultValue::Exists()); + DefaultValue::Clear(); DefaultValue::Clear(); EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_FALSE(DefaultValue::IsSet()); + + EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); } // Tests that DefaultValue::Get() returns the @@ -188,7 +251,9 @@ TEST(DefaultValueTest, CanBeSetAndUnset) { // false. TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_TRUE(DefaultValue::Exists()); EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::Exists()); EXPECT_EQ(0, DefaultValue::Get()); @@ -212,6 +277,12 @@ TEST(DefaultValueOfReferenceTest, IsInitiallyUnset) { EXPECT_FALSE(DefaultValue::IsSet()); } +// Tests that DefaultValue::Exists is false initiallly. +TEST(DefaultValueOfReferenceTest, IsInitiallyNotExisting) { + EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); +} + // Tests that DefaultValue can be set and then unset. TEST(DefaultValueOfReferenceTest, CanBeSetAndUnset) { int n = 1; @@ -219,12 +290,18 @@ TEST(DefaultValueOfReferenceTest, CanBeSetAndUnset) { UserType u; DefaultValue::Set(u); + EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_EQ(&n, &(DefaultValue::Get())); EXPECT_EQ(&u, &(DefaultValue::Get())); DefaultValue::Clear(); DefaultValue::Clear(); + EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_FALSE(DefaultValue::IsSet()); } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 3e27aa84..3e944ea4 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -987,6 +987,18 @@ TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { #endif // GMOCK_HAS_REGEX +#ifdef GTEST_HAS_DEATH_TEST + +TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) { + MockA a; + // TODO(wan@google.com): We should really verify the output message, + // but we cannot yet due to that EXPECT_DEATH only captures stderr + // while Google Mock logs to stdout. + EXPECT_DEATH(a.ReturnResult(1), ""); +} + +#endif // GTEST_HAS_DEATH_TEST + // Tests that an excessive call (one whose arguments match the // matchers but is called too many times) performs the default action. TEST(ExcessiveCallTest, DoesDefaultAction) { -- cgit v1.2.3 From c069d7fe27bfe8cfdaff77ef38455688c453c28d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 2 Feb 2009 20:51:53 +0000 Subject: Improves ACTION* to allow explicit instantiating with reference types. --- include/gmock/gmock-generated-actions.h | 220 +++++++++++++-------------- include/gmock/gmock-generated-actions.h.pump | 12 +- test/gmock-generated-actions_test.cc | 30 ++++ 3 files changed, 146 insertions(+), 116 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 04771419..5188b917 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -1611,12 +1611,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ + p0##_type p0;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0));\ }\ - const p0##_type p0;\ + p0##_type p0;\ };\ template \ inline name##ActionP name(p0##_type p0) {\ @@ -1662,14 +1662,14 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ - const p1##_type p1;\ + p0##_type p0;\ + p1##_type p1;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ + p0##_type p0;\ + p1##_type p1;\ };\ template \ inline name##ActionP2 name(p0##_type p0, \ @@ -1716,16 +1716,16 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ };\ template \ inline name##ActionP3 name(p0##_type p0, \ @@ -1775,18 +1775,18 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ };\ template \ @@ -1841,20 +1841,20 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ };\ template \ @@ -1910,22 +1910,22 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ };\ template \ @@ -1984,25 +1984,25 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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;\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ - const p6##_type p6;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ - const p6##_type p6;\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6, p7));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ - const p6##_type p6;\ - const p7##_type 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;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6, p7, p8));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ - const p6##_type p6;\ - const p7##_type p7;\ - const p8##_type 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;\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6, p7, p8, p9));\ }\ - const p0##_type p0;\ - const p1##_type p1;\ - const p2##_type p2;\ - const p3##_type p3;\ - const p4##_type p4;\ - const p5##_type p5;\ - const p6##_type p6;\ - const p7##_type p7;\ - const p8##_type p8;\ - const p9##_type 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;\ };\ template ]]]] @@ -754,11 +754,11 @@ $var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]] }\ template <$typename_arg_types>\ return_type gmock_PerformImpl(const args_type& args, [[]] -$arg_types_and_names) const;\$const_param_field_decls +$arg_types_and_names) const;\$param_field_decls };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl($params));\ - }\$const_param_field_decls2 + }\$param_field_decls2 };\$template inline $class_name$param_types name($param_types_and_names) {\ return $class_name$param_types($params);\ diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index adf1f82a..aee2c905 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -1280,5 +1280,35 @@ TEST(ActionPnMacroTest, TypesAreCorrect) { Plus(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); } +// Tests that an ACTION_P*() action can be explicitly instantiated +// with reference-typed parameters. + +ACTION_P(Plus1, x) { return x; } +ACTION_P2(Plus2, x, y) { return x + y; } +ACTION_P3(Plus3, x, y, z) { return x + y + z; } +ACTION_P10(Plus10, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +TEST(ActionPnMacroTest, CanExplicitlyInstantiateWithReferenceTypes) { + int x = 1, y = 2, z = 3; + const tuple<> empty = make_tuple(); + + Action a = Plus1(x); + EXPECT_EQ(1, a.Perform(empty)); + + a = Plus2(x, y); + EXPECT_EQ(3, a.Perform(empty)); + + a = Plus3(x, y, z); + EXPECT_EQ(6, a.Perform(empty)); + + int n[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + a = Plus10(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], + n[8], n[9]); + EXPECT_EQ(55, a.Perform(empty)); +} + } // namespace gmock_generated_actions_test } // namespace testing -- cgit v1.2.3 From e1cdce5f761ed0fb04be0aea4d1b9138e9dbc1f7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Feb 2009 01:09:43 +0000 Subject: Implements action Throw(exception). --- include/gmock/gmock-generated-actions.h | 10 ++++++++++ include/gmock/gmock-generated-actions.h.pump | 10 ++++++++++ test/gmock-generated-actions_test.cc | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 5188b917..b67fa982 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -2298,4 +2298,14 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, arg4_type arg4, arg5_type arg5, arg6_type arg6, arg7_type arg7, \ arg8_type arg8, arg9_type arg9) const +namespace testing { + +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown. +#if GTEST_HAS_EXCEPTIONS +ACTION_P(Throw, exception) { throw exception; } +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace testing + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 7b042ff8..0c403eb6 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -772,4 +772,14 @@ $arg_types_and_names) const ]] +namespace testing { + +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown. +#if GTEST_HAS_EXCEPTIONS +ACTION_P(Throw, exception) { throw exception; } +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace testing + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index aee2c905..0d5260a2 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -1310,5 +1310,26 @@ TEST(ActionPnMacroTest, CanExplicitlyInstantiateWithReferenceTypes) { EXPECT_EQ(55, a.Perform(empty)); } +#if GTEST_HAS_EXCEPTIONS + +TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) { + const Action a = Throw('a'); + EXPECT_THROW(a.Perform(make_tuple(0)), char); +} + +class MyException {}; + +TEST(ThrowActionTest, ThrowsGivenExceptionInNonVoidFunction) { + const Action a = Throw(MyException()); + EXPECT_THROW(a.Perform(make_tuple('0')), MyException); +} + +TEST(ThrowActionTest, ThrowsGivenExceptionInNullaryFunction) { + const Action a = Throw(MyException()); + EXPECT_THROW(a.Perform(make_tuple()), MyException); +} + +#endif // GTEST_HAS_EXCEPTIONS + } // namespace gmock_generated_actions_test } // namespace testing -- cgit v1.2.3 From 2f0849fef4883a9cb9e785ae0f90a6d0d00d2959 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Feb 2009 18:06:37 +0000 Subject: Fixes the "ambiguous overload" compiler error when a mock function takes an argument that supports streaming to basic_ostream. --- include/gmock/gmock-printers.h | 15 +++++++++-- test/gmock-printers_test.cc | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index eae6e52d..759aa347 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -116,8 +116,19 @@ class TypeWithoutFormatter { // to simplify the implementation, as much code in 'internal' needs to // use << in STL, which would conflict with our own << were it defined // in 'internal'. -template -::std::ostream& operator<<(::std::ostream& os, const T& x) { +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value>:: PrintValue(x, &os); return os; diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 9677491a..6254809b 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -597,6 +597,64 @@ TEST(PrintWideStringTest, StringInStdNamespace) { } #endif // GTEST_HAS_STD_WSTRING +// Tests printing types that support generic streaming (i.e. streaming +// to std::basic_ostream for any valid Char and +// CharTraits types). + +// Tests printing a non-template type that supports generic streaming. + +class AllowsGenericStreaming {}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreaming& a) { + return os << "AllowsGenericStreaming"; +} + +TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { + AllowsGenericStreaming a; + EXPECT_EQ("AllowsGenericStreaming", Print(a)); +} + +// Tests printing a template type that supports generic streaming. + +template +class AllowsGenericStreamingTemplate {}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreamingTemplate& a) { + return os << "AllowsGenericStreamingTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TemplateType) { + AllowsGenericStreamingTemplate a; + EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); +} + +// Tests printing a type that supports generic streaming and can be +// implicitly converted to another printable type. + +template +class AllowsGenericStreamingAndImplicitConversionTemplate { + public: + operator bool() const { return false; } +}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreamingAndImplicitConversionTemplate& a) { + return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { + AllowsGenericStreamingAndImplicitConversionTemplate a; + EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); +} + // Tests printing STL containers. TEST(PrintStlContainerTest, EmptyDeque) { -- cgit v1.2.3 From ce198ff8997775d63b802615ee0cea5886ab82ab Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 12 Feb 2009 01:34:27 +0000 Subject: Implements the MATCHER* macros. --- include/gmock/gmock-generated-matchers.h | 829 ++++++++++++++++++++++++++ include/gmock/gmock-generated-matchers.h.pump | 210 +++++++ include/gmock/gmock-printers.h | 15 +- include/gmock/internal/gmock-internal-utils.h | 6 + src/gmock-internal-utils.cc | 24 + test/gmock-generated-matchers_test.cc | 338 +++++++++++ test/gmock-internal-utils_test.cc | 34 ++ test/gmock-printers_test.cc | 24 + 8 files changed, 1479 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 09ccc9c3..f8cbf49e 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -44,6 +44,14 @@ namespace testing { namespace internal { +// Generates a non-fatal failure iff 'description' is not a valid +// matcher description. +inline void ValidateMatcherDescription(const char* description) { + EXPECT_STREQ("", description) + << "The description string in a MATCHER*() macro must be \"\" " + "at this moment. We will implement custom description string soon."; +} + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -647,4 +655,825 @@ ElementsAreArray(const T (&array)[N]) { } // namespace testing +// The MATCHER* family of macros can be used in a namespace scope 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. For now, the description_string must be "", but we'll +// allow other values soon. Inside the statements, you can refer to +// the value being matched by 'arg', and refer to its type by +// 'arg_type'. 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. +// +// 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. +// +// 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. +// +// 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. +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// 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, +// 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). +// +// CAVEAT: +// +// 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + }\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl());\ + }\ + name##Matcher() {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + };\ + inline name##Matcher name() {\ + return name##Matcher();\ + }\ + template \ + bool name##Matcher::\ + gmock_Impl::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " ";\ + ::testing::internal::UniversalPrint(p0, os);\ + }\ + p0##_type p0;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0));\ + }\ + name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + };\ + template \ + inline name##MatcherP name(p0##_type p0) {\ + return name##MatcherP(p0);\ + }\ + template \ + template \ + bool name##MatcherP::\ + gmock_Impl::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + };\ + template \ + inline name##MatcherP2 name(p0##_type p0, \ + p1##_type p1) {\ + return name##MatcherP2(p0, p1);\ + }\ + template \ + template \ + bool name##MatcherP2::\ + gmock_Impl::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p7, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p7, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p8, os);\ + *os << ")";\ + }\ + 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;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + 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;\ + };\ + 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::Matches(arg_type arg) 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 Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p7, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p8, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p9, os);\ + *os << ")";\ + }\ + 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;\ + };\ + 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) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + 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;\ + };\ + 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::Matches(arg_type arg) const + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index b45028ae..2a457aad 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -47,6 +47,14 @@ $var n = 10 $$ The maximum arity we support. namespace testing { namespace internal { +// Generates a non-fatal failure iff 'description' is not a valid +// matcher description. +inline void ValidateMatcherDescription(const char* description) { + EXPECT_STREQ("", description) + << "The description string in a MATCHER*() macro must be \"\" " + "at this moment. We will implement custom description string soon."; +} + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -300,4 +308,206 @@ ElementsAreArray(const T (&array)[N]) { } // namespace testing +// The MATCHER* family of macros can be used in a namespace scope 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. For now, the description_string must be "", but we'll +// allow other values soon. Inside the statements, you can refer to +// the value being matched by 'arg', and refer to its type by +// 'arg_type'. 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. +// +// 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. +// +// 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. +// +// 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. +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// 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, +// 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). +// +// CAVEAT: +// +// 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 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($ctor_param_list)$inits {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ +[[$if i==1 [[ *os << " ";\ + ::testing::internal::UniversalPrint(p0, os);\ + +]] $elif i>=2 [[ *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ +$range k 1..i-1 +$for k [[ + + *os << ", ";\ + ::testing::internal::UniversalPrint(p$k, os);\ +]] + + *os << ")";\ + +]]]] + }\$param_field_decls + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl($params));\ + }\ + $class_name($ctor_param_list)$inits {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\$param_field_decls2 + };\$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::Matches(arg_type arg) const +]] + + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 759aa347..5cd5f12e 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -44,9 +44,12 @@ // When T is a reference type, the address of the value is also // printed. // -// We also provide a convenient wrapper +// We also provide some convenient wrappers: // +// // Prints to a string. // string ::testing::internal::UniversalPrinter::PrintAsString(value); +// // Prints a value using its inferred type. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ @@ -585,6 +588,16 @@ class UniversalPrinter { #endif // _MSC_VER }; +// Prints a value using its inferred type. In particular, if the +// original type of the value is a reference, the *referenced* type +// (as opposed to the reference type) will be used, as C++ doesn't +// infer reference types. This is useful when you just want to know +// what the value is and don't care if it's a reference or not. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter::Print(value, os); +} + } // namespace internal } // namespace testing diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index bdc82882..9a74d546 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -63,6 +63,12 @@ namespace proto2 { class Message; } namespace testing { namespace internal { +// Converts an identifier name to a space-separated list of lower-case +// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is +// treated as one word. For example, both "FooBar123" and +// "foo_bar_123" are converted to "foo bar 123". +string ConvertIdentifierNameToWords(const char* id_name); + // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 58bc64e4..735abce5 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -37,6 +37,7 @@ #include +#include #include // NOLINT #include #include @@ -46,6 +47,29 @@ namespace testing { namespace internal { +// Converts an identifier name to a space-separated list of lower-case +// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is +// treated as one word. For example, both "FooBar123" and +// "foo_bar_123" are converted to "foo bar 123". +string ConvertIdentifierNameToWords(const char* id_name) { + string result; + char prev_char = '\0'; + for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) { + // We don't care about the current locale as the input is + // guaranteed to be a valid C++ identifier name. + const bool starts_new_word = isupper(*p) || + (!isalpha(prev_char) && islower(*p)) || + (!isdigit(prev_char) && isdigit(*p)); + + if (isalnum(*p)) { + if (starts_new_word && result != "") + result += ' '; + result += tolower(*p); + } + } + return result; +} + // This class reports Google Mock failures as Google Test failures. A // user can define another class in a similar fashion if he intends to // use Google Mock with a testing framework other than Google Test. diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 89b26caa..136ef5ce 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -40,6 +40,7 @@ #include #include +#include namespace { @@ -59,6 +60,7 @@ using testing::Ne; using testing::Not; using testing::Pointee; using testing::Ref; +using testing::StaticAssertTypeEq; using testing::StrEq; using testing::internal::string; @@ -370,4 +372,340 @@ TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); } +// Tests for the MATCHER*() macro family. + +// Tests that a simple MATCHER() definition works. + +MATCHER(IsEven, "") { return (arg % 2) == 0; } + +TEST(MatcherMacroTest, Works) { + const Matcher m = IsEven(); + EXPECT_TRUE(m.Matches(6)); + EXPECT_FALSE(m.Matches(7)); + + EXPECT_EQ("is even", Describe(m)); + EXPECT_EQ("not (is even)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 6)); + EXPECT_EQ("", Explain(m, 7)); +} + +// Tests that the description string supplied to MATCHER() must be +// empty. + +MATCHER(HasBadDescription, "not empty?") { + return true; +} + +TEST(MatcherMacroTest, + CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(HasBadDescription(), + "The description string in a MATCHER*() macro " + "must be \"\" at this moment"); +} + +// Tests that the body of MATCHER() can reference the type of the +// value being matched. + +MATCHER(IsEmptyString, "") { + StaticAssertTypeEq< ::std::string, arg_type>(); + return arg == ""; +} + +MATCHER(IsEmptyStringByRef, "") { + StaticAssertTypeEq(); + return arg == ""; +} + +TEST(MatcherMacroTest, CanReferenceArgType) { + const Matcher< ::std::string> m1 = IsEmptyString(); + EXPECT_TRUE(m1.Matches("")); + + const Matcher m2 = IsEmptyStringByRef(); + EXPECT_TRUE(m2.Matches("")); +} + +// Tests that MATCHER() can be used in a namespace. + +namespace matcher_test { +MATCHER(IsOdd, "") { return (arg % 2) != 0; } +} // namespace matcher_test + +TEST(MatcherTest, WorksInNamespace) { + Matcher m = matcher_test::IsOdd(); + EXPECT_FALSE(m.Matches(4)); + EXPECT_TRUE(m.Matches(5)); +} + +// Tests that a simple MATCHER_P() definition works. + +MATCHER_P(IsGreaterThan32And, n, "") { return arg > 32 && arg > n; } + +TEST(MatcherPMacroTest, Works) { + const Matcher m = IsGreaterThan32And(5); + EXPECT_TRUE(m.Matches(36)); + EXPECT_FALSE(m.Matches(5)); + + EXPECT_EQ("is greater than 32 and 5", Describe(m)); + EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36)); + EXPECT_EQ("", Explain(m, 5)); +} + +// Tests that the description string supplied to MATCHER_P() must be +// empty. + +MATCHER_P(HasBadDescription1, n, "not empty?") { + return arg > n; +} + +TEST(MatcherPMacroTest, + CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(HasBadDescription1(2), + "The description string in a MATCHER*() macro " + "must be \"\" at this moment"); +} + +// Tests that the description is calculated correctly from the matcher name. +MATCHER_P(_is_Greater_Than32and_, n, "") { return arg > 32 && arg > n; } + +TEST(MatcherPMacroTest, GeneratesCorrectDescription) { + const Matcher m = _is_Greater_Than32and_(5); + + EXPECT_EQ("is greater than 32 and 5", Describe(m)); + EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36)); + EXPECT_EQ("", Explain(m, 5)); +} + +// Tests that a MATCHER_P matcher can be explicitly instantiated with +// a reference parameter type. + +class UncopyableFoo { + public: + explicit UncopyableFoo(char value) : value_(value) {} + private: + UncopyableFoo(const UncopyableFoo&); + void operator=(const UncopyableFoo&); + + char value_; +}; + +MATCHER_P(ReferencesUncopyable, variable, "") { return &arg == &variable; } + +TEST(MatcherPMacroTest, WorksWhenExplicitlyInstantiatedWithReference) { + UncopyableFoo foo1('1'), foo2('2'); + const Matcher m = + ReferencesUncopyable(foo1); + + EXPECT_TRUE(m.Matches(foo1)); + EXPECT_FALSE(m.Matches(foo2)); + + // We don't want the address of the parameter printed, as most + // likely it will just annoy the user. If the address is + // interesting, the user should consider passing the parameter by + // pointer instead. + EXPECT_EQ("references uncopyable 1-byte object <31>", Describe(m)); +} + + +// Tests that the description string supplied to MATCHER_Pn() must be +// empty. + +MATCHER_P2(HasBadDescription2, m, n, "not empty?") { + return arg > m + n; +} + +TEST(MatcherPnMacroTest, + CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(HasBadDescription2(3, 4), + "The description string in a MATCHER*() macro " + "must be \"\" at this moment"); +} + +// Tests that the body of MATCHER_Pn() can reference the parameter +// types. + +MATCHER_P3(ParamTypesAreIntLongAndChar, foo, bar, baz, "") { + StaticAssertTypeEq(); + StaticAssertTypeEq(); // NOLINT + StaticAssertTypeEq(); + return arg == 0; +} + +TEST(MatcherPnMacroTest, CanReferenceParamTypes) { + EXPECT_THAT(0, ParamTypesAreIntLongAndChar(10, 20L, 'a')); +} + +// Tests that a MATCHER_Pn matcher can be explicitly instantiated with +// reference parameter types. + +MATCHER_P2(ReferencesAnyOf, variable1, variable2, "") { + return &arg == &variable1 || &arg == &variable2; +} + +TEST(MatcherPnMacroTest, WorksWhenExplicitlyInstantiatedWithReferences) { + UncopyableFoo foo1('1'), foo2('2'), foo3('3'); + const Matcher m = + ReferencesAnyOf(foo1, foo2); + + EXPECT_TRUE(m.Matches(foo1)); + EXPECT_TRUE(m.Matches(foo2)); + EXPECT_FALSE(m.Matches(foo3)); +} + +TEST(MatcherPnMacroTest, + GeneratesCorretDescriptionWhenExplicitlyInstantiatedWithReferences) { + UncopyableFoo foo1('1'), foo2('2'); + const Matcher m = + ReferencesAnyOf(foo1, foo2); + + // We don't want the addresses of the parameters printed, as most + // likely they will just annoy the user. If the addresses are + // interesting, the user should consider passing the parameters by + // pointers instead. + EXPECT_EQ("references any of (1-byte object <31>, 1-byte object <32>)", + Describe(m)); +} + +// Tests that a simple MATCHER_P2() definition works. + +MATCHER_P2(IsNotInClosedRange, low, hi, "") { return arg < low || arg > hi; } + +TEST(MatcherPnMacroTest, Works) { + const Matcher m = IsNotInClosedRange(10, 20); // NOLINT + EXPECT_TRUE(m.Matches(36L)); + EXPECT_FALSE(m.Matches(15L)); + + EXPECT_EQ("is not in closed range (10, 20)", Describe(m)); + EXPECT_EQ("not (is not in closed range (10, 20))", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36L)); + EXPECT_EQ("", Explain(m, 15L)); +} + +// Tests that MATCHER*() definitions can be overloaded on the number +// of parameters; also tests MATCHER_Pn() where n >= 3. + +MATCHER(EqualsSumOf, "") { return arg == 0; } +MATCHER_P(EqualsSumOf, a, "") { return arg == a; } +MATCHER_P2(EqualsSumOf, a, b, "") { return arg == a + b; } +MATCHER_P3(EqualsSumOf, a, b, c, "") { return arg == a + b + c; } +MATCHER_P4(EqualsSumOf, a, b, c, d, "") { return arg == a + b + c + d; } +MATCHER_P5(EqualsSumOf, a, b, c, d, e, "") { return arg == a + b + c + d + e; } +MATCHER_P6(EqualsSumOf, a, b, c, d, e, f, "") { + return arg == a + b + c + d + e + f; +} +MATCHER_P7(EqualsSumOf, a, b, c, d, e, f, g, "") { + return arg == a + b + c + d + e + f + g; +} +MATCHER_P8(EqualsSumOf, a, b, c, d, e, f, g, h, "") { + return arg == a + b + c + d + e + f + g + h; +} +MATCHER_P9(EqualsSumOf, a, b, c, d, e, f, g, h, i, "") { + return arg == a + b + c + d + e + f + g + h + i; +} +MATCHER_P10(EqualsSumOf, a, b, c, d, e, f, g, h, i, j, "") { + return arg == a + b + c + d + e + f + g + h + i + j; +} + +TEST(MatcherPnMacroTest, CanBeOverloadedOnNumberOfParameters) { + EXPECT_THAT(0, EqualsSumOf()); + EXPECT_THAT(1, EqualsSumOf(1)); + EXPECT_THAT(12, EqualsSumOf(10, 2)); + EXPECT_THAT(123, EqualsSumOf(100, 20, 3)); + EXPECT_THAT(1234, EqualsSumOf(1000, 200, 30, 4)); + EXPECT_THAT(12345, EqualsSumOf(10000, 2000, 300, 40, 5)); + EXPECT_THAT("abcdef", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f')); + EXPECT_THAT("abcdefg", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g')); + EXPECT_THAT("abcdefgh", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h")); + EXPECT_THAT("abcdefghi", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i')); + EXPECT_THAT("abcdefghij", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i', ::std::string("j"))); + + EXPECT_THAT(1, Not(EqualsSumOf())); + EXPECT_THAT(-1, Not(EqualsSumOf(1))); + EXPECT_THAT(-12, Not(EqualsSumOf(10, 2))); + EXPECT_THAT(-123, Not(EqualsSumOf(100, 20, 3))); + EXPECT_THAT(-1234, Not(EqualsSumOf(1000, 200, 30, 4))); + EXPECT_THAT(-12345, Not(EqualsSumOf(10000, 2000, 300, 40, 5))); + EXPECT_THAT("abcdef ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f'))); + EXPECT_THAT("abcdefg ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', + 'g'))); + EXPECT_THAT("abcdefgh ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h"))); + EXPECT_THAT("abcdefghi ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i'))); + EXPECT_THAT("abcdefghij ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i', ::std::string("j")))); +} + +// Tests that a MATCHER_Pn() definition can be instantiated with any +// compatible parameter types. +TEST(MatcherPnMacroTest, WorksForDifferentParameterTypes) { + EXPECT_THAT(123, EqualsSumOf(100L, 20, static_cast(3))); + EXPECT_THAT("abcd", EqualsSumOf(::std::string("a"), "b", 'c', "d")); + + EXPECT_THAT(124, Not(EqualsSumOf(100L, 20, static_cast(3)))); + EXPECT_THAT("abcde", Not(EqualsSumOf(::std::string("a"), "b", 'c', "d"))); +} + +// Tests that the matcher body can promote the parameter types. + +MATCHER_P2(EqConcat, prefix, suffix, "") { + // The following lines promote the two parameters to desired types. + std::string prefix_str(prefix); + char suffix_char(suffix); + return arg == prefix_str + suffix_char; +} + +TEST(MatcherPnMacroTest, SimpleTypePromotion) { + Matcher no_promo = + EqConcat(std::string("foo"), 't'); + Matcher promo = + EqConcat("foo", static_cast('t')); + EXPECT_FALSE(no_promo.Matches("fool")); + EXPECT_FALSE(promo.Matches("fool")); + EXPECT_TRUE(no_promo.Matches("foot")); + EXPECT_TRUE(promo.Matches("foot")); +} + +// Verifies the type of a MATCHER*. + +TEST(MatcherPnMacroTest, TypesAreCorrect) { + // EqualsSumOf() must be assignable to a EqualsSumOfMatcher variable. + EqualsSumOfMatcher a0 = EqualsSumOf(); + + // EqualsSumOf(1) must be assignable to a EqualsSumOfMatcherP variable. + EqualsSumOfMatcherP a1 = EqualsSumOf(1); + + // EqualsSumOf(p1, ..., pk) must be assignable to a EqualsSumOfMatcherPk + // variable, and so on. + EqualsSumOfMatcherP2 a2 = EqualsSumOf(1, '2'); + EqualsSumOfMatcherP3 a3 = EqualsSumOf(1, 2, '3'); + EqualsSumOfMatcherP4 a4 = EqualsSumOf(1, 2, 3, '4'); + EqualsSumOfMatcherP5 a5 = + EqualsSumOf(1, 2, 3, 4, '5'); + EqualsSumOfMatcherP6 a6 = + EqualsSumOf(1, 2, 3, 4, 5, '6'); + EqualsSumOfMatcherP7 a7 = + EqualsSumOf(1, 2, 3, 4, 5, 6, '7'); + EqualsSumOfMatcherP8 a8 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, '8'); + EqualsSumOfMatcherP9 a9 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, '9'); + EqualsSumOfMatcherP10 a10 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); +} + } // namespace diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 2a43caa9..2ea76b0e 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -50,6 +50,40 @@ namespace { using ::std::tr1::tuple; +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsNoWord) { + EXPECT_EQ("", ConvertIdentifierNameToWords("")); + EXPECT_EQ("", ConvertIdentifierNameToWords("_")); + EXPECT_EQ("", ConvertIdentifierNameToWords("__")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsDigits) { + EXPECT_EQ("1", ConvertIdentifierNameToWords("_1")); + EXPECT_EQ("2", ConvertIdentifierNameToWords("2_")); + EXPECT_EQ("34", ConvertIdentifierNameToWords("_34_")); + EXPECT_EQ("34 56", ConvertIdentifierNameToWords("_34_56")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsCamelCaseWords) { + EXPECT_EQ("a big word", ConvertIdentifierNameToWords("ABigWord")); + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("FooBar")); + EXPECT_EQ("foo", ConvertIdentifierNameToWords("Foo_")); + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("_Foo_Bar_")); + EXPECT_EQ("foo and bar", ConvertIdentifierNameToWords("_Foo__And_Bar")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContains_SeparatedWords) { + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("foo_bar")); + EXPECT_EQ("foo", ConvertIdentifierNameToWords("_foo_")); + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("_foo_bar_")); + EXPECT_EQ("foo and bar", ConvertIdentifierNameToWords("_foo__and_bar")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameIsMixture) { + EXPECT_EQ("foo bar 123", ConvertIdentifierNameToWords("Foo_bar123")); + EXPECT_EQ("chapter 11 section 1", + ConvertIdentifierNameToWords("_Chapter11Section_1_")); +} + // Tests that CompileAssertTypesEqual compiles when the type arguments are // equal. TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 6254809b..8ce2b739 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -152,6 +152,7 @@ using ::std::tr1::make_tuple; using ::std::tr1::tuple; using ::std::vector; using ::testing::StartsWith; +using ::testing::internal::UniversalPrint; using ::testing::internal::UniversalPrinter; using ::testing::internal::string; @@ -980,5 +981,28 @@ TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + " " + Print(sizeof(p)) + "-byte object ")); } +TEST(PrintAsStringTest, WorksForNonReference) { + EXPECT_EQ("123", UniversalPrinter::PrintAsString(123)); +} + +TEST(PrintAsStringTest, WorksForReference) { + int n = 123; + EXPECT_EQ("@" + PrintPointer(&n) + " 123", + UniversalPrinter::PrintAsString(n)); +} + +TEST(UniversalPrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalPrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalPrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + } // namespace gmock_printers_test } // namespace testing -- cgit v1.2.3 From 117941f670156e2a9d556ca73a87e7f836f94fe3 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 13 Feb 2009 00:54:56 +0000 Subject: Removes the svn:executable attribute from VS project files. --- msvc/gmock.sln | 0 msvc/gmock.vcproj | 0 msvc/gmock_config.vsprops | 0 msvc/gmock_link_test.vcproj | 0 msvc/gmock_main.vcproj | 0 msvc/gmock_output_test_.vcproj | 0 msvc/gmock_test.vcproj | 0 7 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 msvc/gmock.sln mode change 100755 => 100644 msvc/gmock.vcproj mode change 100755 => 100644 msvc/gmock_config.vsprops mode change 100755 => 100644 msvc/gmock_link_test.vcproj mode change 100755 => 100644 msvc/gmock_main.vcproj mode change 100755 => 100644 msvc/gmock_output_test_.vcproj mode change 100755 => 100644 msvc/gmock_test.vcproj diff --git a/msvc/gmock.sln b/msvc/gmock.sln old mode 100755 new mode 100644 diff --git a/msvc/gmock.vcproj b/msvc/gmock.vcproj old mode 100755 new mode 100644 diff --git a/msvc/gmock_config.vsprops b/msvc/gmock_config.vsprops old mode 100755 new mode 100644 diff --git a/msvc/gmock_link_test.vcproj b/msvc/gmock_link_test.vcproj old mode 100755 new mode 100644 diff --git a/msvc/gmock_main.vcproj b/msvc/gmock_main.vcproj old mode 100755 new mode 100644 diff --git a/msvc/gmock_output_test_.vcproj b/msvc/gmock_output_test_.vcproj old mode 100755 new mode 100644 diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj old mode 100755 new mode 100644 -- cgit v1.2.3 From 585e57b45bc8094dbac09506858a93d35a66297b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 13 Feb 2009 00:58:13 +0000 Subject: Sets the svn:eol-style property of VS project files to CRLF. --- msvc/gmock.sln | 88 +++---- msvc/gmock.vcproj | 526 ++++++++++++++++++++--------------------- msvc/gmock_config.vsprops | 40 ++-- msvc/gmock_link_test.vcproj | 406 +++++++++++++++---------------- msvc/gmock_main.vcproj | 374 ++++++++++++++--------------- msvc/gmock_output_test_.vcproj | 398 +++++++++++++++---------------- msvc/gmock_test.vcproj | 494 +++++++++++++++++++------------------- 7 files changed, 1163 insertions(+), 1163 deletions(-) diff --git a/msvc/gmock.sln b/msvc/gmock.sln index d084ee71..aeb6a614 100644 --- a/msvc/gmock.sln +++ b/msvc/gmock.sln @@ -1,44 +1,44 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock", "gmock.vcproj", "{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vcproj", "{F10D22F8-AC7B-4213-8720-608E7D878CD2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_link_test", "gmock_link_test.vcproj", "{ED597847-A714-4327-B569-70029D2311F0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_output_test_", "gmock_output_test_.vcproj", "{EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.ActiveCfg = Debug|Win32 - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.Build.0 = Debug|Win32 - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.ActiveCfg = Release|Win32 - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.Build.0 = Release|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.ActiveCfg = Debug|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.Build.0 = Debug|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.ActiveCfg = Release|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.Build.0 = Release|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.ActiveCfg = Debug|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.Build.0 = Debug|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.ActiveCfg = Release|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.Build.0 = Release|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.ActiveCfg = Debug|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.Build.0 = Debug|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.ActiveCfg = Release|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.Build.0 = Release|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock", "gmock.vcproj", "{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vcproj", "{F10D22F8-AC7B-4213-8720-608E7D878CD2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_link_test", "gmock_link_test.vcproj", "{ED597847-A714-4327-B569-70029D2311F0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_output_test_", "gmock_output_test_.vcproj", "{EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.Build.0 = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.ActiveCfg = Release|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.Build.0 = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.Build.0 = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.ActiveCfg = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.Build.0 = Release|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.ActiveCfg = Debug|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.Build.0 = Debug|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.ActiveCfg = Release|Win32 + {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.Build.0 = Release|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.ActiveCfg = Debug|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.Build.0 = Debug|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.ActiveCfg = Release|Win32 + {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.Build.0 = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/msvc/gmock.vcproj b/msvc/gmock.vcproj index a58ed364..b9036dad 100644 --- a/msvc/gmock.vcproj +++ b/msvc/gmock.vcproj @@ -1,263 +1,263 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_config.vsprops b/msvc/gmock_config.vsprops index 89b50aa7..fa596ef9 100644 --- a/msvc/gmock_config.vsprops +++ b/msvc/gmock_config.vsprops @@ -1,20 +1,20 @@ - - - - - - + + + + + + diff --git a/msvc/gmock_link_test.vcproj b/msvc/gmock_link_test.vcproj index 3f2eea1e..de87b5af 100644 --- a/msvc/gmock_link_test.vcproj +++ b/msvc/gmock_link_test.vcproj @@ -1,203 +1,203 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_main.vcproj b/msvc/gmock_main.vcproj index e9581158..8e0eccb8 100644 --- a/msvc/gmock_main.vcproj +++ b/msvc/gmock_main.vcproj @@ -1,187 +1,187 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_output_test_.vcproj b/msvc/gmock_output_test_.vcproj index bcbd96f0..051dd149 100644 --- a/msvc/gmock_output_test_.vcproj +++ b/msvc/gmock_output_test_.vcproj @@ -1,199 +1,199 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj index 5263d867..135b2e6c 100644 --- a/msvc/gmock_test.vcproj +++ b/msvc/gmock_test.vcproj @@ -1,247 +1,247 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 31c4522aa1a1c9c0234ad913c83cd7493d0dde9d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 13 Feb 2009 07:46:38 +0000 Subject: Adds upload_gmock.py for uploading a patch for review. --- Makefile.am | 5 + scripts/upload.py | 1387 +++++++++++++++++++++++++++++++++++++++++++++++ scripts/upload_gmock.py | 78 +++ 3 files changed, 1470 insertions(+) create mode 100755 scripts/upload.py create mode 100755 scripts/upload_gmock.py diff --git a/Makefile.am b/Makefile.am index 4a5a3fd6..bc06f612 100644 --- a/Makefile.am +++ b/Makefile.am @@ -173,6 +173,11 @@ EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \ include/gmock/gmock-generated-nice-strict.h.pump \ include/gmock/internal/gmock-generated-internal-utils.h.pump +# Scripts for uploading a patch for review. +EXTRA_DIST += \ + scripts/upload.py \ + scripts/upload_gmock.py + # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ scripts/generator/COPYING \ diff --git a/scripts/upload.py b/scripts/upload.py new file mode 100755 index 00000000..6e6f9a14 --- /dev/null +++ b/scripts/upload.py @@ -0,0 +1,1387 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# 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. + +"""Tool for uploading diffs from a version control system to the codereview app. + +Usage summary: upload.py [options] [-- diff_options] + +Diff options are passed to the diff command of the underlying system. + +Supported version control systems: + Git + Mercurial + Subversion + +It is important for Git/Mercurial users to specify a tree/node/branch to diff +against by using the '--rev' option. +""" +# This code is derived from appcfg.py in the App Engine SDK (open source), +# and from ASPN recipe #146306. + +import cookielib +import getpass +import logging +import md5 +import mimetypes +import optparse +import os +import re +import socket +import subprocess +import sys +import urllib +import urllib2 +import urlparse + +try: + import readline +except ImportError: + pass + +# The logging verbosity: +# 0: Errors only. +# 1: Status messages. +# 2: Info logs. +# 3: Debug logs. +verbosity = 1 + +# Max size of patch or base file. +MAX_UPLOAD_SIZE = 900 * 1024 + + +def GetEmail(prompt): + """Prompts the user for their email address and returns it. + + The last used email address is saved to a file and offered up as a suggestion + to the user. If the user presses enter without typing in anything the last + used email address is used. If the user enters a new address, it is saved + for next time we prompt. + + """ + last_email_file_name = os.path.expanduser("~/.last_codereview_email_address") + last_email = "" + if os.path.exists(last_email_file_name): + try: + last_email_file = open(last_email_file_name, "r") + last_email = last_email_file.readline().strip("\n") + last_email_file.close() + prompt += " [%s]" % last_email + except IOError, e: + pass + email = raw_input(prompt + ": ").strip() + if email: + try: + last_email_file = open(last_email_file_name, "w") + last_email_file.write(email) + last_email_file.close() + except IOError, e: + pass + else: + email = last_email + return email + + +def StatusUpdate(msg): + """Print a status message to stdout. + + If 'verbosity' is greater than 0, print the message. + + Args: + msg: The string to print. + """ + if verbosity > 0: + print msg + + +def ErrorExit(msg): + """Print an error message to stderr and exit.""" + print >>sys.stderr, msg + sys.exit(1) + + +class ClientLoginError(urllib2.HTTPError): + """Raised to indicate there was an error authenticating with ClientLogin.""" + + def __init__(self, url, code, msg, headers, args): + urllib2.HTTPError.__init__(self, url, code, msg, headers, None) + self.args = args + self.reason = args["Error"] + + +class AbstractRpcServer(object): + """Provides a common interface for a simple RPC server.""" + + def __init__(self, host, auth_function, host_override=None, extra_headers={}, + save_cookies=False): + """Creates a new HttpRpcServer. + + Args: + host: The host to send requests to. + auth_function: A function that takes no arguments and returns an + (email, password) tuple when called. Will be called if authentication + is required. + host_override: The host header to send to the server (defaults to host). + extra_headers: A dict of extra headers to append to every request. + save_cookies: If True, save the authentication cookies to local disk. + If False, use an in-memory cookiejar instead. Subclasses must + implement this functionality. Defaults to False. + """ + self.host = host + self.host_override = host_override + self.auth_function = auth_function + self.authenticated = False + self.extra_headers = extra_headers + self.save_cookies = save_cookies + self.opener = self._GetOpener() + if self.host_override: + logging.info("Server: %s; Host: %s", self.host, self.host_override) + else: + logging.info("Server: %s", self.host) + + def _GetOpener(self): + """Returns an OpenerDirector for making HTTP requests. + + Returns: + A urllib2.OpenerDirector object. + """ + raise NotImplementedError() + + def _CreateRequest(self, url, data=None): + """Creates a new urllib request.""" + logging.debug("Creating request for: '%s' with payload:\n%s", url, data) + req = urllib2.Request(url, data=data) + if self.host_override: + req.add_header("Host", self.host_override) + for key, value in self.extra_headers.iteritems(): + req.add_header(key, value) + return req + + def _GetAuthToken(self, email, password): + """Uses ClientLogin to authenticate the user, returning an auth token. + + Args: + email: The user's email address + password: The user's password + + Raises: + ClientLoginError: If there was an error authenticating with ClientLogin. + HTTPError: If there was some other form of HTTP error. + + Returns: + The authentication token returned by ClientLogin. + """ + account_type = "GOOGLE" + if self.host.endswith(".google.com"): + # Needed for use inside Google. + account_type = "HOSTED" + req = self._CreateRequest( + url="https://www.google.com/accounts/ClientLogin", + data=urllib.urlencode({ + "Email": email, + "Passwd": password, + "service": "ah", + "source": "rietveld-codereview-upload", + "accountType": account_type, + }), + ) + try: + response = self.opener.open(req) + response_body = response.read() + response_dict = dict(x.split("=") + for x in response_body.split("\n") if x) + return response_dict["Auth"] + except urllib2.HTTPError, e: + if e.code == 403: + body = e.read() + response_dict = dict(x.split("=", 1) for x in body.split("\n") if x) + raise ClientLoginError(req.get_full_url(), e.code, e.msg, + e.headers, response_dict) + else: + raise + + def _GetAuthCookie(self, auth_token): + """Fetches authentication cookies for an authentication token. + + Args: + auth_token: The authentication token returned by ClientLogin. + + Raises: + HTTPError: If there was an error fetching the authentication cookies. + """ + # This is a dummy value to allow us to identify when we're successful. + continue_location = "http://localhost/" + args = {"continue": continue_location, "auth": auth_token} + req = self._CreateRequest("http://%s/_ah/login?%s" % + (self.host, urllib.urlencode(args))) + try: + response = self.opener.open(req) + except urllib2.HTTPError, e: + response = e + if (response.code != 302 or + response.info()["location"] != continue_location): + raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg, + response.headers, response.fp) + self.authenticated = True + + def _Authenticate(self): + """Authenticates the user. + + The authentication process works as follows: + 1) We get a username and password from the user + 2) We use ClientLogin to obtain an AUTH token for the user + (see http://code.google.com/apis/accounts/AuthForInstalledApps.html). + 3) We pass the auth token to /_ah/login on the server to obtain an + authentication cookie. If login was successful, it tries to redirect + us to the URL we provided. + + If we attempt to access the upload API without first obtaining an + authentication cookie, it returns a 401 response and directs us to + authenticate ourselves with ClientLogin. + """ + for i in range(3): + credentials = self.auth_function() + try: + auth_token = self._GetAuthToken(credentials[0], credentials[1]) + except ClientLoginError, e: + if e.reason == "BadAuthentication": + print >>sys.stderr, "Invalid username or password." + continue + if e.reason == "CaptchaRequired": + print >>sys.stderr, ( + "Please go to\n" + "https://www.google.com/accounts/DisplayUnlockCaptcha\n" + "and verify you are a human. Then try again.") + break + if e.reason == "NotVerified": + print >>sys.stderr, "Account not verified." + break + if e.reason == "TermsNotAgreed": + print >>sys.stderr, "User has not agreed to TOS." + break + if e.reason == "AccountDeleted": + print >>sys.stderr, "The user account has been deleted." + break + if e.reason == "AccountDisabled": + print >>sys.stderr, "The user account has been disabled." + break + if e.reason == "ServiceDisabled": + print >>sys.stderr, ("The user's access to the service has been " + "disabled.") + break + if e.reason == "ServiceUnavailable": + print >>sys.stderr, "The service is not available; try again later." + break + raise + self._GetAuthCookie(auth_token) + return + + def Send(self, request_path, payload=None, + content_type="application/octet-stream", + timeout=None, + **kwargs): + """Sends an RPC and returns the response. + + Args: + request_path: The path to send the request to, eg /api/appversion/create. + payload: The body of the request, or None to send an empty request. + content_type: The Content-Type header to use. + timeout: timeout in seconds; default None i.e. no timeout. + (Note: for large requests on OS X, the timeout doesn't work right.) + kwargs: Any keyword arguments are converted into query string parameters. + + Returns: + The response body, as a string. + """ + # TODO: Don't require authentication. Let the server say + # whether it is necessary. + if not self.authenticated: + self._Authenticate() + + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + tries = 0 + while True: + tries += 1 + args = dict(kwargs) + url = "http://%s%s" % (self.host, request_path) + if args: + url += "?" + urllib.urlencode(args) + req = self._CreateRequest(url=url, data=payload) + req.add_header("Content-Type", content_type) + try: + f = self.opener.open(req) + response = f.read() + f.close() + return response + except urllib2.HTTPError, e: + if tries > 3: + raise + elif e.code == 401: + self._Authenticate() +## elif e.code >= 500 and e.code < 600: +## # Server Error - try again. +## continue + else: + raise + finally: + socket.setdefaulttimeout(old_timeout) + + +class HttpRpcServer(AbstractRpcServer): + """Provides a simplified RPC-style interface for HTTP requests.""" + + def _Authenticate(self): + """Save the cookie jar after authentication.""" + super(HttpRpcServer, self)._Authenticate() + if self.save_cookies: + StatusUpdate("Saving authentication cookies to %s" % self.cookie_file) + self.cookie_jar.save() + + def _GetOpener(self): + """Returns an OpenerDirector that supports cookies and ignores redirects. + + Returns: + A urllib2.OpenerDirector object. + """ + opener = urllib2.OpenerDirector() + opener.add_handler(urllib2.ProxyHandler()) + opener.add_handler(urllib2.UnknownHandler()) + opener.add_handler(urllib2.HTTPHandler()) + opener.add_handler(urllib2.HTTPDefaultErrorHandler()) + opener.add_handler(urllib2.HTTPSHandler()) + opener.add_handler(urllib2.HTTPErrorProcessor()) + if self.save_cookies: + self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies") + self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file) + if os.path.exists(self.cookie_file): + try: + self.cookie_jar.load() + self.authenticated = True + StatusUpdate("Loaded authentication cookies from %s" % + self.cookie_file) + except (cookielib.LoadError, IOError): + # Failed to load cookies - just ignore them. + pass + else: + # Create an empty cookie file with mode 600 + fd = os.open(self.cookie_file, os.O_CREAT, 0600) + os.close(fd) + # Always chmod the cookie file + os.chmod(self.cookie_file, 0600) + else: + # Don't save cookies across runs of update.py. + self.cookie_jar = cookielib.CookieJar() + opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) + return opener + + +parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]") +parser.add_option("-y", "--assume_yes", action="store_true", + dest="assume_yes", default=False, + help="Assume that the answer to yes/no questions is 'yes'.") +# Logging +group = parser.add_option_group("Logging options") +group.add_option("-q", "--quiet", action="store_const", const=0, + dest="verbose", help="Print errors only.") +group.add_option("-v", "--verbose", action="store_const", const=2, + dest="verbose", default=1, + help="Print info level logs (default).") +group.add_option("--noisy", action="store_const", const=3, + dest="verbose", help="Print all logs.") +# Review server +group = parser.add_option_group("Review server options") +group.add_option("-s", "--server", action="store", dest="server", + default="codereview.appspot.com", + metavar="SERVER", + help=("The server to upload to. The format is host[:port]. " + "Defaults to 'codereview.appspot.com'.")) +group.add_option("-e", "--email", action="store", dest="email", + metavar="EMAIL", default=None, + help="The username to use. Will prompt if omitted.") +group.add_option("-H", "--host", action="store", dest="host", + metavar="HOST", default=None, + help="Overrides the Host header sent with all RPCs.") +group.add_option("--no_cookies", action="store_false", + dest="save_cookies", default=True, + help="Do not save authentication cookies to local disk.") +# Issue +group = parser.add_option_group("Issue options") +group.add_option("-d", "--description", action="store", dest="description", + metavar="DESCRIPTION", default=None, + help="Optional description when creating an issue.") +group.add_option("-f", "--description_file", action="store", + dest="description_file", metavar="DESCRIPTION_FILE", + default=None, + help="Optional path of a file that contains " + "the description when creating an issue.") +group.add_option("-r", "--reviewers", action="store", dest="reviewers", + metavar="REVIEWERS", default=None, + help="Add reviewers (comma separated email addresses).") +group.add_option("--cc", action="store", dest="cc", + metavar="CC", default=None, + help="Add CC (comma separated email addresses).") +# Upload options +group = parser.add_option_group("Patch options") +group.add_option("-m", "--message", action="store", dest="message", + metavar="MESSAGE", default=None, + help="A message to identify the patch. " + "Will prompt if omitted.") +group.add_option("-i", "--issue", type="int", action="store", + metavar="ISSUE", default=None, + help="Issue number to which to add. Defaults to new issue.") +group.add_option("--download_base", action="store_true", + dest="download_base", default=False, + help="Base files will be downloaded by the server " + "(side-by-side diffs may not work on files with CRs).") +group.add_option("--rev", action="store", dest="revision", + metavar="REV", default=None, + help="Branch/tree/revision to diff against (used by DVCS).") +group.add_option("--send_mail", action="store_true", + dest="send_mail", default=False, + help="Send notification email to reviewers.") + + +def GetRpcServer(options): + """Returns an instance of an AbstractRpcServer. + + Returns: + A new AbstractRpcServer, on which RPC calls can be made. + """ + + rpc_server_class = HttpRpcServer + + def GetUserCredentials(): + """Prompts the user for a username and password.""" + email = options.email + if email is None: + email = GetEmail("Email (login for uploading to %s)" % options.server) + password = getpass.getpass("Password for %s: " % email) + return (email, password) + + # If this is the dev_appserver, use fake authentication. + host = (options.host or options.server).lower() + if host == "localhost" or host.startswith("localhost:"): + email = options.email + if email is None: + email = "test@example.com" + logging.info("Using debug user %s. Override with --email" % email) + server = rpc_server_class( + options.server, + lambda: (email, "password"), + host_override=options.host, + extra_headers={"Cookie": + 'dev_appserver_login="%s:False"' % email}, + save_cookies=options.save_cookies) + # Don't try to talk to ClientLogin. + server.authenticated = True + return server + + return rpc_server_class(options.server, GetUserCredentials, + host_override=options.host, + save_cookies=options.save_cookies) + + +def EncodeMultipartFormData(fields, files): + """Encode form fields for multipart/form-data. + + Args: + fields: A sequence of (name, value) elements for regular form fields. + files: A sequence of (name, filename, value) elements for data to be + uploaded as files. + Returns: + (content_type, body) ready for httplib.HTTP instance. + + Source: + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306 + """ + BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-' + CRLF = '\r\n' + lines = [] + for (key, value) in fields: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"' % key) + lines.append('') + lines.append(value) + for (key, filename, value) in files: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)) + lines.append('Content-Type: %s' % GetContentType(filename)) + lines.append('') + lines.append(value) + lines.append('--' + BOUNDARY + '--') + lines.append('') + body = CRLF.join(lines) + content_type = 'multipart/form-data; boundary=%s' % BOUNDARY + return content_type, body + + +def GetContentType(filename): + """Helper to guess the content-type from the filename.""" + return mimetypes.guess_type(filename)[0] or 'application/octet-stream' + + +# Use a shell for subcommands on Windows to get a PATH search. +use_shell = sys.platform.startswith("win") + +def RunShellWithReturnCode(command, print_output=False, + universal_newlines=True): + """Executes a command and returns the output from stdout and the return code. + + Args: + command: Command to execute. + print_output: If True, the output is printed to stdout. + If False, both stdout and stderr are ignored. + universal_newlines: Use universal_newlines flag (default: True). + + Returns: + Tuple (output, return code) + """ + logging.info("Running %s", command) + p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=use_shell, universal_newlines=universal_newlines) + if print_output: + output_array = [] + while True: + line = p.stdout.readline() + if not line: + break + print line.strip("\n") + output_array.append(line) + output = "".join(output_array) + else: + output = p.stdout.read() + p.wait() + errout = p.stderr.read() + if print_output and errout: + print >>sys.stderr, errout + p.stdout.close() + p.stderr.close() + return output, p.returncode + + +def RunShell(command, silent_ok=False, universal_newlines=True, + print_output=False): + data, retcode = RunShellWithReturnCode(command, print_output, + universal_newlines) + if retcode: + ErrorExit("Got error status from %s:\n%s" % (command, data)) + if not silent_ok and not data: + ErrorExit("No output from %s" % command) + return data + + +class VersionControlSystem(object): + """Abstract base class providing an interface to the VCS.""" + + def __init__(self, options): + """Constructor. + + Args: + options: Command line options. + """ + self.options = options + + def GenerateDiff(self, args): + """Return the current diff as a string. + + Args: + args: Extra arguments to pass to the diff command. + """ + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def CheckForUnknownFiles(self): + """Show an "are you sure?" prompt if there are unknown files.""" + unknown_files = self.GetUnknownFiles() + if unknown_files: + print "The following files are not added to version control:" + for line in unknown_files: + print line + prompt = "Are you sure to continue?(y/N) " + answer = raw_input(prompt).strip() + if answer != "y": + ErrorExit("User aborted") + + def GetBaseFile(self, filename): + """Get the content of the upstream version of a file. + + Returns: + A tuple (base_content, new_content, is_binary, status) + base_content: The contents of the base file. + new_content: For text files, this is empty. For binary files, this is + the contents of the new file, since the diff output won't contain + information to reconstruct the current file. + is_binary: True iff the file is binary. + status: The status of the file. + """ + + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + + def GetBaseFiles(self, diff): + """Helper that calls GetBase file for each file in the patch. + + Returns: + A dictionary that maps from filename to GetBaseFile's tuple. Filenames + are retrieved based on lines that start with "Index:" or + "Property changes on:". + """ + files = {} + for line in diff.splitlines(True): + if line.startswith('Index:') or line.startswith('Property changes on:'): + unused, filename = line.split(':', 1) + # On Windows if a file has property changes its filename uses '\' + # instead of '/'. + filename = filename.strip().replace('\\', '/') + files[filename] = self.GetBaseFile(filename) + return files + + + def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, + files): + """Uploads the base files (and if necessary, the current ones as well).""" + + def UploadFile(filename, file_id, content, is_binary, status, is_base): + """Uploads a file to the server.""" + file_too_large = False + if is_base: + type = "base" + else: + type = "current" + if len(content) > MAX_UPLOAD_SIZE: + print ("Not uploading the %s file for %s because it's too large." % + (type, filename)) + file_too_large = True + content = "" + checksum = md5.new(content).hexdigest() + if options.verbose > 0 and not file_too_large: + print "Uploading %s file for %s" % (type, filename) + url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id) + form_fields = [("filename", filename), + ("status", status), + ("checksum", checksum), + ("is_binary", str(is_binary)), + ("is_current", str(not is_base)), + ] + if file_too_large: + form_fields.append(("file_too_large", "1")) + if options.email: + form_fields.append(("user", options.email)) + ctype, body = EncodeMultipartFormData(form_fields, + [("data", filename, content)]) + response_body = rpc_server.Send(url, body, + content_type=ctype) + if not response_body.startswith("OK"): + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + + patches = dict() + [patches.setdefault(v, k) for k, v in patch_list] + for filename in patches.keys(): + base_content, new_content, is_binary, status = files[filename] + file_id_str = patches.get(filename) + if file_id_str.find("nobase") != -1: + base_content = None + file_id_str = file_id_str[file_id_str.rfind("_") + 1:] + file_id = int(file_id_str) + if base_content != None: + UploadFile(filename, file_id, base_content, is_binary, status, True) + if new_content != None: + UploadFile(filename, file_id, new_content, is_binary, status, False) + + def IsImage(self, filename): + """Returns true if the filename has an image extension.""" + mimetype = mimetypes.guess_type(filename)[0] + if not mimetype: + return False + return mimetype.startswith("image/") + + +class SubversionVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Subversion.""" + + def __init__(self, options): + super(SubversionVCS, self).__init__(options) + if self.options.revision: + match = re.match(r"(\d+)(:(\d+))?", self.options.revision) + if not match: + ErrorExit("Invalid Subversion revision %s." % self.options.revision) + self.rev_start = match.group(1) + self.rev_end = match.group(3) + else: + self.rev_start = self.rev_end = None + # Cache output from "svn list -r REVNO dirname". + # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev). + self.svnls_cache = {} + # SVN base URL is required to fetch files deleted in an older revision. + # Result is cached to not guess it over and over again in GetBaseFile(). + required = self.options.download_base or self.options.revision is not None + self.svn_base = self._GuessBase(required) + + def GuessBase(self, required): + """Wrapper for _GuessBase.""" + return self.svn_base + + def _GuessBase(self, required): + """Returns the SVN base URL. + + Args: + required: If true, exits if the url can't be guessed, otherwise None is + returned. + """ + info = RunShell(["svn", "info"]) + for line in info.splitlines(): + words = line.split() + if len(words) == 2 and words[0] == "URL:": + url = words[1] + scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) + username, netloc = urllib.splituser(netloc) + if username: + logging.info("Removed username from base URL") + if netloc.endswith("svn.python.org"): + if netloc == "svn.python.org": + if path.startswith("/projects/"): + path = path[9:] + elif netloc != "pythondev@svn.python.org": + ErrorExit("Unrecognized Python URL: %s" % url) + base = "http://svn.python.org/view/*checkout*%s/" % path + logging.info("Guessed Python base = %s", base) + elif netloc.endswith("svn.collab.net"): + if path.startswith("/repos/"): + path = path[6:] + base = "http://svn.collab.net/viewvc/*checkout*%s/" % path + logging.info("Guessed CollabNet base = %s", base) + elif netloc.endswith(".googlecode.com"): + path = path + "/" + base = urlparse.urlunparse(("http", netloc, path, params, + query, fragment)) + logging.info("Guessed Google Code base = %s", base) + else: + path = path + "/" + base = urlparse.urlunparse((scheme, netloc, path, params, + query, fragment)) + logging.info("Guessed base = %s", base) + return base + if required: + ErrorExit("Can't find URL in output from svn info") + return None + + def GenerateDiff(self, args): + cmd = ["svn", "diff"] + if self.options.revision: + cmd += ["-r", self.options.revision] + cmd.extend(args) + data = RunShell(cmd) + count = 0 + for line in data.splitlines(): + if line.startswith("Index:") or line.startswith("Property changes on:"): + count += 1 + logging.info(line) + if not count: + ErrorExit("No valid patches found in output from svn diff") + return data + + def _CollapseKeywords(self, content, keyword_str): + """Collapses SVN keywords.""" + # svn cat translates keywords but svn diff doesn't. As a result of this + # behavior patching.PatchChunks() fails with a chunk mismatch error. + # This part was originally written by the Review Board development team + # who had the same problem (http://reviews.review-board.org/r/276/). + # Mapping of keywords to known aliases + svn_keywords = { + # Standard keywords + 'Date': ['Date', 'LastChangedDate'], + 'Revision': ['Revision', 'LastChangedRevision', 'Rev'], + 'Author': ['Author', 'LastChangedBy'], + 'HeadURL': ['HeadURL', 'URL'], + 'Id': ['Id'], + + # Aliases + 'LastChangedDate': ['LastChangedDate', 'Date'], + 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'], + 'LastChangedBy': ['LastChangedBy', 'Author'], + 'URL': ['URL', 'HeadURL'], + } + + def repl(m): + if m.group(2): + return "$%s::%s$" % (m.group(1), " " * len(m.group(3))) + return "$%s$" % m.group(1) + keywords = [keyword + for name in keyword_str.split(" ") + for keyword in svn_keywords.get(name, [])] + return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content) + + def GetUnknownFiles(self): + status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True) + unknown_files = [] + for line in status.split("\n"): + if line and line[0] == "?": + unknown_files.append(line) + return unknown_files + + def ReadFile(self, filename): + """Returns the contents of a file.""" + file = open(filename, 'rb') + result = "" + try: + result = file.read() + finally: + file.close() + return result + + def GetStatus(self, filename): + """Returns the status of a file.""" + if not self.options.revision: + status = RunShell(["svn", "status", "--ignore-externals", filename]) + if not status: + ErrorExit("svn status returned no output for %s" % filename) + status_lines = status.splitlines() + # If file is in a cl, the output will begin with + # "\n--- Changelist 'cl_name':\n". See + # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt + if (len(status_lines) == 3 and + not status_lines[0] and + status_lines[1].startswith("--- Changelist")): + status = status_lines[2] + else: + status = status_lines[0] + # If we have a revision to diff against we need to run "svn list" + # for the old and the new revision and compare the results to get + # the correct status for a file. + else: + dirname, relfilename = os.path.split(filename) + if dirname not in self.svnls_cache: + cmd = ["svn", "list", "-r", self.rev_start, dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to get status for %s." % filename) + old_files = out.splitlines() + args = ["svn", "list"] + if self.rev_end: + args += ["-r", self.rev_end] + cmd = args + [dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to run command %s" % cmd) + self.svnls_cache[dirname] = (old_files, out.splitlines()) + old_files, new_files = self.svnls_cache[dirname] + if relfilename in old_files and relfilename not in new_files: + status = "D " + elif relfilename in old_files and relfilename in new_files: + status = "M " + else: + status = "A " + return status + + def GetBaseFile(self, filename): + status = self.GetStatus(filename) + base_content = None + new_content = None + + # If a file is copied its status will be "A +", which signifies + # "addition-with-history". See "svn st" for more information. We need to + # upload the original file or else diff parsing will fail if the file was + # edited. + if status[0] == "A" and status[3] != "+": + # We'll need to upload the new content if we're adding a binary file + # since diff's output won't contain it. + mimetype = RunShell(["svn", "propget", "svn:mime-type", filename], + silent_ok=True) + base_content = "" + is_binary = mimetype and not mimetype.startswith("text/") + if is_binary and self.IsImage(filename): + new_content = self.ReadFile(filename) + elif (status[0] in ("M", "D", "R") or + (status[0] == "A" and status[3] == "+") or # Copied file. + (status[0] == " " and status[1] == "M")): # Property change. + args = [] + if self.options.revision: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + # Don't change filename, it's needed later. + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:mime-type", url] + mimetype, returncode = RunShellWithReturnCode(cmd) + if returncode: + # File does not exist in the requested revision. + # Reset mimetype, it contains an error message. + mimetype = "" + get_base = False + is_binary = mimetype and not mimetype.startswith("text/") + if status[0] == " ": + # Empty base content just to force an upload. + base_content = "" + elif is_binary: + if self.IsImage(filename): + get_base = True + if status[0] == "M": + if not self.rev_end: + new_content = self.ReadFile(filename) + else: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end) + new_content = RunShell(["svn", "cat", url], + universal_newlines=True, silent_ok=True) + else: + base_content = "" + else: + get_base = True + + if get_base: + if is_binary: + universal_newlines = False + else: + universal_newlines = True + if self.rev_start: + # "svn cat -r REV delete_file.txt" doesn't work. cat requires + # the full URL with "@REV" appended instead of using "-r" option. + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + base_content = RunShell(["svn", "cat", url], + universal_newlines=universal_newlines, + silent_ok=True) + else: + base_content = RunShell(["svn", "cat", filename], + universal_newlines=universal_newlines, + silent_ok=True) + if not is_binary: + args = [] + if self.rev_start: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:keywords", url] + keywords, returncode = RunShellWithReturnCode(cmd) + if keywords and not returncode: + base_content = self._CollapseKeywords(base_content, keywords) + else: + StatusUpdate("svn status returned unexpected output: %s" % status) + sys.exit(1) + return base_content, new_content, is_binary, status[0:5] + + +class GitVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Git.""" + + def __init__(self, options): + super(GitVCS, self).__init__(options) + # Map of filename -> hash of base file. + self.base_hashes = {} + + def GenerateDiff(self, extra_args): + # This is more complicated than svn's GenerateDiff because we must convert + # the diff output to include an svn-style "Index:" line as well as record + # the hashes of the base files, so we can upload them along with our diff. + if self.options.revision: + extra_args = [self.options.revision] + extra_args + gitdiff = RunShell(["git", "diff", "--full-index"] + extra_args) + svndiff = [] + filecount = 0 + filename = None + for line in gitdiff.splitlines(): + match = re.match(r"diff --git a/(.*) b/.*$", line) + if match: + filecount += 1 + filename = match.group(1) + svndiff.append("Index: %s\n" % filename) + else: + # The "index" line in a git diff looks like this (long hashes elided): + # index 82c0d44..b2cee3f 100755 + # We want to save the left hash, as that identifies the base file. + match = re.match(r"index (\w+)\.\.", line) + if match: + self.base_hashes[filename] = match.group(1) + svndiff.append(line + "\n") + if not filecount: + ErrorExit("No valid patches found in output from git diff") + return "".join(svndiff) + + def GetUnknownFiles(self): + status = RunShell(["git", "ls-files", "--exclude-standard", "--others"], + silent_ok=True) + return status.splitlines() + + def GetBaseFile(self, filename): + hash = self.base_hashes[filename] + base_content = None + new_content = None + is_binary = False + if hash == "0" * 40: # All-zero hash indicates no base file. + status = "A" + base_content = "" + else: + status = "M" + base_content, returncode = RunShellWithReturnCode(["git", "show", hash]) + if returncode: + ErrorExit("Got error status from 'git show %s'" % hash) + return (base_content, new_content, is_binary, status) + + +class MercurialVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Mercurial.""" + + def __init__(self, options, repo_dir): + super(MercurialVCS, self).__init__(options) + # Absolute path to repository (we can be in a subdir) + self.repo_dir = os.path.normpath(repo_dir) + # Compute the subdir + cwd = os.path.normpath(os.getcwd()) + assert cwd.startswith(self.repo_dir) + self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") + if self.options.revision: + self.base_rev = self.options.revision + else: + self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip() + + def _GetRelPath(self, filename): + """Get relative path of a file according to the current directory, + given its logical path in the repo.""" + assert filename.startswith(self.subdir), filename + return filename[len(self.subdir):].lstrip(r"\/") + + def GenerateDiff(self, extra_args): + # If no file specified, restrict to the current subdir + extra_args = extra_args or ["."] + cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args + data = RunShell(cmd, silent_ok=True) + svndiff = [] + filecount = 0 + for line in data.splitlines(): + m = re.match("diff --git a/(\S+) b/(\S+)", line) + if m: + # Modify line to make it look like as it comes from svn diff. + # With this modification no changes on the server side are required + # to make upload.py work with Mercurial repos. + # NOTE: for proper handling of moved/copied files, we have to use + # the second filename. + filename = m.group(2) + svndiff.append("Index: %s" % filename) + svndiff.append("=" * 67) + filecount += 1 + logging.info(line) + else: + svndiff.append(line) + if not filecount: + ErrorExit("No valid patches found in output from hg diff") + return "\n".join(svndiff) + "\n" + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + args = [] + status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], + silent_ok=True) + unknown_files = [] + for line in status.splitlines(): + st, fn = line.split(" ", 1) + if st == "?": + unknown_files.append(fn) + return unknown_files + + def GetBaseFile(self, filename): + # "hg status" and "hg cat" both take a path relative to the current subdir + # rather than to the repo root, but "hg diff" has given us the full path + # to the repo root. + base_content = "" + new_content = None + is_binary = False + oldrelpath = relpath = self._GetRelPath(filename) + # "hg status -C" returns two lines for moved/copied files, one otherwise + out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) + out = out.splitlines() + # HACK: strip error message about missing file/directory if it isn't in + # the working copy + if out[0].startswith('%s: ' % relpath): + out = out[1:] + if len(out) > 1: + # Moved/copied => considered as modified, use old filename to + # retrieve base contents + oldrelpath = out[1].strip() + status = "M" + else: + status, _ = out[0].split(' ', 1) + if status != "A": + base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath], + silent_ok=True) + is_binary = "\0" in base_content # Mercurial's heuristic + if status != "R": + new_content = open(relpath, "rb").read() + is_binary = is_binary or "\0" in new_content + if is_binary and base_content: + # Fetch again without converting newlines + base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath], + silent_ok=True, universal_newlines=False) + if not is_binary or not self.IsImage(relpath): + new_content = None + return base_content, new_content, is_binary, status + + +# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync. +def SplitPatch(data): + """Splits a patch into separate pieces for each file. + + Args: + data: A string containing the output of svn diff. + + Returns: + A list of 2-tuple (filename, text) where text is the svn diff output + pertaining to filename. + """ + patches = [] + filename = None + diff = [] + for line in data.splitlines(True): + new_filename = None + if line.startswith('Index:'): + unused, new_filename = line.split(':', 1) + new_filename = new_filename.strip() + elif line.startswith('Property changes on:'): + unused, temp_filename = line.split(':', 1) + # When a file is modified, paths use '/' between directories, however + # when a property is modified '\' is used on Windows. Make them the same + # otherwise the file shows up twice. + temp_filename = temp_filename.strip().replace('\\', '/') + if temp_filename != filename: + # File has property changes but no modifications, create a new diff. + new_filename = temp_filename + if new_filename: + if filename and diff: + patches.append((filename, ''.join(diff))) + filename = new_filename + diff = [line] + continue + if diff is not None: + diff.append(line) + if filename and diff: + patches.append((filename, ''.join(diff))) + return patches + + +def UploadSeparatePatches(issue, rpc_server, patchset, data, options): + """Uploads a separate patch for each file in the diff output. + + Returns a list of [patch_key, filename] for each file. + """ + patches = SplitPatch(data) + rv = [] + for patch in patches: + if len(patch[1]) > MAX_UPLOAD_SIZE: + print ("Not uploading the patch for " + patch[0] + + " because the file is too large.") + continue + form_fields = [("filename", patch[0])] + if not options.download_base: + form_fields.append(("content_upload", "1")) + files = [("data", "data.diff", patch[1])] + ctype, body = EncodeMultipartFormData(form_fields, files) + url = "/%d/upload_patch/%d" % (int(issue), int(patchset)) + print "Uploading patch for " + patch[0] + response_body = rpc_server.Send(url, body, content_type=ctype) + lines = response_body.splitlines() + if not lines or lines[0] != "OK": + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + rv.append([lines[1], patch[0]]) + return rv + + +def GuessVCS(options): + """Helper to guess the version control system. + + This examines the current directory, guesses which VersionControlSystem + we're using, and returns an instance of the appropriate class. Exit with an + error if we can't figure it out. + + Returns: + A VersionControlSystem instance. Exits if the VCS can't be guessed. + """ + # Mercurial has a command to get the base directory of a repository + # Try running it, but don't die if we don't have hg installed. + # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. + try: + out, returncode = RunShellWithReturnCode(["hg", "root"]) + if returncode == 0: + return MercurialVCS(options, out.strip()) + except OSError, (errno, message): + if errno != 2: # ENOENT -- they don't have hg installed. + raise + + # Subversion has a .svn in all working directories. + if os.path.isdir('.svn'): + logging.info("Guessed VCS = Subversion") + return SubversionVCS(options) + + # Git has a command to test if you're in a git tree. + # Try running it, but don't die if we don't have git installed. + try: + out, returncode = RunShellWithReturnCode(["git", "rev-parse", + "--is-inside-work-tree"]) + if returncode == 0: + return GitVCS(options) + except OSError, (errno, message): + if errno != 2: # ENOENT -- they don't have git installed. + raise + + ErrorExit(("Could not guess version control system. " + "Are you in a working copy directory?")) + + +def RealMain(argv, data=None): + """The real main function. + + Args: + argv: Command line arguments. + data: Diff contents. If None (default) the diff is generated by + the VersionControlSystem implementation returned by GuessVCS(). + + Returns: + A 2-tuple (issue id, patchset id). + The patchset id is None if the base files are not uploaded by this + script (applies only to SVN checkouts). + """ + logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" + "%(lineno)s %(message)s ")) + os.environ['LC_ALL'] = 'C' + options, args = parser.parse_args(argv[1:]) + global verbosity + verbosity = options.verbose + if verbosity >= 3: + logging.getLogger().setLevel(logging.DEBUG) + elif verbosity >= 2: + logging.getLogger().setLevel(logging.INFO) + vcs = GuessVCS(options) + if isinstance(vcs, SubversionVCS): + # base field is only allowed for Subversion. + # Note: Fetching base files may become deprecated in future releases. + base = vcs.GuessBase(options.download_base) + else: + base = None + if not base and options.download_base: + options.download_base = True + logging.info("Enabled upload of base file") + if not options.assume_yes: + vcs.CheckForUnknownFiles() + if data is None: + data = vcs.GenerateDiff(args) + files = vcs.GetBaseFiles(data) + if verbosity >= 1: + print "Upload server:", options.server, "(change with -s/--server)" + if options.issue: + prompt = "Message describing this patch set: " + else: + prompt = "New issue subject: " + message = options.message or raw_input(prompt).strip() + if not message: + ErrorExit("A non-empty message is required") + rpc_server = GetRpcServer(options) + form_fields = [("subject", message)] + if base: + form_fields.append(("base", base)) + if options.issue: + form_fields.append(("issue", str(options.issue))) + if options.email: + form_fields.append(("user", options.email)) + if options.reviewers: + for reviewer in options.reviewers.split(','): + if "@" in reviewer and not reviewer.split("@")[1].count(".") == 1: + ErrorExit("Invalid email address: %s" % reviewer) + form_fields.append(("reviewers", options.reviewers)) + if options.cc: + for cc in options.cc.split(','): + if "@" in cc and not cc.split("@")[1].count(".") == 1: + ErrorExit("Invalid email address: %s" % cc) + form_fields.append(("cc", options.cc)) + description = options.description + if options.description_file: + if options.description: + ErrorExit("Can't specify description and description_file") + file = open(options.description_file, 'r') + description = file.read() + file.close() + if description: + form_fields.append(("description", description)) + # Send a hash of all the base file so the server can determine if a copy + # already exists in an earlier patchset. + base_hashes = "" + for file, info in files.iteritems(): + if not info[0] is None: + checksum = md5.new(info[0]).hexdigest() + if base_hashes: + base_hashes += "|" + base_hashes += checksum + ":" + file + form_fields.append(("base_hashes", base_hashes)) + # If we're uploading base files, don't send the email before the uploads, so + # that it contains the file status. + if options.send_mail and options.download_base: + form_fields.append(("send_mail", "1")) + if not options.download_base: + form_fields.append(("content_upload", "1")) + if len(data) > MAX_UPLOAD_SIZE: + print "Patch is large, so uploading file patches separately." + uploaded_diff_file = [] + form_fields.append(("separate_patches", "1")) + else: + uploaded_diff_file = [("data", "data.diff", data)] + ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) + response_body = rpc_server.Send("/upload", body, content_type=ctype) + patchset = None + if not options.download_base or not uploaded_diff_file: + lines = response_body.splitlines() + if len(lines) >= 2: + msg = lines[0] + patchset = lines[1].strip() + patches = [x.split(" ", 1) for x in lines[2:]] + else: + msg = response_body + else: + msg = response_body + StatusUpdate(msg) + if not response_body.startswith("Issue created.") and \ + not response_body.startswith("Issue updated."): + sys.exit(0) + issue = msg[msg.rfind("/")+1:] + + if not uploaded_diff_file: + result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) + if not options.download_base: + patches = result + + if not options.download_base: + vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) + if options.send_mail: + rpc_server.Send("/" + issue + "/mail", payload="") + return issue, patchset + + +def main(): + try: + RealMain(sys.argv) + except KeyboardInterrupt: + print + StatusUpdate("Interrupted.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/scripts/upload_gmock.py b/scripts/upload_gmock.py new file mode 100755 index 00000000..5dc484b3 --- /dev/null +++ b/scripts/upload_gmock.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# +# Copyright 2009, 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. + +"""upload_gmock.py v0.1.0 -- uploads a Google Mock patch for review. + +This simple wrapper passes all command line flags and +--cc=googlemock@googlegroups.com to upload.py. + +USAGE: upload_gmock.py [options for upload.py] +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import sys + +CC_FLAG = '--cc=' +GMOCK_GROUP = 'googlemock@googlegroups.com' + + +def main(): + # Finds the path to upload.py, assuming it is in the same directory + # as this file. + my_dir = os.path.dirname(os.path.abspath(__file__)) + upload_py_path = os.path.join(my_dir, 'upload.py') + + # Adds Google Mock discussion group to the cc line if it's not there + # already. + upload_py_argv = [upload_py_path] + found_cc_flag = False + for arg in sys.argv[1:]: + if arg.startswith(CC_FLAG): + found_cc_flag = True + cc_line = arg[len(CC_FLAG):] + cc_list = [addr for addr in cc_line.split(',') if addr] + if GMOCK_GROUP not in cc_list: + cc_list.append(GMOCK_GROUP) + upload_py_argv.append(CC_FLAG + ','.join(cc_list)) + else: + upload_py_argv.append(arg) + + if not found_cc_flag: + upload_py_argv.append(CC_FLAG + GMOCK_GROUP) + + # Invokes upload.py with the modified command line flags. + os.execv(upload_py_path, upload_py_argv) + + +if __name__ == '__main__': + main() -- cgit v1.2.3 From 7a13fee2f01e4d052f520018f985da98790deb3d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 13 Feb 2009 19:00:22 +0000 Subject: Removes upload*.py from the release package, as they are useless without an SVN checkout. --- Makefile.am | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index bc06f612..4a5a3fd6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -173,11 +173,6 @@ EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \ include/gmock/gmock-generated-nice-strict.h.pump \ include/gmock/internal/gmock-generated-internal-utils.h.pump -# Scripts for uploading a patch for review. -EXTRA_DIST += \ - scripts/upload.py \ - scripts/upload_gmock.py - # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ scripts/generator/COPYING \ -- cgit v1.2.3 From e0d051ea64dd5f32d5b6af9831747d1acb2a9c40 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 19 Feb 2009 00:33:37 +0000 Subject: Makes sure all internal macros are named GMOCK_*_. No functionality is changed. --- include/gmock/gmock-actions.h | 53 +- include/gmock/gmock-generated-actions.h | 74 +-- include/gmock/gmock-generated-actions.h.pump | 8 +- include/gmock/gmock-generated-function-mockers.h | 548 ++++++++++----------- .../gmock/gmock-generated-function-mockers.h.pump | 44 +- include/gmock/gmock-generated-matchers.h | 38 +- include/gmock/gmock-generated-matchers.h.pump | 11 +- include/gmock/gmock-matchers.h | 48 +- include/gmock/gmock-spec-builders.h | 10 +- include/gmock/gmock.h | 2 +- include/gmock/internal/gmock-internal-utils.h | 18 +- include/gmock/internal/gmock-port.h | 29 +- src/gmock.cc | 12 +- test/gmock-internal-utils_test.cc | 25 +- 14 files changed, 470 insertions(+), 450 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 95e075d2..7aa5274c 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -100,7 +100,7 @@ class BuiltInDefaultValue { // The following specializations define the default values for // specific types we care about. -#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(type, value) \ +#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ template <> \ class BuiltInDefaultValue { \ public: \ @@ -108,17 +108,17 @@ class BuiltInDefaultValue { static type Get() { return value; } \ } -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(void, ); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT #if GTEST_HAS_GLOBAL_STRING -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(::string, ""); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, ""); #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_STD_STRING -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(::std::string, ""); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); #endif // GTEST_HAS_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'); +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'); // signed wchar_t and unsigned wchar_t are NOT in the C++ standard. // Using them is a bad practice and not portable. So don't use them. @@ -146,21 +146,21 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(char, '\0'); // that type is the same as unsigned int for gcc, and invalid for // MSVC. #if defined(__GNUC__) || defined(_NATIVE_WCHAR_T_DEFINED) -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE(wchar_t, 0U); // NOLINT +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); +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 +#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ } // namespace internal @@ -460,8 +460,9 @@ class ReturnAction { // 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; - GMOCK_COMPILE_ASSERT(!internal::is_reference::value, - use_ReturnRef_instead_of_Return_to_return_a_reference); + GMOCK_COMPILE_ASSERT_( + !internal::is_reference::value, + use_ReturnRef_instead_of_Return_to_return_a_reference); return Action(new Impl(value_)); } private: @@ -489,8 +490,8 @@ class ReturnNullAction { // Allows ReturnNull() to be used in any pointer-returning function. template static Result Perform(const ArgumentTuple&) { - GMOCK_COMPILE_ASSERT(internal::is_pointer::value, - ReturnNull_can_be_used_to_return_a_pointer_only); + GMOCK_COMPILE_ASSERT_(internal::is_pointer::value, + ReturnNull_can_be_used_to_return_a_pointer_only); return NULL; } }; @@ -522,8 +523,8 @@ class ReturnRefAction { // 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. - GMOCK_COMPILE_ASSERT(internal::is_reference::value, - use_Return_instead_of_ReturnRef_to_return_a_value); + GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + use_Return_instead_of_ReturnRef_to_return_a_value); return Action(new Impl(ref_)); } private: diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index b67fa982..64475910 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -703,7 +703,7 @@ class InvokeArgumentAction10 { // 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) \ +#define GMOCK_FIELD_(Tuple, N) \ typename ::std::tr1::tuple_element::type // SelectArgs::type is the @@ -728,12 +728,12 @@ 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 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) { using ::std::tr1::get; @@ -759,7 +759,7 @@ template class SelectArgs { public: - typedef Result type(GMOCK_FIELD(ArgumentTuple, k1)); + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { using ::std::tr1::get; @@ -771,8 +771,8 @@ template class SelectArgs { public: - typedef Result type(GMOCK_FIELD(ArgumentTuple, k1), - GMOCK_FIELD(ArgumentTuple, k2)); + typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), + GMOCK_FIELD_(ArgumentTuple, k2)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { using ::std::tr1::get; @@ -784,8 +784,8 @@ template class SelectArgs { public: - typedef Result type(GMOCK_FIELD(ArgumentTuple, k1), - GMOCK_FIELD(ArgumentTuple, k2), GMOCK_FIELD(ArgumentTuple, k3)); + 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) { using ::std::tr1::get; @@ -798,9 +798,9 @@ template { public: - typedef Result type(GMOCK_FIELD(ArgumentTuple, k1), - GMOCK_FIELD(ArgumentTuple, k2), GMOCK_FIELD(ArgumentTuple, k3), - GMOCK_FIELD(ArgumentTuple, k4)); + 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) { using ::std::tr1::get; @@ -814,9 +814,9 @@ template { 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 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) { using ::std::tr1::get; @@ -830,10 +830,10 @@ template { 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 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) { using ::std::tr1::get; @@ -847,10 +847,10 @@ template { 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 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) { using ::std::tr1::get; @@ -864,11 +864,11 @@ template { 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 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) { using ::std::tr1::get; @@ -883,11 +883,11 @@ template { 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 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) { using ::std::tr1::get; @@ -897,7 +897,7 @@ class SelectArgs::type $range i 1..n @@ -296,7 +296,7 @@ $range i 1..n template class SelectArgs { public: - typedef Result type($for i, [[GMOCK_FIELD(ArgumentTuple, k$i)]]); + typedef Result type($for i, [[GMOCK_FIELD_(ArgumentTuple, k$i)]]); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { using ::std::tr1::get; @@ -312,7 +312,7 @@ template class SelectArgs { public: - typedef Result type($for j1, [[GMOCK_FIELD(ArgumentTuple, k$j1)]]); + typedef Result type($for j1, [[GMOCK_FIELD_(ArgumentTuple, k$j1)]]); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { using ::std::tr1::get; @@ -322,7 +322,7 @@ class SelectArgs::Result +#define GMOCK_RESULT_(tn, F) tn ::testing::internal::Function::Result // The type of argument N of function type F. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_ARG(tn, F, N) tn ::testing::internal::Function::Argument##N +#define GMOCK_ARG_(tn, F, N) tn ::testing::internal::Function::Argument##N // The matcher type for argument N of function type F. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MATCHER(tn, F, N) const ::testing::Matcher& +#define GMOCK_MATCHER_(tn, F, N) const ::testing::Matcher& // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MOCKER(Method) GMOCK_CONCAT_TOKEN(gmock_##Method##_, __LINE__) +#define GMOCK_MOCKER_(Method) GMOCK_CONCAT_TOKEN_(gmock_##Method##_, __LINE__) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD0(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method() constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD0_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method() constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 0, \ this_method_does_not_take_0_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(); \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(); \ } \ ::testing::MockSpec& \ gmock_##Method() constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(); \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD1(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD1_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 1, \ this_method_does_not_take_1_argument); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1); \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1); \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD2(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD2_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 2, \ this_method_does_not_take_2_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2); \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD3(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD3_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 3, \ this_method_does_not_take_3_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3); \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD4(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD4_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 4, \ this_method_does_not_take_4_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD5(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4, \ - GMOCK_ARG(tn, F, 5) gmock_a5) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD5_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4, \ + GMOCK_ARG_(tn, F, 5) gmock_a5) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 5, \ this_method_does_not_take_5_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4, gmock_a5); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER(tn, F, 5) gmock_a5) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER_(tn, F, 5) gmock_a5) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD6(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4, \ - GMOCK_ARG(tn, F, 5) gmock_a5, \ - GMOCK_ARG(tn, F, 6) gmock_a6) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD6_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4, \ + GMOCK_ARG_(tn, F, 5) gmock_a5, \ + GMOCK_ARG_(tn, F, 6) gmock_a6) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 6, \ this_method_does_not_take_6_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4, gmock_a5, gmock_a6); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER(tn, F, 6) gmock_a6) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER_(tn, F, 6) gmock_a6) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD7(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4, \ - GMOCK_ARG(tn, F, 5) gmock_a5, \ - GMOCK_ARG(tn, F, 6) gmock_a6, \ - GMOCK_ARG(tn, F, 7) gmock_a7) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD7_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4, \ + GMOCK_ARG_(tn, F, 5) gmock_a5, \ + GMOCK_ARG_(tn, F, 6) gmock_a6, \ + GMOCK_ARG_(tn, F, 7) gmock_a7) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 7, \ this_method_does_not_take_7_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER(tn, F, 7) gmock_a7) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER_(tn, F, 7) gmock_a7) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD8(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4, \ - GMOCK_ARG(tn, F, 5) gmock_a5, \ - GMOCK_ARG(tn, F, 6) gmock_a6, \ - GMOCK_ARG(tn, F, 7) gmock_a7, \ - GMOCK_ARG(tn, F, 8) gmock_a8) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD8_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4, \ + GMOCK_ARG_(tn, F, 5) gmock_a5, \ + GMOCK_ARG_(tn, F, 6) gmock_a6, \ + GMOCK_ARG_(tn, F, 7) gmock_a7, \ + GMOCK_ARG_(tn, F, 8) gmock_a8) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 8, \ this_method_does_not_take_8_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER(tn, F, 7) gmock_a7, \ - GMOCK_MATCHER(tn, F, 8) gmock_a8) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ + GMOCK_MATCHER_(tn, F, 8) gmock_a8) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD9(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4, \ - GMOCK_ARG(tn, F, 5) gmock_a5, \ - GMOCK_ARG(tn, F, 6) gmock_a6, \ - GMOCK_ARG(tn, F, 7) gmock_a7, \ - GMOCK_ARG(tn, F, 8) gmock_a8, \ - GMOCK_ARG(tn, F, 9) gmock_a9) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD9_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4, \ + GMOCK_ARG_(tn, F, 5) gmock_a5, \ + GMOCK_ARG_(tn, F, 6) gmock_a6, \ + GMOCK_ARG_(tn, F, 7) gmock_a7, \ + GMOCK_ARG_(tn, F, 8) gmock_a8, \ + GMOCK_ARG_(tn, F, 9) gmock_a9) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 9, \ this_method_does_not_take_9_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER(tn, F, 7) gmock_a7, \ - GMOCK_MATCHER(tn, F, 8) gmock_a8, \ - GMOCK_MATCHER(tn, F, 9) gmock_a9) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ + GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ + GMOCK_MATCHER_(tn, F, 9) gmock_a9) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ gmock_a9); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD10(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method(GMOCK_ARG(tn, F, 1) gmock_a1, \ - GMOCK_ARG(tn, F, 2) gmock_a2, \ - GMOCK_ARG(tn, F, 3) gmock_a3, \ - GMOCK_ARG(tn, F, 4) gmock_a4, \ - GMOCK_ARG(tn, F, 5) gmock_a5, \ - GMOCK_ARG(tn, F, 6) gmock_a6, \ - GMOCK_ARG(tn, F, 7) gmock_a7, \ - GMOCK_ARG(tn, F, 8) gmock_a8, \ - GMOCK_ARG(tn, F, 9) gmock_a9, \ - GMOCK_ARG(tn, F, 10) gmock_a10) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD10_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ + GMOCK_ARG_(tn, F, 2) gmock_a2, \ + GMOCK_ARG_(tn, F, 3) gmock_a3, \ + GMOCK_ARG_(tn, F, 4) gmock_a4, \ + GMOCK_ARG_(tn, F, 5) gmock_a5, \ + GMOCK_ARG_(tn, F, 6) gmock_a6, \ + GMOCK_ARG_(tn, F, 7) gmock_a7, \ + GMOCK_ARG_(tn, F, 8) gmock_a8, \ + GMOCK_ARG_(tn, F, 9) gmock_a9, \ + GMOCK_ARG_(tn, F, 10) gmock_a10) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 10, \ this_method_does_not_take_10_arguments); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ gmock_a10); \ } \ ::testing::MockSpec& \ - gmock_##Method(GMOCK_MATCHER(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER(tn, F, 7) gmock_a7, \ - GMOCK_MATCHER(tn, F, 8) gmock_a8, \ - GMOCK_MATCHER(tn, F, 9) gmock_a9, \ - GMOCK_MATCHER(tn, F, 10) gmock_a10) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ + gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ + GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ + GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ + GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ + GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ + GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ + GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ + GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ + GMOCK_MATCHER_(tn, F, 9) gmock_a9, \ + GMOCK_MATCHER_(tn, F, 10) gmock_a10) constness { \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ gmock_a10); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) - -#define MOCK_METHOD0(m, F) GMOCK_METHOD0(, , , m, F) -#define MOCK_METHOD1(m, F) GMOCK_METHOD1(, , , m, F) -#define MOCK_METHOD2(m, F) GMOCK_METHOD2(, , , m, F) -#define MOCK_METHOD3(m, F) GMOCK_METHOD3(, , , m, F) -#define MOCK_METHOD4(m, F) GMOCK_METHOD4(, , , m, F) -#define MOCK_METHOD5(m, F) GMOCK_METHOD5(, , , m, F) -#define MOCK_METHOD6(m, F) GMOCK_METHOD6(, , , m, F) -#define MOCK_METHOD7(m, F) GMOCK_METHOD7(, , , m, F) -#define MOCK_METHOD8(m, F) GMOCK_METHOD8(, , , m, F) -#define MOCK_METHOD9(m, F) GMOCK_METHOD9(, , , m, F) -#define MOCK_METHOD10(m, F) GMOCK_METHOD10(, , , m, F) - -#define MOCK_CONST_METHOD0(m, F) GMOCK_METHOD0(, const, , m, F) -#define MOCK_CONST_METHOD1(m, F) GMOCK_METHOD1(, const, , m, F) -#define MOCK_CONST_METHOD2(m, F) GMOCK_METHOD2(, const, , m, F) -#define MOCK_CONST_METHOD3(m, F) GMOCK_METHOD3(, const, , m, F) -#define MOCK_CONST_METHOD4(m, F) GMOCK_METHOD4(, const, , m, F) -#define MOCK_CONST_METHOD5(m, F) GMOCK_METHOD5(, const, , m, F) -#define MOCK_CONST_METHOD6(m, F) GMOCK_METHOD6(, const, , m, F) -#define MOCK_CONST_METHOD7(m, F) GMOCK_METHOD7(, const, , m, F) -#define MOCK_CONST_METHOD8(m, F) GMOCK_METHOD8(, const, , m, F) -#define MOCK_CONST_METHOD9(m, F) GMOCK_METHOD9(, const, , m, F) -#define MOCK_CONST_METHOD10(m, F) GMOCK_METHOD10(, const, , m, F) - -#define MOCK_METHOD0_T(m, F) GMOCK_METHOD0(typename, , , m, F) -#define MOCK_METHOD1_T(m, F) GMOCK_METHOD1(typename, , , m, F) -#define MOCK_METHOD2_T(m, F) GMOCK_METHOD2(typename, , , m, F) -#define MOCK_METHOD3_T(m, F) GMOCK_METHOD3(typename, , , m, F) -#define MOCK_METHOD4_T(m, F) GMOCK_METHOD4(typename, , , m, F) -#define MOCK_METHOD5_T(m, F) GMOCK_METHOD5(typename, , , m, F) -#define MOCK_METHOD6_T(m, F) GMOCK_METHOD6(typename, , , m, F) -#define MOCK_METHOD7_T(m, F) GMOCK_METHOD7(typename, , , m, F) -#define MOCK_METHOD8_T(m, F) GMOCK_METHOD8(typename, , , m, F) -#define MOCK_METHOD9_T(m, F) GMOCK_METHOD9(typename, , , m, F) -#define MOCK_METHOD10_T(m, F) GMOCK_METHOD10(typename, , , m, F) - -#define MOCK_CONST_METHOD0_T(m, F) GMOCK_METHOD0(typename, const, , m, F) -#define MOCK_CONST_METHOD1_T(m, F) GMOCK_METHOD1(typename, const, , m, F) -#define MOCK_CONST_METHOD2_T(m, F) GMOCK_METHOD2(typename, const, , m, F) -#define MOCK_CONST_METHOD3_T(m, F) GMOCK_METHOD3(typename, const, , m, F) -#define MOCK_CONST_METHOD4_T(m, F) GMOCK_METHOD4(typename, const, , m, F) -#define MOCK_CONST_METHOD5_T(m, F) GMOCK_METHOD5(typename, const, , m, F) -#define MOCK_CONST_METHOD6_T(m, F) GMOCK_METHOD6(typename, const, , m, F) -#define MOCK_CONST_METHOD7_T(m, F) GMOCK_METHOD7(typename, const, , m, F) -#define MOCK_CONST_METHOD8_T(m, F) GMOCK_METHOD8(typename, const, , m, F) -#define MOCK_CONST_METHOD9_T(m, F) GMOCK_METHOD9(typename, const, , m, F) -#define MOCK_CONST_METHOD10_T(m, F) GMOCK_METHOD10(typename, const, , m, F) - -#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD0(, , ct, m, F) -#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD1(, , ct, m, F) -#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD2(, , ct, m, F) -#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD3(, , ct, m, F) -#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD4(, , ct, m, F) -#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD5(, , ct, m, F) -#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD6(, , ct, m, F) -#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD7(, , ct, m, F) -#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD8(, , ct, m, F) -#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD9(, , ct, m, F) -#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD10(, , ct, m, F) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + +#define MOCK_METHOD0(m, F) GMOCK_METHOD0_(, , , m, F) +#define MOCK_METHOD1(m, F) GMOCK_METHOD1_(, , , m, F) +#define MOCK_METHOD2(m, F) GMOCK_METHOD2_(, , , m, F) +#define MOCK_METHOD3(m, F) GMOCK_METHOD3_(, , , m, F) +#define MOCK_METHOD4(m, F) GMOCK_METHOD4_(, , , m, F) +#define MOCK_METHOD5(m, F) GMOCK_METHOD5_(, , , m, F) +#define MOCK_METHOD6(m, F) GMOCK_METHOD6_(, , , m, F) +#define MOCK_METHOD7(m, F) GMOCK_METHOD7_(, , , m, F) +#define MOCK_METHOD8(m, F) GMOCK_METHOD8_(, , , m, F) +#define MOCK_METHOD9(m, F) GMOCK_METHOD9_(, , , m, F) +#define MOCK_METHOD10(m, F) GMOCK_METHOD10_(, , , m, F) + +#define MOCK_CONST_METHOD0(m, F) GMOCK_METHOD0_(, const, , m, F) +#define MOCK_CONST_METHOD1(m, F) GMOCK_METHOD1_(, const, , m, F) +#define MOCK_CONST_METHOD2(m, F) GMOCK_METHOD2_(, const, , m, F) +#define MOCK_CONST_METHOD3(m, F) GMOCK_METHOD3_(, const, , m, F) +#define MOCK_CONST_METHOD4(m, F) GMOCK_METHOD4_(, const, , m, F) +#define MOCK_CONST_METHOD5(m, F) GMOCK_METHOD5_(, const, , m, F) +#define MOCK_CONST_METHOD6(m, F) GMOCK_METHOD6_(, const, , m, F) +#define MOCK_CONST_METHOD7(m, F) GMOCK_METHOD7_(, const, , m, F) +#define MOCK_CONST_METHOD8(m, F) GMOCK_METHOD8_(, const, , m, F) +#define MOCK_CONST_METHOD9(m, F) GMOCK_METHOD9_(, const, , m, F) +#define MOCK_CONST_METHOD10(m, F) GMOCK_METHOD10_(, const, , m, F) + +#define MOCK_METHOD0_T(m, F) GMOCK_METHOD0_(typename, , , m, F) +#define MOCK_METHOD1_T(m, F) GMOCK_METHOD1_(typename, , , m, F) +#define MOCK_METHOD2_T(m, F) GMOCK_METHOD2_(typename, , , m, F) +#define MOCK_METHOD3_T(m, F) GMOCK_METHOD3_(typename, , , m, F) +#define MOCK_METHOD4_T(m, F) GMOCK_METHOD4_(typename, , , m, F) +#define MOCK_METHOD5_T(m, F) GMOCK_METHOD5_(typename, , , m, F) +#define MOCK_METHOD6_T(m, F) GMOCK_METHOD6_(typename, , , m, F) +#define MOCK_METHOD7_T(m, F) GMOCK_METHOD7_(typename, , , m, F) +#define MOCK_METHOD8_T(m, F) GMOCK_METHOD8_(typename, , , m, F) +#define MOCK_METHOD9_T(m, F) GMOCK_METHOD9_(typename, , , m, F) +#define MOCK_METHOD10_T(m, F) GMOCK_METHOD10_(typename, , , m, F) + +#define MOCK_CONST_METHOD0_T(m, F) GMOCK_METHOD0_(typename, const, , m, F) +#define MOCK_CONST_METHOD1_T(m, F) GMOCK_METHOD1_(typename, const, , m, F) +#define MOCK_CONST_METHOD2_T(m, F) GMOCK_METHOD2_(typename, const, , m, F) +#define MOCK_CONST_METHOD3_T(m, F) GMOCK_METHOD3_(typename, const, , m, F) +#define MOCK_CONST_METHOD4_T(m, F) GMOCK_METHOD4_(typename, const, , m, F) +#define MOCK_CONST_METHOD5_T(m, F) GMOCK_METHOD5_(typename, const, , m, F) +#define MOCK_CONST_METHOD6_T(m, F) GMOCK_METHOD6_(typename, const, , m, F) +#define MOCK_CONST_METHOD7_T(m, F) GMOCK_METHOD7_(typename, const, , m, F) +#define MOCK_CONST_METHOD8_T(m, F) GMOCK_METHOD8_(typename, const, , m, F) +#define MOCK_CONST_METHOD9_T(m, F) GMOCK_METHOD9_(typename, const, , m, F) +#define MOCK_CONST_METHOD10_T(m, F) GMOCK_METHOD10_(typename, const, , m, F) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD0_(, , ct, m, F) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD1_(, , ct, m, F) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD2_(, , ct, m, F) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD3_(, , ct, m, F) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD4_(, , ct, m, F) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD5_(, , ct, m, F) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD6_(, , ct, m, F) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD7_(, , ct, m, F) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD8_(, , ct, m, F) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD9_(, , ct, m, F) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD10_(, , ct, m, F) #define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD0(, const, ct, m, F) + GMOCK_METHOD0_(, const, ct, m, F) #define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD1(, const, ct, m, F) + GMOCK_METHOD1_(, const, ct, m, F) #define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD2(, const, ct, m, F) + GMOCK_METHOD2_(, const, ct, m, F) #define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD3(, const, ct, m, F) + GMOCK_METHOD3_(, const, ct, m, F) #define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD4(, const, ct, m, F) + GMOCK_METHOD4_(, const, ct, m, F) #define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD5(, const, ct, m, F) + GMOCK_METHOD5_(, const, ct, m, F) #define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD6(, const, ct, m, F) + GMOCK_METHOD6_(, const, ct, m, F) #define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD7(, const, ct, m, F) + GMOCK_METHOD7_(, const, ct, m, F) #define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD8(, const, ct, m, F) + GMOCK_METHOD8_(, const, ct, m, F) #define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD9(, const, ct, m, F) + GMOCK_METHOD9_(, const, ct, m, F) #define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD10(, const, ct, m, F) + GMOCK_METHOD10_(, const, ct, m, F) #define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD0(typename, , ct, m, F) + GMOCK_METHOD0_(typename, , ct, m, F) #define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD1(typename, , ct, m, F) + GMOCK_METHOD1_(typename, , ct, m, F) #define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD2(typename, , ct, m, F) + GMOCK_METHOD2_(typename, , ct, m, F) #define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD3(typename, , ct, m, F) + GMOCK_METHOD3_(typename, , ct, m, F) #define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD4(typename, , ct, m, F) + GMOCK_METHOD4_(typename, , ct, m, F) #define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD5(typename, , ct, m, F) + GMOCK_METHOD5_(typename, , ct, m, F) #define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD6(typename, , ct, m, F) + GMOCK_METHOD6_(typename, , ct, m, F) #define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD7(typename, , ct, m, F) + GMOCK_METHOD7_(typename, , ct, m, F) #define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD8(typename, , ct, m, F) + GMOCK_METHOD8_(typename, , ct, m, F) #define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD9(typename, , ct, m, F) + GMOCK_METHOD9_(typename, , ct, m, F) #define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD10(typename, , ct, m, F) + GMOCK_METHOD10_(typename, , ct, m, F) #define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD0(typename, const, ct, m, F) + GMOCK_METHOD0_(typename, const, ct, m, F) #define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD1(typename, const, ct, m, F) + GMOCK_METHOD1_(typename, const, ct, m, F) #define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD2(typename, const, ct, m, F) + GMOCK_METHOD2_(typename, const, ct, m, F) #define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD3(typename, const, ct, m, F) + GMOCK_METHOD3_(typename, const, ct, m, F) #define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD4(typename, const, ct, m, F) + GMOCK_METHOD4_(typename, const, ct, m, F) #define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD5(typename, const, ct, m, F) + GMOCK_METHOD5_(typename, const, ct, m, F) #define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD6(typename, const, ct, m, F) + GMOCK_METHOD6_(typename, const, ct, m, F) #define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD7(typename, const, ct, m, F) + GMOCK_METHOD7_(typename, const, ct, m, F) #define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD8(typename, const, ct, m, F) + GMOCK_METHOD8_(typename, const, ct, m, F) #define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD9(typename, const, ct, m, F) + GMOCK_METHOD9_(typename, const, ct, m, F) #define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD10(typename, const, ct, m, F) + GMOCK_METHOD10_(typename, const, ct, m, F) } // namespace testing diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 4f7fdc16..a9abc973 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -106,92 +106,94 @@ using internal::FunctionMocker; // The result type of function type F. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_RESULT(tn, F) tn ::testing::internal::Function::Result +#define GMOCK_RESULT_(tn, F) tn ::testing::internal::Function::Result // The type of argument N of function type F. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_ARG(tn, F, N) tn ::testing::internal::Function::Argument##N +#define GMOCK_ARG_(tn, F, N) tn ::testing::internal::Function::Argument##N // The matcher type for argument N of function type F. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MATCHER(tn, F, N) const ::testing::Matcher& +#define GMOCK_MATCHER_(tn, F, N) const ::testing::Matcher& // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MOCKER(Method) GMOCK_CONCAT_TOKEN(gmock_##Method##_, __LINE__) +#define GMOCK_MOCKER_(Method) GMOCK_CONCAT_TOKEN_(gmock_##Method##_, __LINE__) $for i [[ $range j 1..i $var arg_as = [[$for j, \ - [[GMOCK_ARG(tn, F, $j) gmock_a$j]]]] + [[GMOCK_ARG_(tn, F, $j) gmock_a$j]]]] $var as = [[$for j, [[gmock_a$j]]]] $var matcher_as = [[$for j, \ - [[GMOCK_MATCHER(tn, F, $j) gmock_a$j]]]] + [[GMOCK_MATCHER_(tn, F, $j) gmock_a$j]]]] // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD$i(tn, constness, ct, Method, F) \ - GMOCK_RESULT(tn, F) ct Method($arg_as) constness { \ - GMOCK_COMPILE_ASSERT(::std::tr1::tuple_size< \ +#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, F) \ + GMOCK_RESULT_(tn, F) ct Method($arg_as) constness { \ + GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == $i, \ this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ - GMOCK_MOCKER(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER(Method).Invoke($as); \ + GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(Method).Invoke($as); \ } \ ::testing::MockSpec& \ gmock_##Method($matcher_as) constness { \ - return GMOCK_MOCKER(Method).RegisterOwner(this).With($as); \ + return GMOCK_MOCKER_(Method).RegisterOwner(this).With($as); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) ]] $for i [[ -#define MOCK_METHOD$i(m, F) GMOCK_METHOD$i(, , , m, F) +#define MOCK_METHOD$i(m, F) GMOCK_METHOD$i[[]]_(, , , m, F) ]] $for i [[ -#define MOCK_CONST_METHOD$i(m, F) GMOCK_METHOD$i(, const, , m, F) +#define MOCK_CONST_METHOD$i(m, F) GMOCK_METHOD$i[[]]_(, const, , m, F) ]] $for i [[ -#define MOCK_METHOD$i[[]]_T(m, F) GMOCK_METHOD$i(typename, , , m, F) +#define MOCK_METHOD$i[[]]_T(m, F) GMOCK_METHOD$i[[]]_(typename, , , m, F) ]] $for i [[ -#define MOCK_CONST_METHOD$i[[]]_T(m, F) GMOCK_METHOD$i(typename, const, , m, F) +#define MOCK_CONST_METHOD$i[[]]_T(m, F) [[]] +GMOCK_METHOD$i[[]]_(typename, const, , m, F) ]] $for i [[ -#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD$i(, , ct, m, F) +#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, F) [[]] +GMOCK_METHOD$i[[]]_(, , ct, m, F) ]] $for i [[ #define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD$i(, const, ct, m, F) + GMOCK_METHOD$i[[]]_(, const, ct, m, F) ]] $for i [[ #define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD$i(typename, , ct, m, F) + GMOCK_METHOD$i[[]]_(typename, , ct, m, F) ]] $for i [[ #define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD$i(typename, const, ct, m, F) + GMOCK_METHOD$i[[]]_(typename, const, ct, m, F) ]] diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index f8cbf49e..727109cd 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -56,7 +56,7 @@ inline void ValidateMatcherDescription(const char* description) { template class ElementsAreMatcherImpl : public MatcherInterface { public: - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename RawContainer::value_type Element; // Constructs the matcher from a sequence of element values or @@ -195,7 +195,8 @@ class ElementsAreMatcher0 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher* const matchers = NULL; @@ -210,7 +211,8 @@ class ElementsAreMatcher1 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -231,7 +233,8 @@ class ElementsAreMatcher2 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -255,7 +258,8 @@ class ElementsAreMatcher3 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -281,7 +285,8 @@ class ElementsAreMatcher4 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -309,7 +314,8 @@ class ElementsAreMatcher5 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -341,7 +347,8 @@ class ElementsAreMatcher6 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -375,7 +382,8 @@ class ElementsAreMatcher7 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -411,7 +419,8 @@ class ElementsAreMatcher8 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -450,7 +459,8 @@ class ElementsAreMatcher9 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -491,7 +501,8 @@ class ElementsAreMatcher10 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -532,7 +543,8 @@ class ElementsAreArrayMatcher { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 2a457aad..8fd79196 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -59,7 +59,7 @@ inline void ValidateMatcherDescription(const char* description) { template class ElementsAreMatcherImpl : public MatcherInterface { public: - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename RawContainer::value_type Element; // Constructs the matcher from a sequence of element values or @@ -198,7 +198,8 @@ class ElementsAreMatcher0 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher* const matchers = NULL; @@ -218,7 +219,8 @@ class ElementsAreMatcher$i { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; const Matcher matchers[] = { @@ -251,7 +253,8 @@ class ElementsAreArrayMatcher { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST(GMOCK_REMOVE_REFERENCE(Container)) RawContainer; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; typedef typename RawContainer::value_type Element; return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 9113d178..525128b9 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -377,7 +377,7 @@ class TuplePrefix { // isn't interesting to the user most of the time. The // matcher's ExplainMatchResultTo() method handles the case when // the address is interesting. - internal::UniversalPrinter:: + internal::UniversalPrinter:: Print(value, os); ExplainMatchResultAsNeededTo(matcher, value, os); *os << "\n"; @@ -412,9 +412,9 @@ bool TupleMatches(const MatcherTuple& matcher_tuple, using ::std::tr1::tuple_size; // Makes sure that matcher_tuple and value_tuple have the same // number of fields. - GMOCK_COMPILE_ASSERT(tuple_size::value == - tuple_size::value, - matcher_and_value_have_different_numbers_of_fields); + GMOCK_COMPILE_ASSERT_(tuple_size::value == + tuple_size::value, + matcher_and_value_have_different_numbers_of_fields); return TuplePrefix::value>:: Matches(matcher_tuple, value_tuple); } @@ -528,7 +528,7 @@ class AnythingMatcher { // // The following template definition assumes that the Rhs parameter is // a "bare" type (i.e. neither 'const T' nor 'T&'). -#define GMOCK_IMPLEMENT_COMPARISON_MATCHER(name, op, relation) \ +#define GMOCK_IMPLEMENT_COMPARISON_MATCHER_(name, op, relation) \ template class name##Matcher { \ public: \ explicit name##Matcher(const Rhs& rhs) : rhs_(rhs) {} \ @@ -558,14 +558,14 @@ class AnythingMatcher { // Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v) // respectively. -GMOCK_IMPLEMENT_COMPARISON_MATCHER(Eq, ==, "equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER(Ge, >=, "greater than or equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER(Gt, >, "greater than"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER(Le, <=, "less than or equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER(Lt, <, "less than"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER(Ne, !=, "not equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Eq, ==, "equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ge, >=, "greater than or equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Gt, >, "greater than"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Le, <=, "less than or equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Lt, <, "less than"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "not equal to"); -#undef GMOCK_IMPLEMENT_COMPARISON_MATCHER +#undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_ // Implements the polymorphic NotNull() matcher, which matches any // pointer that is not NULL. @@ -893,7 +893,7 @@ class MatchesRegexMatcher { // // We define this as a macro in order to eliminate duplicated source // code. -#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER(name, op, relation) \ +#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \ class name##2Matcher { \ public: \ template \ @@ -917,14 +917,14 @@ class MatchesRegexMatcher { } // Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. -GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Eq, ==, "equal to"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Ge, >=, "greater than or equal to"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Gt, >, "greater than"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Le, <=, "less than or equal to"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Lt, <, "less than"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER(Ne, !=, "not equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==, "equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ge, >=, "greater than or equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Gt, >, "greater than"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Le, <=, "less than or equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Lt, <, "less than"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "not equal to"); -#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER +#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ // Implements the Not(m) matcher, which matches a value that doesn't // match matcher m. @@ -1364,8 +1364,8 @@ class PointeeMatcher { template class Impl : public MatcherInterface { public: - typedef typename PointeeOf::type Pointee; + typedef typename PointeeOf::type Pointee; explicit Impl(const InnerMatcher& matcher) : matcher_(MatcherCast(matcher)) {} @@ -1474,7 +1474,7 @@ class PropertyMatcher { // may cause double references and fail to compile. That's why we // need GMOCK_REFERENCE_TO_CONST, which works regardless of // PropertyType being a reference or not. - typedef GMOCK_REFERENCE_TO_CONST(PropertyType) RefToConstProperty; + typedef GMOCK_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty; PropertyMatcher(PropertyType (Class::*property)() const, const Matcher& matcher) @@ -1859,7 +1859,7 @@ inline PolymorphicMatcher< return MakePolymorphicMatcher( internal::PropertyMatcher( property, - MatcherCast(matcher))); + MatcherCast(matcher))); // The call to MatcherCast() is required for supporting inner // matchers of compatible types. For example, it allows // Property(&Foo::bar, m) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 0364b570..bd956f3d 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -378,7 +378,7 @@ class InSequence { bool sequence_created_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InSequence); // NOLINT -} GMOCK_ATTRIBUTE_UNUSED; +} GMOCK_ATTRIBUTE_UNUSED_; namespace internal { @@ -1562,13 +1562,13 @@ inline const T& Const(const T& x) { return x; } // of the method used in call is a result of macro expansion. // See CompilesWithMethodNameExpandedFromMacro tests in // internal/gmock-spec-builders_test.cc for more details. -#define ON_CALL_IMPL_(obj, call) \ +#define GMOCK_ON_CALL_IMPL_(obj, call) \ ((obj).gmock_##call).InternalDefaultActionSetAt(__FILE__, __LINE__, \ #obj, #call) -#define ON_CALL(obj, call) ON_CALL_IMPL_(obj, call) +#define ON_CALL(obj, call) GMOCK_ON_CALL_IMPL_(obj, call) -#define EXPECT_CALL_IMPL_(obj, call) \ +#define GMOCK_EXPECT_CALL_IMPL_(obj, call) \ ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call) -#define EXPECT_CALL(obj, call) EXPECT_CALL_IMPL_(obj, call) +#define EXPECT_CALL(obj, call) GMOCK_EXPECT_CALL_IMPL_(obj, call) #endif // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index 9c9cdd91..41d175f1 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -68,7 +68,7 @@ namespace testing { // Declares Google Mock flags that we want a user to use programmatically. -GMOCK_DECLARE_string(verbose); +GMOCK_DECLARE_string_(verbose); // Initializes Google Mock. This must be called before running the // tests. In particular, it parses the command line for the flags diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 9a74d546..b3d1a1d1 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -48,13 +48,13 @@ // Concatenates two pre-processor symbols; works for concatenating // built-in macros like __FILE__ and __LINE__. -#define GMOCK_CONCAT_TOKEN_IMPL(foo, bar) foo##bar -#define GMOCK_CONCAT_TOKEN(foo, bar) GMOCK_CONCAT_TOKEN_IMPL(foo, bar) +#define GMOCK_CONCAT_TOKEN_IMPL_(foo, bar) foo##bar +#define GMOCK_CONCAT_TOKEN_(foo, bar) GMOCK_CONCAT_TOKEN_IMPL_(foo, bar) #ifdef __GNUC__ -#define GMOCK_ATTRIBUTE_UNUSED __attribute__ ((unused)) +#define GMOCK_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else -#define GMOCK_ATTRIBUTE_UNUSED +#define GMOCK_ATTRIBUTE_UNUSED_ #endif // __GNUC__ class ProtocolMessage; @@ -88,7 +88,7 @@ struct RemoveReference { typedef T type; }; // NOLINT // A handy wrapper around RemoveReference that works when the argument // T depends on template parameters. -#define GMOCK_REMOVE_REFERENCE(T) \ +#define GMOCK_REMOVE_REFERENCE_(T) \ typename ::testing::internal::RemoveReference::type // Removes const from a type if it is a const type, otherwise leaves @@ -101,7 +101,7 @@ struct RemoveConst { typedef T type; }; // NOLINT // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. -#define GMOCK_REMOVE_CONST(T) \ +#define GMOCK_REMOVE_CONST_(T) \ typename ::testing::internal::RemoveConst::type // Adds reference to a type if it is not a reference type, @@ -114,7 +114,7 @@ struct AddReference { typedef T& type; }; // NOLINT // A handy wrapper around AddReference that works when the argument T // depends on template parameters. -#define GMOCK_ADD_REFERENCE(T) \ +#define GMOCK_ADD_REFERENCE_(T) \ typename ::testing::internal::AddReference::type // Adds a reference to const on top of T as necessary. For example, @@ -126,8 +126,8 @@ struct AddReference { typedef T& type; }; // NOLINT // const char& ==> const char& // // The argument T must depend on some template parameters. -#define GMOCK_REFERENCE_TO_CONST(T) \ - GMOCK_ADD_REFERENCE(const GMOCK_REMOVE_REFERENCE(T)) +#define GMOCK_REFERENCE_TO_CONST_(T) \ + GMOCK_ADD_REFERENCE_(const GMOCK_REMOVE_REFERENCE_(T)) // PointeeOf::type is the type of a value pointed to by a // Pointer, which can be either a smart pointer or a raw pointer. The diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index a39f77bc..45b95cde 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -183,18 +183,18 @@ template struct CompileAssert { }; -#define GMOCK_COMPILE_ASSERT(expr, msg) \ +#define GMOCK_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(bool(expr))> \ msg[bool(expr) ? 1 : -1] -// Implementation details of GMOCK_COMPILE_ASSERT: +// Implementation details of GMOCK_COMPILE_ASSERT_: // -// - GMOCK_COMPILE_ASSERT works by defining an array type that has -1 +// - GMOCK_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // -// #define GMOCK_COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// #define GMOCK_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part @@ -202,8 +202,8 @@ struct CompileAssert { // following code with the simple definition: // // int foo; -// GMOCK_COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. +// GMOCK_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be @@ -216,7 +216,7 @@ struct CompileAssert { // // instead, these compilers will refuse to compile // -// GMOCK_COMPILE_ASSERT(5 > 0, some_message); +// GMOCK_COMPILE_ASSERT_(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) @@ -293,22 +293,23 @@ class GMockCheckProvider { } // namespace internal } // namespace testing -// Macro for referencing flags. +// Macro for referencing flags. This is public as we want the user to +// use this syntax to reference Google Mock flags. #define GMOCK_FLAG(name) FLAGS_gmock_##name // Macros for declaring flags. -#define GMOCK_DECLARE_bool(name) extern bool GMOCK_FLAG(name) -#define GMOCK_DECLARE_int32(name) \ +#define GMOCK_DECLARE_bool_(name) extern bool GMOCK_FLAG(name) +#define GMOCK_DECLARE_int32_(name) \ extern ::testing::internal::Int32 GMOCK_FLAG(name) -#define GMOCK_DECLARE_string(name) \ +#define GMOCK_DECLARE_string_(name) \ extern ::testing::internal::String GMOCK_FLAG(name) // Macros for defining flags. -#define GMOCK_DEFINE_bool(name, default_val, doc) \ +#define GMOCK_DEFINE_bool_(name, default_val, doc) \ bool GMOCK_FLAG(name) = (default_val) -#define GMOCK_DEFINE_int32(name, default_val, doc) \ +#define GMOCK_DEFINE_int32_(name, default_val, doc) \ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val) -#define GMOCK_DEFINE_string(name, default_val, doc) \ +#define GMOCK_DEFINE_string_(name, default_val, doc) \ ::testing::internal::String GMOCK_FLAG(name) = (default_val) #endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ diff --git a/src/gmock.cc b/src/gmock.cc index b2f3d59d..c017917d 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -34,12 +34,12 @@ namespace testing { -GMOCK_DEFINE_string(verbose, internal::kWarningVerbosity, - "Controls how verbose Google Mock's output is." - " Valid values:\n" - " info - prints all messages.\n" - " warning - prints warnings and errors.\n" - " error - prints errors only."); +GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity, + "Controls how verbose Google Mock's output is." + " Valid values:\n" + " info - prints all messages.\n" + " warning - prints warnings and errors.\n" + " error - prints errors only."); namespace internal { diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 2ea76b0e..6503ffb2 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -103,11 +103,11 @@ TEST(RemoveReferenceTest, RemovesReference) { CompileAssertTypesEqual::type>(); } -// Tests GMOCK_REMOVE_REFERENCE. +// Tests GMOCK_REMOVE_REFERENCE_. template void TestGMockRemoveReference() { - CompileAssertTypesEqual(); + CompileAssertTypesEqual(); } TEST(RemoveReferenceTest, MacroVersion) { @@ -127,11 +127,11 @@ TEST(RemoveConstTest, RemovesConst) { CompileAssertTypesEqual::type>(); } -// Tests GMOCK_REMOVE_CONST. +// Tests GMOCK_REMOVE_CONST_. template void TestGMockRemoveConst() { - CompileAssertTypesEqual(); + CompileAssertTypesEqual(); } TEST(RemoveConstTest, MacroVersion) { @@ -152,11 +152,11 @@ TEST(AddReferenceTest, AddsReference) { CompileAssertTypesEqual::type>(); } -// Tests GMOCK_ADD_REFERENCE. +// Tests GMOCK_ADD_REFERENCE_. template void TestGMockAddReference() { - CompileAssertTypesEqual(); + CompileAssertTypesEqual(); } TEST(AddReferenceTest, MacroVersion) { @@ -164,11 +164,11 @@ TEST(AddReferenceTest, MacroVersion) { TestGMockAddReference(); } -// Tests GMOCK_REFERENCE_TO_CONST. +// Tests GMOCK_REFERENCE_TO_CONST_. template void TestGMockReferenceToConst() { - CompileAssertTypesEqual(); + CompileAssertTypesEqual(); } TEST(GMockReferenceToConstTest, Works) { @@ -207,8 +207,9 @@ class Derived : public Base {}; // Tests that ImplicitlyConvertible::value is a compile-time constant. TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { - GMOCK_COMPILE_ASSERT((ImplicitlyConvertible::value), const_true); - GMOCK_COMPILE_ASSERT((!ImplicitlyConvertible::value), const_false); + GMOCK_COMPILE_ASSERT_((ImplicitlyConvertible::value), const_true); + GMOCK_COMPILE_ASSERT_((!ImplicitlyConvertible::value), + const_false); } // Tests that ImplicitlyConvertible::value is true when T1 can @@ -233,8 +234,8 @@ TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { // Tests that IsAProtocolMessage::value is a compile-time constant. TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { - GMOCK_COMPILE_ASSERT(IsAProtocolMessage::value, const_true); - GMOCK_COMPILE_ASSERT(!IsAProtocolMessage::value, const_false); + GMOCK_COMPILE_ASSERT_(IsAProtocolMessage::value, const_true); + GMOCK_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); } // Tests that IsAProtocolMessage::value is true when T is -- cgit v1.2.3 From 4a5330d3d6e582248dbcf602f70048dc72cc8182 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 19 Feb 2009 00:36:44 +0000 Subject: Implements custom description string for MATCHER*. --- include/gmock/gmock-generated-matchers.h | 501 +++++++++++++++----------- include/gmock/gmock-generated-matchers.h.pump | 141 ++++++-- include/gmock/gmock-printers.h | 96 +++-- src/gmock-matchers.cc | 145 +++++++- test/gmock-generated-matchers_test.cc | 61 +++- test/gmock-matchers_test.cc | 314 ++++++++++++++++ test/gmock-printers_test.cc | 61 +++- 7 files changed, 1029 insertions(+), 290 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 727109cd..26c064b7 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -40,18 +40,11 @@ #include #include #include +#include namespace testing { namespace internal { -// Generates a non-fatal failure iff 'description' is not a valid -// matcher description. -inline void ValidateMatcherDescription(const char* description) { - EXPECT_STREQ("", description) - << "The description string in a MATCHER*() macro must be \"\" " - "at this moment. We will implement custom description string soon."; -} - // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -674,10 +667,18 @@ ElementsAreArray(const T (&array)[N]) { // // will define a matcher with the given name that executes the // statements, which must return a bool to indicate if the match -// succeeds. For now, the description_string must be "", but we'll -// allow other values soon. Inside the statements, you can refer to -// the value being matched by 'arg', and refer to its type by -// 'arg_type'. For example: +// 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; } // @@ -740,6 +741,38 @@ ElementsAreArray(const T (&array)[N]) { // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to // support multi-parameter matchers. // +// When defining a parameterized matcher, you can use Python-style +// interpolations in the description string to refer to the parameter +// values. We support the following syntax 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) { ... } @@ -796,25 +829,77 @@ ElementsAreArray(const T (&array)[N]) { // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. +namespace testing { +namespace internal { + +// Constants denoting interpolations in a matcher description string. +const int kTupleInterpolation = -1; // "%(*)s" +const int kPercentInterpolation = -2; // "%%" +const int kInvalidInterpolation = -3; // "%" followed by invalid text + +// Records the location and content of an interpolation. +struct Interpolation { + Interpolation(const char* start, const char* end, int param) + : start_pos(start), end_pos(end), param_index(param) {} + + // Points to the start of the interpolation (the '%' character). + const char* start_pos; + // Points to the first character after the interpolation. + const char* end_pos; + // 0-based index of the interpolated matcher parameter; + // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%". + int param_index; +}; + +typedef ::std::vector Interpolations; + +// Parses a matcher description string and returns a vector of +// interpolations that appear in the string; generates non-fatal +// failures iff 'description' is an invalid matcher description. +// 'param_names' is a NULL-terminated array of parameter names in the +// order they appear in the MATCHER_P*() parameter list. +Interpolations ValidateMatcherDescription( + const char* param_names[], const char* description); + +// Returns the actual matcher description, given the matcher name, +// user-supplied description template string, interpolations in the +// string, and the printed values of the matcher parameters. +string FormatMatcherDescription( + const char* matcher_name, const char* description, + const Interpolations& interp, const Strings& param_values); + +} // namespace internal +} // namespace testing + #define MATCHER(name, description)\ class name##Matcher {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - gmock_Impl() {}\ + gmock_Impl(const ::testing::internal::Interpolations& gmock_interp)\ + : gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple<>());\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl());\ + return ::testing::Matcher(\ + new gmock_Impl(gmock_interp_));\ }\ name##Matcher() {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ + ::testing::internal::Interpolations gmock_interp_;\ };\ inline name##Matcher name() {\ return name##Matcher();\ @@ -830,23 +915,32 @@ ElementsAreArray(const T (&array)[N]) { template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\ + explicit gmock_Impl(p0##_type gmock_p0, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " ";\ - ::testing::internal::UniversalPrint(p0, os);\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, gmock_interp_));\ }\ name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template \ inline name##MatcherP name(p0##_type p0) {\ @@ -864,30 +958,35 @@ ElementsAreArray(const T (&array)[N]) { template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ - p1(gmock_p1) {}\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), p1(gmock_p1), gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p1, os);\ - *os << ")";\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, gmock_interp_));\ }\ name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ p1(gmock_p1) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template \ inline name##MatcherP2 name(p0##_type p0, \ @@ -906,35 +1005,39 @@ ElementsAreArray(const T (&array)[N]) { 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) {}\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p1, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p2, os);\ - *os << ")";\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, \ + p2));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, gmock_interp_));\ }\ name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template \ inline name##MatcherP3 name(p0##_type p0, \ @@ -955,40 +1058,42 @@ ElementsAreArray(const T (&array)[N]) { 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) {}\ + p3##_type gmock_p3, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p1, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p2, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p3, os);\ - *os << ")";\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, gmock_interp_));\ }\ 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template \ @@ -1013,45 +1118,45 @@ ElementsAreArray(const T (&array)[N]) { 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) {}\ + p3##_type gmock_p3, p4##_type gmock_p4, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p1, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p2, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p3, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p4, os);\ - *os << ")";\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3, p4));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, gmock_interp_));\ }\ 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template \ @@ -1076,25 +1181,18 @@ ElementsAreArray(const T (&array)[N]) { 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) {}\ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p1, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p2, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p3, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p4, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p5, os);\ - *os << ")";\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4, p5));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1102,17 +1200,20 @@ ElementsAreArray(const T (&array)[N]) { p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3, p4, p5));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, gmock_interp_));\ }\ 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1120,6 +1221,7 @@ ElementsAreArray(const T (&array)[N]) { p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template \ @@ -1147,26 +1249,20 @@ ElementsAreArray(const T (&array)[N]) { 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) {}\ + p6##_type gmock_p6, \ + const ::testing::internal::Interpolations& gmock_interp)\ + : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ + p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + gmock_interp_(gmock_interp) {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ - *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p1, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p2, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p3, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p4, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p5, os);\ - *os << ", ";\ - ::testing::internal::UniversalPrint(p6, os);\ - *os << ")";\ + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple(p0, p1, p2, p3, p4, p5, \ + p6));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1175,18 +1271,22 @@ ElementsAreArray(const T (&array)[N]) { p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3, p4, p5, p6));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, gmock_interp_));\ }\ 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ + NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1195,6 +1295,7 @@ ElementsAreArray(const T (&array)[N]) { p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template (p0, p1, p2, \ + p3, p4, p5, p6, p7));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1257,11 +1349,13 @@ ElementsAreArray(const T (&array)[N]) { p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3, p4, p5, p6, p7));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, \ + gmock_interp_));\ }\ name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ @@ -1269,7 +1363,10 @@ ElementsAreArray(const T (&array)[N]) { 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ + #p7, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1279,6 +1376,7 @@ ElementsAreArray(const T (&array)[N]) { p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template (p0, p1, p2, p3, p4, p5, p6, p7, p8));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1346,11 +1432,13 @@ ElementsAreArray(const T (&array)[N]) { p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3, p4, p5, p6, p7, p8));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8, \ + gmock_interp_));\ }\ name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ @@ -1358,7 +1446,10 @@ ElementsAreArray(const T (&array)[N]) { 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ + #p7, #p8, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1369,6 +1460,7 @@ ElementsAreArray(const T (&array)[N]) { p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1441,11 +1520,13 @@ ElementsAreArray(const T (&array)[N]) { p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl(p0, p1, \ - p2, p3, p4, p5, p6, p7, p8, p9));\ + return ::testing::Matcher(\ + new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, \ + gmock_interp_));\ }\ name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ @@ -1453,7 +1534,10 @@ ElementsAreArray(const T (&array)[N]) { 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) {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ + #p7, #p8, #p9, NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1465,6 +1549,7 @@ ElementsAreArray(const T (&array)[N]) { p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ + ::testing::internal::Interpolations gmock_interp_;\ };\ template #include #include +#include namespace testing { namespace internal { -// Generates a non-fatal failure iff 'description' is not a valid -// matcher description. -inline void ValidateMatcherDescription(const char* description) { - EXPECT_STREQ("", description) - << "The description string in a MATCHER*() macro must be \"\" " - "at this moment. We will implement custom description string soon."; -} - // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -310,6 +303,9 @@ ElementsAreArray(const T (&array)[N]) { } } // 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. The syntax: @@ -318,10 +314,18 @@ ElementsAreArray(const T (&array)[N]) { // // will define a matcher with the given name that executes the // statements, which must return a bool to indicate if the match -// succeeds. For now, the description_string must be "", but we'll -// allow other values soon. Inside the statements, you can refer to -// the value being matched by 'arg', and refer to its type by -// 'arg_type'. For example: +// 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; } // @@ -384,6 +388,38 @@ ElementsAreArray(const T (&array)[N]) { // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to // support multi-parameter matchers. // +// When defining a parameterized matcher, you can use Python-style +// interpolations in the description string to refer to the parameter +// values. We support the following syntax 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) { ... } @@ -440,6 +476,48 @@ ElementsAreArray(const T (&array)[N]) { // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. +namespace testing { +namespace internal { + +// Constants denoting interpolations in a matcher description string. +const int kTupleInterpolation = -1; // "%(*)s" +const int kPercentInterpolation = -2; // "%%" +const int kInvalidInterpolation = -3; // "%" followed by invalid text + +// Records the location and content of an interpolation. +struct Interpolation { + Interpolation(const char* start, const char* end, int param) + : start_pos(start), end_pos(end), param_index(param) {} + + // Points to the start of the interpolation (the '%' character). + const char* start_pos; + // Points to the first character after the interpolation. + const char* end_pos; + // 0-based index of the interpolated matcher parameter; + // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%". + int param_index; +}; + +typedef ::std::vector Interpolations; + +// Parses a matcher description string and returns a vector of +// interpolations that appear in the string; generates non-fatal +// failures iff 'description' is an invalid matcher description. +// 'param_names' is a NULL-terminated array of parameter names in the +// order they appear in the MATCHER_P*() parameter list. +Interpolations ValidateMatcherDescription( + const char* param_names[], const char* description); + +// Returns the actual matcher description, given the matcher name, +// user-supplied description template string, interpolations in the +// string, and the printed values of the matcher parameters. +string FormatMatcherDescription( + const char* matcher_name, const char* description, + const Interpolations& interp, const Strings& param_values); + +} // namespace internal +} // namespace testing + $range i 0..n $for i @@ -454,7 +532,11 @@ $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, ]] +const ::testing::internal::Interpolations& gmock_interp]] +$var impl_inits = [[ : $for j [[p$j(gmock_p$j), ]]gmock_interp_(gmock_interp)]] $var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var params_and_interp = [[$for j [[p$j, ]]gmock_interp_]] $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]]]] @@ -475,34 +557,29 @@ $var param_field_decls2 = [[$for j template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - [[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\ + [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ + $impl_inits {}\ virtual bool Matches(arg_type arg) const;\ - virtual void DescribeTo(::std::ostream* os) const {\ - *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ -[[$if i==1 [[ *os << " ";\ - ::testing::internal::UniversalPrint(p0, os);\ - -]] $elif i>=2 [[ *os << " (";\ - ::testing::internal::UniversalPrint(p0, os);\ -$range k 1..i-1 -$for k [[ - - *os << ", ";\ - ::testing::internal::UniversalPrint(p$k, os);\ -]] - - *os << ")";\ - -]]]] + virtual void DescribeTo(::std::ostream* gmock_os) const {\ + const ::testing::internal::Strings& gmock_printed_params = \ + ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ + ::std::tr1::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]]));\ + *gmock_os << ::testing::internal::FormatMatcherDescription(\ + #name, description, gmock_interp_, gmock_printed_params);\ }\$param_field_decls + const ::testing::internal::Interpolations gmock_interp_;\ };\ template \ operator ::testing::Matcher() const {\ - return ::testing::Matcher(new gmock_Impl($params));\ + return ::testing::Matcher(\ + new gmock_Impl($params_and_interp));\ }\ $class_name($ctor_param_list)$inits {\ - ::testing::internal::ValidateMatcherDescription(description);\ + const char* gmock_param_names[] = { $for j [[#p$j, ]]NULL };\ + gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ + gmock_param_names, ("" description ""));\ }\$param_field_decls2 + ::testing::internal::Interpolations gmock_interp_;\ };\$template inline $class_name$param_types name($param_types_and_names) {\ return $class_name$param_types($params);\ diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 5cd5f12e..28e904c3 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -41,22 +41,36 @@ // type Foo by defining either operator<<(::std::ostream&, const Foo&) // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. If both are defined, PrintTo() takes precedence. -// When T is a reference type, the address of the value is also +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are // printed. // // We also provide some convenient wrappers: // -// // Prints to a string. -// string ::testing::internal::UniversalPrinter::PrintAsString(value); -// // Prints a value using its inferred type. -// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// // Prints a value as the given type to a string. +// string ::testing::internal::UniversalPrinter::PrintToString(value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ #include // NOLINT +#include #include #include +#include #include #include @@ -350,13 +364,19 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { // Overload for ::std::tr1::tuple. Needed for printing function // arguments, which are packed as tuples. -// This helper template allows PrintTo() for tuples to be defined by +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by // induction on the number of tuple fields. The idea is that // TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. + +// The inductive case. template struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); @@ -364,20 +384,33 @@ struct TuplePrefixPrinter { UniversalPrinter::type> ::Print(::std::tr1::get(t), os); } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } }; + +// Base cases. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} -}; -template <> -struct TuplePrefixPrinter<1> { + template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); - } + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} }; +template <> +template +void TuplePrefixPrinter<1>::PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); +} // Helper function for printing a tuple. T must be instantiated with // a tuple type. @@ -499,7 +532,7 @@ class UniversalPrinter { // A convenient wrapper for Print() that returns the print-out as a // string. - static string PrintAsString(const T& value) { + static string PrintToString(const T& value) { ::std::stringstream ss; Print(value, &ss); return ss.str(); @@ -548,7 +581,7 @@ class UniversalPrinter { // A convenient wrapper for Print() that returns the print-out as a // string. - static string PrintAsString(const T (&a)[N]) { + static string PrintToString(const T (&a)[N]) { ::std::stringstream ss; Print(a, &ss); return ss.str(); @@ -577,7 +610,7 @@ class UniversalPrinter { // A convenient wrapper for Print() that returns the print-out as a // string. - static string PrintAsString(const T& value) { + static string PrintToString(const T& value) { ::std::stringstream ss; Print(value, &ss); return ss.str(); @@ -588,15 +621,34 @@ class UniversalPrinter { #endif // _MSC_VER }; -// Prints a value using its inferred type. In particular, if the -// original type of the value is a reference, the *referenced* type -// (as opposed to the reference type) will be used, as C++ doesn't -// infer reference types. This is useful when you just want to know -// what the value is and don't care if it's a reference or not. +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. template -void UniversalPrint(const T& value, ::std::ostream* os) { +void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalPrinter::Print(value, os); } +inline void UniversalTersePrint(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrinter::Print(string(str), os); + } +} +inline void UniversalTersePrint(char* str, ::std::ostream* os) { + UniversalTersePrint(static_cast(str), os); +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} } // namespace internal } // namespace testing diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc index 99fd3a2d..79b525d3 100644 --- a/src/gmock-matchers.cc +++ b/src/gmock-matchers.cc @@ -31,10 +31,15 @@ // Google Mock - a framework for writing C++ mock classes. // -// This file implements the Matcher and -// Matcher. +// This file implements Matcher, Matcher, and +// utilities for defining matchers. #include +#include + +#include +#include +#include namespace testing { @@ -58,4 +63,140 @@ Matcher::Matcher(const char* s) { *this = Eq(internal::string(s)); } +namespace internal { + +// Utilities for validating and formatting description strings in the +// MATCHER*() macros. + +// Returns the 0-based index of the given parameter in the +// NULL-terminated parameter array; if the parameter is "*", returns +// kTupleInterpolation; if it's not found in the list, returns +// kInvalidInterpolation. +int GetParamIndex(const char* param_names[], const string& param_name) { + if (param_name == "*") + return kTupleInterpolation; + + for (int i = 0; param_names[i] != NULL; i++) { + if (param_name == param_names[i]) + return i; + } + return kInvalidInterpolation; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Helper function used by ValidateMatcherDescription() to format +// error messages. +string FormatMatcherDescriptionSyntaxError(const char* description, + const char* error_pos) { + ::std::stringstream ss; + ss << "Syntax error at index " << (error_pos - description) + << " in matcher description \"" << description << "\": "; + return ss.str(); +} + +// Parses a matcher description string and returns a vector of +// interpolations that appear in the string; generates non-fatal +// failures iff 'description' is an invalid matcher description. +// 'param_names' is a NULL-terminated array of parameter names in the +// order they appear in the MATCHER_P*() parameter list. +Interpolations ValidateMatcherDescription( + const char* param_names[], const char* description) { + Interpolations interps; + for (const char* p = description; *p != '\0';) { + if (SkipPrefix("%%", &p)) { + interps.push_back(Interpolation(p - 2, p, kPercentInterpolation)); + } else if (SkipPrefix("%(", &p)) { + const char* const q = strstr(p, ")s"); + if (q == NULL) { + // TODO(wan@google.com): change the source file location in + // the failure to point to where the MATCHER*() macro is used. + ADD_FAILURE() << FormatMatcherDescriptionSyntaxError(description, p - 2) + << "an interpolation must end with \")s\", " + << "but \"" << (p - 2) << "\" does not."; + } else { + const string param_name(p, q); + const int param_index = GetParamIndex(param_names, param_name); + if (param_index == kInvalidInterpolation) { + ADD_FAILURE() << FormatMatcherDescriptionSyntaxError(description, p) + << "\"" << param_name + << "\" is an invalid parameter name."; + } else { + interps.push_back(Interpolation(p - 2, q + 2, param_index)); + p = q + 2; + } + } + } else { + EXPECT_NE(*p, '%') << FormatMatcherDescriptionSyntaxError(description, p) + << "use \"%%\" instead of \"%\" to print \"%\"."; + ++p; + } + } + return interps; +} + +// Joins a vector of strings as if they are fields of a tuple; returns +// the joined string. +string JoinAsTuple(const Strings& fields) { + switch (fields.size()) { + case 0: + return ""; + case 1: + return fields[0]; + default: + string result = "(" + fields[0]; + for (size_t i = 1; i < fields.size(); i++) { + result += ", "; + result += fields[i]; + } + result += ")"; + return result; + } +} + +// Returns the actual matcher description, given the matcher name, +// user-supplied description template string, interpolations in the +// string, and the printed values of the matcher parameters. +string FormatMatcherDescription( + const char* matcher_name, const char* description, + const Interpolations& interp, const Strings& param_values) { + string result; + if (*description == '\0') { + // When the user supplies an empty description, we calculate one + // from the matcher name. + result = ConvertIdentifierNameToWords(matcher_name); + if (param_values.size() >= 1) + result += " " + JoinAsTuple(param_values); + } else { + // The end position of the last interpolation. + const char* last_interp_end = description; + for (size_t i = 0; i < interp.size(); i++) { + result.append(last_interp_end, interp[i].start_pos); + const int param_index = interp[i].param_index; + if (param_index == kTupleInterpolation) { + result += JoinAsTuple(param_values); + } else if (param_index == kPercentInterpolation) { + result += '%'; + } else if (param_index != kInvalidInterpolation) { + result += param_values[param_index]; + } + last_interp_end = interp[i].end_pos; + } + result += last_interp_end; + } + + return result; +} + +} // namespace internal } // namespace testing diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 136ef5ce..1f88626f 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -390,17 +390,23 @@ TEST(MatcherMacroTest, Works) { } // Tests that the description string supplied to MATCHER() must be -// empty. +// valid. -MATCHER(HasBadDescription, "not empty?") { - return true; -} +MATCHER(HasBadDescription, "Invalid%") { return true; } TEST(MatcherMacroTest, CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { - EXPECT_NONFATAL_FAILURE(HasBadDescription(), - "The description string in a MATCHER*() macro " - "must be \"\" at this moment"); + EXPECT_NONFATAL_FAILURE( + HasBadDescription(), + "Syntax error at index 7 in matcher description \"Invalid%\": " + "use \"%%\" instead of \"%\" to print \"%\"."); +} + +MATCHER(HasGoodDescription, "good") { return true; } + +TEST(MatcherMacroTest, AcceptsValidDescription) { + const Matcher m = HasGoodDescription(); + EXPECT_EQ("good", Describe(m)); } // Tests that the body of MATCHER() can reference the type of the @@ -452,17 +458,26 @@ TEST(MatcherPMacroTest, Works) { } // Tests that the description string supplied to MATCHER_P() must be -// empty. +// valid. -MATCHER_P(HasBadDescription1, n, "not empty?") { +MATCHER_P(HasBadDescription1, n, "not %(m)s good") { return arg > n; } TEST(MatcherPMacroTest, CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { - EXPECT_NONFATAL_FAILURE(HasBadDescription1(2), - "The description string in a MATCHER*() macro " - "must be \"\" at this moment"); + EXPECT_NONFATAL_FAILURE( + HasBadDescription1(2), + "Syntax error at index 6 in matcher description \"not %(m)s good\": " + "\"m\" is an invalid parameter name."); +} + + +MATCHER_P(HasGoodDescription1, n, "good %(n)s") { return true; } + +TEST(MatcherPMacroTest, AcceptsValidDescription) { + const Matcher m = HasGoodDescription1(5); + EXPECT_EQ("good 5", Describe(m)); } // Tests that the description is calculated correctly from the matcher name. @@ -509,17 +524,29 @@ TEST(MatcherPMacroTest, WorksWhenExplicitlyInstantiatedWithReference) { // Tests that the description string supplied to MATCHER_Pn() must be -// empty. +// valid. -MATCHER_P2(HasBadDescription2, m, n, "not empty?") { +MATCHER_P2(HasBadDescription2, m, n, "not %(good") { return arg > m + n; } TEST(MatcherPnMacroTest, CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { - EXPECT_NONFATAL_FAILURE(HasBadDescription2(3, 4), - "The description string in a MATCHER*() macro " - "must be \"\" at this moment"); + EXPECT_NONFATAL_FAILURE( + HasBadDescription2(3, 4), + "Syntax error at index 4 in matcher description \"not %(good\": " + "an interpolation must end with \")s\", but \"%(good\" does not."); +} + +MATCHER_P2(HasComplexDescription, foo, bar, + "is as complex as %(foo)s %(bar)s (i.e. %(*)s or %%%(foo)s!)") { + return true; +} + +TEST(MatcherPnMacroTest, AcceptsValidDescription) { + Matcher m = HasComplexDescription(100, "ducks"); + EXPECT_EQ("is as complex as 100 \"ducks\" (i.e. (100, \"ducks\") or %100!)", + Describe(m)); } // Tests that the body of MATCHER_Pn() can reference the parameter diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index e9d12b29..0afa6236 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -48,6 +48,15 @@ #include namespace testing { + +namespace internal { +string FormatMatcherDescriptionSyntaxError(const char* description, + const char* error_pos); +int GetParamIndex(const char* param_names[], const string& param_name); +string JoinAsTuple(const Strings& fields); +bool SkipPrefix(const char* prefix, const char** pstr); +} // namespace internal + namespace gmock_matchers_test { using std::stringstream; @@ -91,7 +100,18 @@ using testing::Truly; using testing::TypedEq; using testing::_; using testing::internal::FloatingEqMatcher; +using testing::internal::FormatMatcherDescriptionSyntaxError; +using testing::internal::GetParamIndex; +using testing::internal::Interpolation; +using testing::internal::Interpolations; +using testing::internal::JoinAsTuple; +using testing::internal::SkipPrefix; using testing::internal::String; +using testing::internal::Strings; +using testing::internal::ValidateMatcherDescription; +using testing::internal::kInvalidInterpolation; +using testing::internal::kPercentInterpolation; +using testing::internal::kTupleInterpolation; using testing::internal::string; #ifdef GMOCK_HAS_REGEX @@ -2769,5 +2789,299 @@ TEST(ContainerEqExtraTest, WorksForMaps) { Explain(m, test_map)); } +// Tests GetParamIndex(). + +TEST(GetParamIndexTest, WorksForEmptyParamList) { + const char* params[] = { NULL }; + EXPECT_EQ(kTupleInterpolation, GetParamIndex(params, "*")); + EXPECT_EQ(kInvalidInterpolation, GetParamIndex(params, "a")); +} + +TEST(GetParamIndexTest, RecognizesStar) { + const char* params[] = { "a", "b", NULL }; + EXPECT_EQ(kTupleInterpolation, GetParamIndex(params, "*")); +} + +TEST(GetParamIndexTest, RecognizesKnownParam) { + const char* params[] = { "foo", "bar", NULL }; + EXPECT_EQ(0, GetParamIndex(params, "foo")); + EXPECT_EQ(1, GetParamIndex(params, "bar")); +} + +TEST(GetParamIndexTest, RejectsUnknownParam) { + const char* params[] = { "foo", "bar", NULL }; + EXPECT_EQ(kInvalidInterpolation, GetParamIndex(params, "foobar")); +} + +// Tests SkipPrefix(). + +TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { + const char* const str = "hello"; + + const char* p = str; + EXPECT_TRUE(SkipPrefix("", &p)); + EXPECT_EQ(str, p); + + p = str; + EXPECT_TRUE(SkipPrefix("hell", &p)); + EXPECT_EQ(str + 4, p); +} + +TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { + const char* const str = "world"; + + const char* p = str; + EXPECT_FALSE(SkipPrefix("W", &p)); + EXPECT_EQ(str, p); + + p = str; + EXPECT_FALSE(SkipPrefix("world!", &p)); + EXPECT_EQ(str, p); +} + +// Tests FormatMatcherDescriptionSyntaxError(). +TEST(FormatMatcherDescriptionSyntaxErrorTest, FormatsCorrectly) { + const char* const description = "hello%world"; + EXPECT_EQ("Syntax error at index 5 in matcher description \"hello%world\": ", + FormatMatcherDescriptionSyntaxError(description, description + 5)); +} + +// Tests ValidateMatcherDescription(). + +TEST(ValidateMatcherDescriptionTest, AcceptsEmptyDescription) { + const char* params[] = { "foo", "bar", NULL }; + EXPECT_THAT(ValidateMatcherDescription(params, ""), + ElementsAre()); +} + +TEST(ValidateMatcherDescriptionTest, + AcceptsNonEmptyDescriptionWithNoInterpolation) { + const char* params[] = { "foo", "bar", NULL }; + EXPECT_THAT(ValidateMatcherDescription(params, "a simple description"), + ElementsAre()); +} + +// We use MATCHER_P3() to define a matcher for testing +// ValidateMatcherDescription(); otherwise we'll end up with much +// plumbing code. This is not circular as +// ValidateMatcherDescription() doesn't affect whether the matcher +// matches a value or not. +MATCHER_P3(EqInterpolation, start, end, index, "equals Interpolation%(*)s") { + return arg.start_pos == start && arg.end_pos == end && + arg.param_index == index; +} + +TEST(ValidateMatcherDescriptionTest, AcceptsPercentInterpolation) { + const char* params[] = { "foo", NULL }; + const char* const desc = "one %%"; + EXPECT_THAT(ValidateMatcherDescription(params, desc), + ElementsAre(EqInterpolation(desc + 4, desc + 6, + kPercentInterpolation))); +} + +TEST(ValidateMatcherDescriptionTest, AcceptsTupleInterpolation) { + const char* params[] = { "foo", "bar", "baz", NULL }; + const char* const desc = "%(*)s after"; + EXPECT_THAT(ValidateMatcherDescription(params, desc), + ElementsAre(EqInterpolation(desc, desc + 5, + kTupleInterpolation))); +} + +TEST(ValidateMatcherDescriptionTest, AcceptsParamInterpolation) { + const char* params[] = { "foo", "bar", "baz", NULL }; + const char* const desc = "a %(bar)s."; + EXPECT_THAT(ValidateMatcherDescription(params, desc), + ElementsAre(EqInterpolation(desc + 2, desc + 9, 1))); +} + +TEST(ValidateMatcherDescriptionTest, AcceptsMultiplenterpolations) { + const char* params[] = { "foo", "bar", "baz", NULL }; + const char* const desc = "%(baz)s %(foo)s %(bar)s"; + EXPECT_THAT(ValidateMatcherDescription(params, desc), + ElementsAre(EqInterpolation(desc, desc + 7, 2), + EqInterpolation(desc + 8, desc + 15, 0), + EqInterpolation(desc + 16, desc + 23, 1))); +} + +TEST(ValidateMatcherDescriptionTest, AcceptsRepeatedParams) { + const char* params[] = { "foo", "bar", NULL }; + const char* const desc = "%(foo)s and %(foo)s"; + EXPECT_THAT(ValidateMatcherDescription(params, desc), + ElementsAre(EqInterpolation(desc, desc + 7, 0), + EqInterpolation(desc + 12, desc + 19, 0))); +} + +TEST(ValidateMatcherDescriptionTest, RejectsUnknownParam) { + const char* params[] = { "a", "bar", NULL }; + EXPECT_NONFATAL_FAILURE({ + EXPECT_THAT(ValidateMatcherDescription(params, "%(foo)s"), + ElementsAre()); + }, "Syntax error at index 2 in matcher description \"%(foo)s\": " + "\"foo\" is an invalid parameter name."); +} + +TEST(ValidateMatcherDescriptionTest, RejectsUnfinishedParam) { + const char* params[] = { "a", "bar", NULL }; + EXPECT_NONFATAL_FAILURE({ + EXPECT_THAT(ValidateMatcherDescription(params, "%(foo)"), + ElementsAre()); + }, "Syntax error at index 0 in matcher description \"%(foo)\": " + "an interpolation must end with \")s\", but \"%(foo)\" does not."); + + EXPECT_NONFATAL_FAILURE({ + EXPECT_THAT(ValidateMatcherDescription(params, "x%(a"), + ElementsAre()); + }, "Syntax error at index 1 in matcher description \"x%(a\": " + "an interpolation must end with \")s\", but \"%(a\" does not."); +} + +TEST(ValidateMatcherDescriptionTest, RejectsSinglePercent) { + const char* params[] = { "a", NULL }; + EXPECT_NONFATAL_FAILURE({ + EXPECT_THAT(ValidateMatcherDescription(params, "a %."), + ElementsAre()); + }, "Syntax error at index 2 in matcher description \"a %.\": " + "use \"%%\" instead of \"%\" to print \"%\"."); + +} + +// Tests JoinAsTuple(). + +TEST(JoinAsTupleTest, JoinsEmptyTuple) { + EXPECT_EQ("", JoinAsTuple(Strings())); +} + +TEST(JoinAsTupleTest, JoinsOneTuple) { + const char* fields[] = { "1" }; + EXPECT_EQ("1", JoinAsTuple(Strings(fields, fields + 1))); +} + +TEST(JoinAsTupleTest, JoinsTwoTuple) { + const char* fields[] = { "1", "a" }; + EXPECT_EQ("(1, a)", JoinAsTuple(Strings(fields, fields + 2))); +} + +TEST(JoinAsTupleTest, JoinsTenTuple) { + const char* fields[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; + EXPECT_EQ("(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)", + JoinAsTuple(Strings(fields, fields + 10))); +} + +// Tests FormatMatcherDescription(). + +TEST(FormatMatcherDescriptionTest, WorksForEmptyDescription) { + EXPECT_EQ("is even", + FormatMatcherDescription("IsEven", "", Interpolations(), + Strings())); + + const char* params[] = { "5" }; + EXPECT_EQ("equals 5", + FormatMatcherDescription("Equals", "", Interpolations(), + Strings(params, params + 1))); + + const char* params2[] = { "5", "8" }; + EXPECT_EQ("is in range (5, 8)", + FormatMatcherDescription("IsInRange", "", Interpolations(), + Strings(params2, params2 + 2))); +} + +TEST(FormatMatcherDescriptionTest, WorksForDescriptionWithNoInterpolation) { + EXPECT_EQ("is positive", + FormatMatcherDescription("Gt0", "is positive", Interpolations(), + Strings())); + + const char* params[] = { "5", "6" }; + EXPECT_EQ("is negative", + FormatMatcherDescription("Lt0", "is negative", Interpolations(), + Strings(params, params + 2))); +} + +TEST(FormatMatcherDescriptionTest, + WorksWhenDescriptionStartsWithInterpolation) { + const char* params[] = { "5" }; + const char* const desc = "%(num)s times bigger"; + const Interpolation interp[] = { Interpolation(desc, desc + 7, 0) }; + EXPECT_EQ("5 times bigger", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 1), + Strings(params, params + 1))); +} + +TEST(FormatMatcherDescriptionTest, + WorksWhenDescriptionEndsWithInterpolation) { + const char* params[] = { "5", "6" }; + const char* const desc = "is bigger than %(y)s"; + const Interpolation interp[] = { Interpolation(desc + 15, desc + 20, 1) }; + EXPECT_EQ("is bigger than 6", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 1), + Strings(params, params + 2))); +} + +TEST(FormatMatcherDescriptionTest, + WorksWhenDescriptionStartsAndEndsWithInterpolation) { + const char* params[] = { "5", "6" }; + const char* const desc = "%(x)s <= arg <= %(y)s"; + const Interpolation interp[] = { + Interpolation(desc, desc + 5, 0), + Interpolation(desc + 16, desc + 21, 1) + }; + EXPECT_EQ("5 <= arg <= 6", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 2), + Strings(params, params + 2))); +} + +TEST(FormatMatcherDescriptionTest, + WorksWhenDescriptionDoesNotStartOrEndWithInterpolation) { + const char* params[] = { "5.2" }; + const char* const desc = "has %(x)s cents"; + const Interpolation interp[] = { Interpolation(desc + 4, desc + 9, 0) }; + EXPECT_EQ("has 5.2 cents", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 1), + Strings(params, params + 1))); +} + +TEST(FormatMatcherDescriptionTest, + WorksWhenDescriptionContainsMultipleInterpolations) { + const char* params[] = { "5", "6" }; + const char* const desc = "in %(*)s or [%(x)s, %(y)s]"; + const Interpolation interp[] = { + Interpolation(desc + 3, desc + 8, kTupleInterpolation), + Interpolation(desc + 13, desc + 18, 0), + Interpolation(desc + 20, desc + 25, 1) + }; + EXPECT_EQ("in (5, 6) or [5, 6]", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 3), + Strings(params, params + 2))); +} + +TEST(FormatMatcherDescriptionTest, + WorksWhenDescriptionContainsRepeatedParams) { + const char* params[] = { "9" }; + const char* const desc = "in [-%(x)s, %(x)s]"; + const Interpolation interp[] = { + Interpolation(desc + 5, desc + 10, 0), + Interpolation(desc + 12, desc + 17, 0) + }; + EXPECT_EQ("in [-9, 9]", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 2), + Strings(params, params + 1))); +} + +TEST(FormatMatcherDescriptionTest, + WorksForDescriptionWithInvalidInterpolation) { + const char* params[] = { "9" }; + const char* const desc = "> %(x)s %(x)"; + const Interpolation interp[] = { Interpolation(desc + 2, desc + 7, 0) }; + EXPECT_EQ("> 9 %(x)", + FormatMatcherDescription("Foo", desc, + Interpolations(interp, interp + 1), + Strings(params, params + 1))); +} + } // namespace gmock_matchers_test } // namespace testing diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 8ce2b739..e5e3ff12 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -151,8 +152,11 @@ using ::std::set; using ::std::tr1::make_tuple; using ::std::tr1::tuple; using ::std::vector; +using ::testing::ElementsAre; using ::testing::StartsWith; -using ::testing::internal::UniversalPrint; +using ::testing::internal::Strings; +using ::testing::internal::UniversalTersePrint; +using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; using ::testing::internal::UniversalPrinter; using ::testing::internal::string; @@ -981,28 +985,67 @@ TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + " " + Print(sizeof(p)) + "-byte object ")); } -TEST(PrintAsStringTest, WorksForNonReference) { - EXPECT_EQ("123", UniversalPrinter::PrintAsString(123)); +TEST(PrintToStringTest, WorksForNonReference) { + EXPECT_EQ("123", UniversalPrinter::PrintToString(123)); } -TEST(PrintAsStringTest, WorksForReference) { +TEST(PrintToStringTest, WorksForReference) { int n = 123; EXPECT_EQ("@" + PrintPointer(&n) + " 123", - UniversalPrinter::PrintAsString(n)); + UniversalPrinter::PrintToString(n)); } -TEST(UniversalPrintTest, WorksForNonReference) { +TEST(UniversalTersePrintTest, WorksForNonReference) { ::std::stringstream ss; - UniversalPrint(123, &ss); + UniversalTersePrint(123, &ss); EXPECT_EQ("123", ss.str()); } -TEST(UniversalPrintTest, WorksForReference) { +TEST(UniversalTersePrintTest, WorksForReference) { const int& n = 123; ::std::stringstream ss; - UniversalPrint(n, &ss); + UniversalTersePrint(n, &ss); EXPECT_EQ("123", ss.str()); } +TEST(UniversalTersePrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalTersePrint(s1, &ss1); + EXPECT_EQ("\"abc\"", ss1.str()); + + char* s2 = const_cast(s1); + ::std::stringstream ss2; + UniversalTersePrint(s2, &ss2); + EXPECT_EQ("\"abc\"", ss2.str()); + + const char* s3 = NULL; + ::std::stringstream ss3; + UniversalTersePrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) { + EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple()), + ElementsAre()); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple) { + EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple(1)), + ElementsAre("1")); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple) { + EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a')), + ElementsAre("1", "'a' (97)")); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely) { + const int n = 1; + EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings( + tuple(n, "a")), + ElementsAre("1", "\"a\"")); +} + } // namespace gmock_printers_test } // namespace testing -- cgit v1.2.3 From 38ca64dd5f8dd4a5ee1822d805f16911213f18fb Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 19 Feb 2009 22:30:22 +0000 Subject: Fixes link errors due to an MS VC bug. By Vlad Losev. --- Makefile.am | 4 +- include/gmock/gmock-generated-actions.h | 71 +-- include/gmock/gmock-generated-actions.h.pump | 72 +-- make/Makefile | 12 +- msvc/gmock_link_test.vcproj | 2 +- test/gmock-sample.cc | 32 -- test/gmock-sample.h | 49 --- test/gmock_link2_test.cc | 40 ++ test/gmock_link_test.cc | 15 +- test/gmock_link_test.h | 635 +++++++++++++++++++++++++++ 10 files changed, 769 insertions(+), 163 deletions(-) delete mode 100644 test/gmock-sample.cc delete mode 100644 test/gmock-sample.h create mode 100644 test/gmock_link2_test.cc create mode 100644 test/gmock_link_test.h diff --git a/Makefile.am b/Makefile.am index 4a5a3fd6..08a6b2bc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -101,8 +101,8 @@ test_gmock_internal_utils_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la TESTS += test/gmock_link_test check_PROGRAMS += test/gmock_link_test test_gmock_link_test_SOURCES = test/gmock_link_test.cc \ - test/gmock-sample.cc \ - test/gmock-sample.h + test/gmock_link2_test.cc \ + test/gmock_link_test.h test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la TESTS += test/gmock-matchers_test diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 64475910..ee26f385 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -908,31 +908,33 @@ class WithArgsAction { explicit WithArgsAction(const InnerAction& action) : action_(action) {} template - operator Action() const { + 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; - typedef typename SelectArgs::type - InnerFunctionType; - class Impl : public ActionInterface { - public: - explicit Impl(const InnerAction& action) : action_(action) {} + explicit Impl(const InnerAction& action) : action_(action) {} - virtual Result Perform(const ArgumentTuple& args) { - return action_.Perform(SelectArgs::Select(args)); - } - private: - Action action_; - }; + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + + private: + typedef typename SelectArgs::type InnerFunctionType; + + Action action_; + }; - return MakeAction(new Impl(action_)); - } - private: const InnerAction action_; }; + // Does two actions sequentially. Used for implementing the DoAll(a1, // a2, ...) action. template @@ -945,28 +947,31 @@ class DoBothAction { // 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; - // Implements the DoAll(...) action for a particular function type F. - class Impl : public ActionInterface { - public: - Impl(const Action& action1, const Action& action2) - : action1_(action1), action2_(action2) {} + 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_; - }; + virtual Result Perform(const ArgumentTuple& args) { + action1_.Perform(args); + return action2_.Perform(args); + } + + private: + const Action action1_; + const Action action2_; + }; - return Action(new Impl(action1_, action2_)); - } - private: Action1 action1_; Action2 action2_; }; diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 1db69d1c..f8bec55d 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -333,27 +333,28 @@ class WithArgsAction { explicit WithArgsAction(const InnerAction& action) : action_(action) {} template - operator Action() const { + 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; - typedef typename SelectArgs::type - InnerFunctionType; - class Impl : public ActionInterface { - public: - explicit Impl(const InnerAction& action) : action_(action) {} + explicit Impl(const InnerAction& action) : action_(action) {} - virtual Result Perform(const ArgumentTuple& args) { - return action_.Perform(SelectArgs::Select(args)); - } - private: - Action action_; - }; + virtual Result Perform(const ArgumentTuple& args) { + return action_.Perform(SelectArgs::Select(args)); + } + + private: + typedef typename SelectArgs::type InnerFunctionType; + + Action action_; + }; - return MakeAction(new Impl(action_)); - } - private: const InnerAction action_; }; @@ -369,28 +370,31 @@ class DoBothAction { // 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; - // Implements the DoAll(...) action for a particular function type F. - class Impl : public ActionInterface { - public: - 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_; - }; - - return Action(new Impl(action1_, action2_)); - } - private: + 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_; + }; + Action1 action1_; Action2 action2_; }; diff --git a/make/Makefile b/make/Makefile index 557eb1e1..85c8b38b 100644 --- a/make/Makefile +++ b/make/Makefile @@ -89,15 +89,15 @@ gmock_main.a : gmock-all.o gtest-all.o gmock_main.o # Builds a sample test. -gmock-sample.o : $(USER_DIR)/gmock-sample.cc $(USER_DIR)/gmock-sample.h \ - $(GMOCK_HEADERS) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock-sample.cc - gmock_link_test.o : $(USER_DIR)/gmock_link_test.cc \ - $(USER_DIR)/gmock-sample.h $(GMOCK_HEADERS) + $(USER_DIR)/gmock_link_test.h $(GMOCK_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link_test.cc -gmock_link_test : gmock-sample.o gmock_link_test.o gmock_main.a +gmock_link2_test.o : $(USER_DIR)/gmock_link2_test.cc \ + $(USER_DIR)/gmock_link_test.h $(GMOCK_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link2_test.cc + +gmock_link_test : gmock_link_test.o gmock_link2_test.o gmock_main.a $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ # Builds another sample test. diff --git a/msvc/gmock_link_test.vcproj b/msvc/gmock_link_test.vcproj index de87b5af..3c1ee142 100644 --- a/msvc/gmock_link_test.vcproj +++ b/msvc/gmock_link_test.vcproj @@ -183,7 +183,7 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > - -class Sample { - public: - virtual ~Sample() {} - - virtual bool Foo(int n) = 0; -}; - -class MockSample : public Sample { - public: - MOCK_METHOD1(Foo, bool(int n)); -}; - -#endif // GMOCK_TEST_GMOCK_SAMPLE_H_ diff --git a/test/gmock_link2_test.cc b/test/gmock_link2_test.cc new file mode 100644 index 00000000..4c310c3d --- /dev/null +++ b/test/gmock_link2_test.cc @@ -0,0 +1,40 @@ +// 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), vladl@google.com (Vlad Losev) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file is for verifying that various Google Mock constructs do not +// produce linker errors when instantiated in different translation units. +// Please see gmock_link_test.h for details. + +#define LinkTest LinkTest2 + +#include "test/gmock_link_test.h" diff --git a/test/gmock_link_test.cc b/test/gmock_link_test.cc index 8a60e8bf..61e97d10 100644 --- a/test/gmock_link_test.cc +++ b/test/gmock_link_test.cc @@ -27,11 +27,14 @@ // (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) +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) -// This file is for verifying that a header file defining a mock class -// can be included in multiple translation units without causing a -// link error. It doesn't have to actually do anything - we are only -// checking that the test links correctly. +// Google Mock - a framework for writing C++ mock classes. +// +// This file is for verifying that various Google Mock constructs do not +// produce linker errors when instantiated in different translation units. +// Please see gmock_link_test.h for details. + +#define LinkTest LinkTest1 -#include "test/gmock-sample.h" +#include "test/gmock_link_test.h" diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h new file mode 100644 index 00000000..769c85d2 --- /dev/null +++ b/test/gmock_link_test.h @@ -0,0 +1,635 @@ +// Copyright 2009, 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: vladl@google.com (Vlad Losev) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file tests that: +// a. A header file defining a mock class can be included in multiple +// translation units without causing a link error. +// b. Actions and matchers can be instantiated with identical template +// arguments in different translation units without causing link +// errors. +// The following constructs are currently tested: +// Actions: +// Return() +// Return(value) +// ReturnNull +// ReturnRef +// Assign +// SetArgumentPointee +// SetArrayArgument +// SetErrnoAndReturn +// Invoke(function) +// Invoke(object, method) +// InvokeWithoutArgs(function) +// InvokeWithoutArgs(object, method) +// InvokeArgument +// WithArg +// WithArgs +// WithoutArgs +// DoAll +// DoDefault +// IgnoreResult +// Throw +// ACTION()-generated +// ACTION_P()-generated +// ACTION_P2()-generated +// Matchers: +// _ +// A +// An +// Eq +// Gt, Lt, Ge, Le, Ne +// NotNull +// Ref +// TypedEq +// DoubleEq +// FloatEq +// NanSensitiveDoubleEq +// NanSensitiveFloatEq +// ContainsRegex +// MatchesRegex +// EndsWith +// HasSubstr +// StartsWith +// StrCaseEq +// StrCaseNe +// StrEq +// StrNe +// ElementsAre +// ElementsAreArray +// ContainerEq +// Field +// Property +// ResultOf(function) +// Pointee +// Truly(predicate) +// AllOf +// AnyOf +// Not +// MatcherCast +// +// Please note: this test does not verify the functioning of these +// constructs, only that the programs using them will link successfully. +// +// Implementation note: +// This test requires identical definitions of Interface and Mock to be +// included in different translation units. We achieve this by writing +// them in this header and #including it in gmock_link_test.cc and +// gmock_link2_test.cc. Because the symbols generated by the compiler for +// those constructs must be identical in both translation units, +// definitions of Interface and Mock tests MUST be kept in the SAME +// NON-ANONYMOUS namespace in this file. The test fixture class LinkTest +// is defined as LinkTest1 in gmock_link_test.cc and as LinkTest2 in +// gmock_link2_test.cc to avoid producing linker errors. + +#ifndef GMOCK_TEST_GMOCK_LINK_TEST_H_ +#define GMOCK_TEST_GMOCK_LINK_TEST_H_ + +#include + +#include +#include +#include +#include + +using testing::_; +using testing::A; +using testing::AllOf; +using testing::AnyOf; +using testing::Assign; +using testing::ContainerEq; +using testing::DoAll; +using testing::DoDefault; +using testing::DoubleEq; +using testing::ElementsAre; +using testing::ElementsAreArray; +using testing::EndsWith; +using testing::Eq; +using testing::Field; +using testing::FloatEq; +using testing::Ge; +using testing::Gt; +using testing::HasSubstr; +using testing::IgnoreResult; +using testing::Invoke; +using testing::InvokeArgument; +using testing::InvokeWithoutArgs; +using testing::Le; +using testing::Lt; +using testing::Matcher; +using testing::MatcherCast; +using testing::NanSensitiveDoubleEq; +using testing::NanSensitiveFloatEq; +using testing::Ne; +using testing::Not; +using testing::NotNull; +using testing::Pointee; +using testing::Property; +using testing::Ref; +using testing::ResultOf; +using testing::Return; +using testing::ReturnNull; +using testing::ReturnRef; +using testing::SetArgumentPointee; +using testing::SetArrayArgument; +using testing::SetErrnoAndReturn; +using testing::StartsWith; +using testing::StrCaseEq; +using testing::StrCaseNe; +using testing::StrEq; +using testing::StrNe; +using testing::Truly; +using testing::TypedEq; +using testing::WithArg; +using testing::WithArgs; +using testing::WithoutArgs; + +#if GTEST_HAS_EXCEPTIONS +using testing::Throw; +#endif // GTEST_HAS_EXCEPTIONS + +#if GMOCK_HAS_REGEX +using testing::ContainsRegex; +using testing::MatchesRegex; +#endif // GMOCK_HAS_REGEX + +class Interface { + public: + virtual ~Interface() {} + virtual void VoidFromString(char* str) = 0; + virtual char* StringFromString(char* str) = 0; + virtual int IntFromString(char* str) = 0; + virtual int& IntRefFromString(char* str) = 0; + virtual void VoidFromFunc(void(*)(char*)) = 0; + virtual void VoidFromIntRef(int& n) = 0; + virtual void VoidFromFloat(float n) = 0; + virtual void VoidFromDouble(double n) = 0; + virtual void VoidFromVector(const std::vector& v) = 0; +}; + +class Mock: public Interface { + public: + MOCK_METHOD1(VoidFromString, void(char* str)); + MOCK_METHOD1(StringFromString, char*(char* str)); + MOCK_METHOD1(IntFromString, int(char* str)); + MOCK_METHOD1(IntRefFromString, int&(char* str)); + MOCK_METHOD1(VoidFromFunc, void(void(*func)(char* str))); + MOCK_METHOD1(VoidFromIntRef, void(int& n)); + MOCK_METHOD1(VoidFromFloat, void(float n)); + MOCK_METHOD1(VoidFromDouble, void(double n)); + MOCK_METHOD1(VoidFromVector, void(const std::vector& v)); +}; + +class InvokeHelper { + public: + static void StaticVoidFromVoid() {} + void VoidFromVoid() {} + static void StaticVoidFromString(char*) {} + void VoidFromString(char*) {} + static int StaticIntFromString(char*) { return 1; } + static bool StaticBoolFromString(const char*) { return true; } +}; + +class FieldHelper { + public: + FieldHelper(int field) : field_(field) {} + int field() const { return field_; } + int field_; // NOLINT -- need external access to field_ to test + // the Field matcher. +}; + +// Tests the linkage of the ReturnVoid action. +TEST(LinkTest, TestReturnVoid) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Return()); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the Return action. +TEST(LinkTest, TestReturn) { + Mock mock; + char ch = 'x'; + + EXPECT_CALL(mock, StringFromString(_)).WillOnce(Return(&ch)); + mock.StringFromString(NULL); +} + +// Tests the linkage of the ReturnNull action. +TEST(LinkTest, TestReturnNull) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Return()); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the ReturnRef action. +TEST(LinkTest, TestReturnRef) { + Mock mock; + int n = 42; + + EXPECT_CALL(mock, IntRefFromString(_)).WillOnce(ReturnRef(n)); + mock.IntRefFromString(NULL); +} + +// Tests the linkage of the Assign action. +TEST(LinkTest, TestAssign) { + Mock mock; + char ch = 'x'; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Assign(&ch, 'y')); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the SetArgumentPointee action. +TEST(LinkTest, TestSetArgumentPointee) { + Mock mock; + char ch = 'x'; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(SetArgumentPointee<0>('y')); + mock.VoidFromString(&ch); +} + +// Tests the linkage of the SetArrayArgument action. +TEST(LinkTest, TestSetArrayArgument) { + Mock mock; + char ch = 'x'; + char ch2 = 'y'; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(SetArrayArgument<0>(&ch2, + &ch2 + 1)); + mock.VoidFromString(&ch); +} + +// Tests the linkage of the SetErrnoAndReturn action. +TEST(LinkTest, TestSetErrnoAndReturn) { + Mock mock; + + int saved_errno = errno; + EXPECT_CALL(mock, IntFromString(_)).WillOnce(SetErrnoAndReturn(1, -1)); + mock.IntFromString(NULL); + errno = saved_errno; +} + +// Tests the linkage of the Invoke(function) and Invoke(object, method) actions. +TEST(LinkTest, TestInvoke) { + Mock mock; + InvokeHelper test_invoke_helper; + + EXPECT_CALL(mock, VoidFromString(_)) + .WillOnce(Invoke(&InvokeHelper::StaticVoidFromString)) + .WillOnce(Invoke(&test_invoke_helper, &InvokeHelper::VoidFromString)); + mock.VoidFromString(NULL); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the InvokeWithoutArgs action. +TEST(LinkTest, TestInvokeWithoutArgs) { + Mock mock; + InvokeHelper test_invoke_helper; + + EXPECT_CALL(mock, VoidFromString(_)) + .WillOnce(InvokeWithoutArgs(&InvokeHelper::StaticVoidFromVoid)) + .WillOnce(InvokeWithoutArgs(&test_invoke_helper, + &InvokeHelper::VoidFromVoid)); + mock.VoidFromString(NULL); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the InvokeArgument action. +TEST(LinkTest, TestInvokeArgument) { + Mock mock; + char ch = 'x'; + + EXPECT_CALL(mock, VoidFromFunc(_)).WillOnce(InvokeArgument<0>(&ch)); + mock.VoidFromFunc(InvokeHelper::StaticVoidFromString); +} + +// Tests the linkage of the WithArg action. +TEST(LinkTest, TestWithArg) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)) + .WillOnce(WithArg<0>(Invoke(&InvokeHelper::StaticVoidFromString))); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the WithArgs action. +TEST(LinkTest, TestWithArgs) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)) + .WillOnce(WithArgs<0>(Invoke(&InvokeHelper::StaticVoidFromString))); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the WithoutArgs action. +TEST(LinkTest, TestWithoutArgs) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(WithoutArgs(Return())); + mock.VoidFromString(NULL); +} + +// Tests the linkage of the DoAll action. +TEST(LinkTest, TestDoAll) { + Mock mock; + char ch = 'x'; + + EXPECT_CALL(mock, VoidFromString(_)) + .WillOnce(DoAll(SetArgumentPointee<0>('y'), Return())); + mock.VoidFromString(&ch); +} + +// Tests the linkage of the DoDefault action. +TEST(LinkTest, TestDoDefault) { + Mock mock; + char ch = 'x'; + + ON_CALL(mock, VoidFromString(_)).WillByDefault(Return()); + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(DoDefault()); + mock.VoidFromString(&ch); +} + +// Tests the linkage of the IgnoreResult action. +TEST(LinkTest, TestIgnoreResult) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(IgnoreResult(Return(42))); + mock.VoidFromString(NULL); +} + +#if GTEST_HAS_EXCEPTIONS +// Tests the linkage of the Throw action. +TEST(LinkTest, TestThrow) { + Mock mock; + + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Throw(42)); + EXPECT_THROW(mock.VoidFromString(NULL), int); +} +#endif // GTEST_HAS_EXCEPTIONS + +// Tests the linkage of actions created using ACTION macro. +namespace { +ACTION(Return1) { return 1; } +} + +TEST(LinkTest, TestActionMacro) { + Mock mock; + + EXPECT_CALL(mock, IntFromString(_)).WillOnce(Return1()); + mock.IntFromString(NULL); +} + +// Tests the linkage of actions created using ACTION_P macro. +namespace { +ACTION_P(ReturnArgument, ret_value) { return ret_value; } +} + +TEST(LinkTest, TestActionPMacro) { + Mock mock; + + EXPECT_CALL(mock, IntFromString(_)).WillOnce(ReturnArgument(42)); + mock.IntFromString(NULL); +} + +// Tests the linkage of actions created using ACTION_P2 macro. +namespace { +ACTION_P2(ReturnEqualsEitherOf, first, second) { + return arg0 == first || arg0 == second; +} +} + +TEST(LinkTest, TestActionP2Macro) { + Mock mock; + char ch = 'x'; + + EXPECT_CALL(mock, IntFromString(_)) + .WillOnce(ReturnEqualsEitherOf("one", "two")); + mock.IntFromString(&ch); +} + +// Tests the linkage of the "_" matcher. +TEST(LinkTest, TestMatcherAnything) { + Mock mock; + + ON_CALL(mock, VoidFromString(_)).WillByDefault(Return()); +} + +// Tests the linkage of the A matcher. +TEST(LinkTest, TestMatcherA) { + Mock mock; + + ON_CALL(mock, VoidFromString(A())).WillByDefault(Return()); +} + +// Tests the linkage of the Eq and the "bare value" matcher. +TEST(LinkTest, TestMatchersEq) { + Mock mock; + const char* p = "x"; + + ON_CALL(mock, VoidFromString(Eq(p))).WillByDefault(Return()); + ON_CALL(mock, VoidFromString(const_cast("y"))) + .WillByDefault(Return()); +} + +// Tests the linkage of the Lt, Gt, Le, Ge, and Ne matchers. +TEST(LinkTest, TestMatchersRelations) { + Mock mock; + + ON_CALL(mock, VoidFromFloat(Lt(1.0f))).WillByDefault(Return()); + ON_CALL(mock, VoidFromFloat(Gt(1.0f))).WillByDefault(Return()); + ON_CALL(mock, VoidFromFloat(Le(1.0f))).WillByDefault(Return()); + ON_CALL(mock, VoidFromFloat(Ge(1.0f))).WillByDefault(Return()); + ON_CALL(mock, VoidFromFloat(Ne(1.0f))).WillByDefault(Return()); +} + +// Tests the linkage of the NotNull matcher. +TEST(LinkTest, TestMatcherNotNull) { + Mock mock; + + ON_CALL(mock, VoidFromString(NotNull())).WillByDefault(Return()); +} + +// Tests the linkage of the Ref matcher. +TEST(LinkTest, TestMatcherRef) { + Mock mock; + int a = 0; + + ON_CALL(mock, VoidFromIntRef(Ref(a))).WillByDefault(Return()); +} + +// Tests the linkage of the TypedEq matcher. +TEST(LinkTest, TestMatcherTypedEq) { + Mock mock; + unsigned long a = 0; + + ON_CALL(mock, VoidFromIntRef(TypedEq(a))).WillByDefault(Return()); +} + +// Tests the linkage of the FloatEq, DoubleEq, NanSensitiveFloatEq and +// NanSensitiveDoubleEq matchers. +TEST(LinkTest, TestMatchersFloatingPoint) { + Mock mock; + float a = 0; + + ON_CALL(mock, VoidFromFloat(FloatEq(a))).WillByDefault(Return()); + ON_CALL(mock, VoidFromDouble(DoubleEq(a))).WillByDefault(Return()); + ON_CALL(mock, VoidFromFloat(NanSensitiveFloatEq(a))).WillByDefault(Return()); + ON_CALL(mock, VoidFromDouble(NanSensitiveDoubleEq(a))) + .WillByDefault(Return()); +} + +#if GMOCK_HAS_REGEX +// Tests the linkage of the ContainsRegex matcher. +TEST(LinkTest, TestMatcherContainsRegex) { + Mock mock; + + ON_CALL(mock, VoidFromString(ContainsRegex(".*"))).WillByDefault(Return()); +} + +// Tests the linkage of the MatchesRegex matcher. +TEST(LinkTest, TestMatcherMatchesRegex) { + Mock mock; + + ON_CALL(mock, VoidFromString(MatchesRegex(".*"))).WillByDefault(Return()); +} +#endif // GMOCK_HAS_REGEX + +// Tests the linkage of the StartsWith, EndsWith, and HasSubstr matchers. +TEST(LinkTest, TestMatchersSubstrings) { + Mock mock; + + ON_CALL(mock, VoidFromString(StartsWith("a"))).WillByDefault(Return()); + ON_CALL(mock, VoidFromString(EndsWith("c"))).WillByDefault(Return()); + ON_CALL(mock, VoidFromString(HasSubstr("b"))).WillByDefault(Return()); +} + +// Tests the linkage of the StrEq, StrNe, StrCaseEq, and StrCaseNe matchers. +TEST(LinkTest, TestMatchersStringEquality) { + Mock mock; + ON_CALL(mock, VoidFromString(StrEq("a"))).WillByDefault(Return()); + ON_CALL(mock, VoidFromString(StrNe("a"))).WillByDefault(Return()); + ON_CALL(mock, VoidFromString(StrCaseEq("a"))).WillByDefault(Return()); + ON_CALL(mock, VoidFromString(StrCaseNe("a"))).WillByDefault(Return()); +} + +// Tests the linkage of the ElementsAre matcher. +TEST(LinkTest, TestMatcherElementsAre) { + Mock mock; + + ON_CALL(mock, VoidFromVector(ElementsAre('a', _))).WillByDefault(Return()); +} + +// Tests the linkage of the ElementsAreArray matcher. +TEST(LinkTest, TestMatcherElementsAreArray) { + Mock mock; + char arr[] = { 'a', 'b' }; + + ON_CALL(mock, VoidFromVector(ElementsAreArray(arr))).WillByDefault(Return()); +} + +// Tests the linkage of the ContainerEq matcher. +TEST(LinkTest, TestMatcherContainerEq) { + Mock mock; + std::vector v; + + ON_CALL(mock, VoidFromVector(ContainerEq(v))).WillByDefault(Return()); +} + +// Tests the linkage of the Field matcher. +TEST(LinkTest, TestMatcherField) { + FieldHelper helper(0); + + Matcher m = Field(&FieldHelper::field_, Eq(0)); + EXPECT_TRUE(m.Matches(helper)); + + Matcher m2 = Field(&FieldHelper::field_, Eq(0)); + EXPECT_TRUE(m2.Matches(&helper)); +} + +// Tests the linkage of the Property matcher. +TEST(LinkTest, TestMatcherProperty) { + FieldHelper helper(0); + + Matcher m = Property(&FieldHelper::field, Eq(0)); + EXPECT_TRUE(m.Matches(helper)); + + Matcher m2 = Property(&FieldHelper::field, Eq(0)); + EXPECT_TRUE(m2.Matches(&helper)); +} + +// Tests the linkage of the ResultOf matcher. +TEST(LinkTest, TestMatcherResultOf) { + Matcher m = ResultOf(&InvokeHelper::StaticIntFromString, Eq(1)); + EXPECT_TRUE(m.Matches(NULL)); +} + +// Tests the linkage of the ResultOf matcher. +TEST(LinkTest, TestMatcherPointee) { + int n = 1; + + Matcher m = Pointee(Eq(1)); + EXPECT_TRUE(m.Matches(&n)); +} + +// Tests the linkage of the Truly matcher. +TEST(LinkTest, TestMatcherTruly) { + Matcher m = Truly(&InvokeHelper::StaticBoolFromString); + EXPECT_TRUE(m.Matches(NULL)); +} + +// Tests the linkage of the AllOf matcher. +TEST(LinkTest, TestMatcherAllOf) { + Matcher m = AllOf(_, Eq(1)); + EXPECT_TRUE(m.Matches(1)); +} + +// Tests the linkage of the AnyOf matcher. +TEST(LinkTest, TestMatcherAnyOf) { + Matcher m = AnyOf(_, Eq(1)); + EXPECT_TRUE(m.Matches(1)); +} + +// Tests the linkage of the Not matcher. +TEST(LinkTest, TestMatcherNot) { + Matcher m = Not(_); + EXPECT_FALSE(m.Matches(1)); +} + +// Tests the linkage of the MatcherCast() function. +TEST(LinkTest, TestMatcherCast) { + Matcher m = MatcherCast(_); + EXPECT_TRUE(m.Matches(NULL)); +} + +#endif // GMOCK_TEST_GMOCK_LINK_TEST_H_ -- cgit v1.2.3 From 7f4c2c0f95a69901175db5edcd07bc26519ef82f Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 19 Feb 2009 22:38:27 +0000 Subject: Adds two actions: SaveArg and SetArgReferee. --- include/gmock/gmock-generated-actions.h | 107 +++++++++++++++++++-------- include/gmock/gmock-generated-actions.h.pump | 40 +++++++++- test/gmock-generated-actions_test.cc | 61 +++++++++++++++ 3 files changed, 177 insertions(+), 31 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index ee26f385..c2e155c2 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -998,51 +998,57 @@ class ActionHelper { public: static Result Perform(Impl* impl, const ::std::tr1::tuple<>& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, ExcessiveArg(), ExcessiveArg(), + return impl->template gmock_PerformImpl<>(args, ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), + ExcessiveArg()); } template static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, get<0>(args), ExcessiveArg(), + return impl->template gmock_PerformImpl(args, get<0>(args), + ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + ExcessiveArg()); } template static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, get<0>(args), get<1>(args), + return impl->template gmock_PerformImpl(args, get<0>(args), + get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + ExcessiveArg()); } template static Result Perform(Impl* impl, const ::std::tr1::tuple& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, get<0>(args), get<1>(args), - get<2>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + 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 ::std::tr1::tuple& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, get<0>(args), get<1>(args), - get<2>(args), get<3>(args), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + 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 ::std::tr1::tuple& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); + 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 & args) { using ::std::tr1::get; - return impl->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()); + 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 & args) { using ::std::tr1::get; - return impl->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()); + 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 & args) { using ::std::tr1::get; - return impl->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()); + 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 & args) { using ::std::tr1::get; - return impl->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()); + 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 & args) { using ::std::tr1::get; - return impl->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)); + 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)); } }; @@ -2303,8 +2314,44 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, arg4_type arg4, arg5_type arg5, arg6_type arg6, arg7_type arg7, \ arg8_type arg8, arg9_type arg9) const +// TODO(wan@google.com): move the following to a different .h file +// such that we don't have to run 'pump' every time the code is +// updated. namespace testing { +namespace internal { + +// Saves argument #0 to where the pointer points. +ACTION_P(SaveArg0, pointer) { *pointer = arg0; } + +// Assigns 'value' to the variable referenced by argument #0. +ACTION_P(SetArg0Referee, value) { + // Ensures that argument #0 is a reference. If you get a compiler + // error on the next line, you are using SetArgReferee(value) in + // a mock function whose k-th (0-based) argument is not a reference. + GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + SetArgReferee_must_be_used_with_a_reference_argument); + arg0 = value; +} + +} // namespace internal + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +template +inline internal::WithArgsAction, k> +SaveArg(const Pointer& pointer) { + return WithArg(internal::SaveArg0(pointer)); +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +template +inline internal::WithArgsAction, k> +SetArgReferee(const Value& value) { + return WithArg(internal::SetArg0Referee(value)); +} + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index f8bec55d..26f9319d 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -436,7 +436,7 @@ $var arg_list = [[$if (i==0) | (i==n) [[$as$eas]] $else [[$as, $eas]]]] $template static Result Perform(Impl* impl, const ::std::tr1::tuple<$As>& args) { using ::std::tr1::get; - return impl->gmock_PerformImpl(args, $arg_list); + return impl->template gmock_PerformImpl<$As>(args, $arg_list); } ]] @@ -774,10 +774,48 @@ $arg_types_and_names) const;\$param_field_decls gmock_Impl::gmock_PerformImpl(const args_type& args, [[]] $arg_types_and_names) const ]] +$$ } // This meta comment fixes auto-indentation in Emacs. It won't +$$ // show up in the generated code. +// TODO(wan@google.com): move the following to a different .h file +// such that we don't have to run 'pump' every time the code is +// updated. namespace testing { +namespace internal { + +// Saves argument #0 to where the pointer points. +ACTION_P(SaveArg0, pointer) { *pointer = arg0; } + +// Assigns 'value' to the variable referenced by argument #0. +ACTION_P(SetArg0Referee, value) { + // Ensures that argument #0 is a reference. If you get a compiler + // error on the next line, you are using SetArgReferee(value) in + // a mock function whose k-th (0-based) argument is not a reference. + GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + SetArgReferee_must_be_used_with_a_reference_argument); + arg0 = value; +} + +} // namespace internal + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +template +inline internal::WithArgsAction, k> +SaveArg(const Pointer& pointer) { + return WithArg(internal::SaveArg0(pointer)); +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +template +inline internal::WithArgsAction, k> +SetArgReferee(const Value& value) { + return WithArg(internal::SetArg0Referee(value)); +} + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 0d5260a2..dd25a123 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -57,6 +57,8 @@ using testing::DoAll; using testing::Invoke; using testing::InvokeArgument; using testing::Return; +using testing::SaveArg; +using testing::SetArgReferee; using testing::SetArgumentPointee; using testing::StaticAssertTypeEq; using testing::Unused; @@ -1026,6 +1028,30 @@ TEST(ActionMacroTest, CanReferenceMockFunctionReturnType) { EXPECT_EQ(1, a1.Perform(make_tuple(false))); } +// Tests that ACTION() works for arguments passed by const reference. +ACTION(ReturnAddrOfConstBoolReferenceArg) { + StaticAssertTypeEq(); + return &arg1; +} + +TEST(ActionMacroTest, WorksForConstReferenceArg) { + Action a = ReturnAddrOfConstBoolReferenceArg(); + const bool b = false; + EXPECT_EQ(&b, a.Perform(tuple(0, b))); +} + +// Tests that ACTION() works for arguments passed by non-const reference. +ACTION(ReturnAddrOfIntReferenceArg) { + StaticAssertTypeEq(); + return &arg0; +} + +TEST(ActionMacroTest, WorksForNonConstReferenceArg) { + Action a = ReturnAddrOfIntReferenceArg(); + int n = 0; + EXPECT_EQ(&n, a.Perform(tuple(n, true, 1))); +} + // Tests that ACTION() can be used in a namespace. namespace action_test { ACTION(Sum) { return arg0 + arg1; } @@ -1310,6 +1336,41 @@ TEST(ActionPnMacroTest, CanExplicitlyInstantiateWithReferenceTypes) { EXPECT_EQ(55, a.Perform(empty)); } +TEST(SaveArgActionTest, WorksForSameType) { + int result = 0; + const Action a1 = SaveArg<0>(&result); + a1.Perform(make_tuple(5)); + EXPECT_EQ(5, result); +} + +TEST(SaveArgActionTest, WorksForCompatibleType) { + int result = 0; + const Action a1 = SaveArg<1>(&result); + a1.Perform(make_tuple(true, 'a')); + EXPECT_EQ('a', result); +} + +TEST(SetArgRefereeActionTest, WorksForSameType) { + int value = 0; + const Action a1 = SetArgReferee<0>(1); + a1.Perform(tuple(value)); + EXPECT_EQ(1, value); +} + +TEST(SetArgRefereeActionTest, WorksForCompatibleType) { + int value = 0; + const Action a1 = SetArgReferee<1>('a'); + a1.Perform(tuple(0, value)); + EXPECT_EQ('a', value); +} + +TEST(SetArgRefereeActionTest, WorksWithExtraArguments) { + int value = 0; + const Action a1 = SetArgReferee<2>('a'); + a1.Perform(tuple(true, 0, value, "hi")); + EXPECT_EQ('a', value); +} + #if GTEST_HAS_EXCEPTIONS TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) { -- cgit v1.2.3 From 1bee7b2f1dbf491fd8a3ee49e791a2aa324d86c7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 20 Feb 2009 18:31:04 +0000 Subject: Implements Contains(element) matcher. By Gary Morain. --- include/gmock/gmock-generated-matchers.h | 41 ++++++++++++ include/gmock/gmock-generated-matchers.h.pump | 41 ++++++++++++ test/gmock-generated-matchers_test.cc | 96 +++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 26c064b7..afe1bd48 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -1573,4 +1573,45 @@ string FormatMatcherDescription( p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>::\ gmock_Impl::Matches(arg_type arg) const +namespace testing { +namespace internal { + +// Returns true iff element is in the STL-style container. +template +inline bool Contains(const Container& container, const Element& element) { + return ::std::find(container.begin(), container.end(), element) != + container.end(); +} + +// Returns true iff element is in the C-style array. +template +inline bool Contains(const ArrayElement (&array)[N], const Element& element) { + return ::std::find(array, array + N, element) != array + N; +} + +} // namespace internal + +// Matches an STL-style container or a C-style array that contains the given +// element. +// +// Examples: +// ::std::set page_ids; +// page_ids.insert(3); +// page_ids.insert(1); +// EXPECT_THAT(page_ids, Contains(1)); +// EXPECT_THAT(page_ids, Contains(3.0)); +// EXPECT_THAT(page_ids, Not(Contains(4))); +// +// ::std::map page_lengths; +// page_lengths[1] = 100; +// EXPECT_THAT(map_int, Contains(::std::pair(1, 100))); +// +// const char* user_ids[] = { "joe", "mike", "tom" }; +// EXPECT_THAT(user_ids, Contains(::std::string("tom"))); +MATCHER_P(Contains, element, "") { + return internal::Contains(arg, element); +} + +} // namespace testing + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 31be698f..09dfedfc 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -590,4 +590,45 @@ $var param_field_decls2 = [[$for j ]] +namespace testing { +namespace internal { + +// Returns true iff element is in the STL-style container. +template +inline bool Contains(const Container& container, const Element& element) { + return ::std::find(container.begin(), container.end(), element) != + container.end(); +} + +// Returns true iff element is in the C-style array. +template +inline bool Contains(const ArrayElement (&array)[N], const Element& element) { + return ::std::find(array, array + N, element) != array + N; +} + +} // namespace internal + +// Matches an STL-style container or a C-style array that contains the given +// element. +// +// Examples: +// ::std::set page_ids; +// page_ids.insert(3); +// page_ids.insert(1); +// EXPECT_THAT(page_ids, Contains(1)); +// EXPECT_THAT(page_ids, Contains(3.0)); +// EXPECT_THAT(page_ids, Not(Contains(4))); +// +// ::std::map page_lengths; +// page_lengths[1] = 100; +// EXPECT_THAT(map_int, Contains(::std::pair(1, 100))); +// +// const char* user_ids[] = { "joe", "mike", "tom" }; +// EXPECT_THAT(user_ids, Contains(::std::string("tom"))); +MATCHER_P(Contains, element, "") { + return internal::Contains(arg, element); +} + +} // namespace testing + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 1f88626f..669652b9 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -34,8 +34,11 @@ #include #include +#include +#include #include #include +#include #include #include @@ -45,9 +48,13 @@ namespace { using std::list; +using std::map; +using std::pair; +using std::set; using std::stringstream; using std::vector; using testing::_; +using testing::Contains; using testing::ElementsAre; using testing::ElementsAreArray; using testing::Eq; @@ -735,4 +742,93 @@ TEST(MatcherPnMacroTest, TypesAreCorrect) { EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); } +TEST(ContainsTest, ListMatchesWhenElementIsInContainer) { + list some_list; + some_list.push_back(3); + some_list.push_back(1); + some_list.push_back(2); + EXPECT_THAT(some_list, Contains(1)); + EXPECT_THAT(some_list, Contains(3.0)); + EXPECT_THAT(some_list, Contains(2.0f)); + + list another_list; + another_list.push_back("fee"); + another_list.push_back("fie"); + another_list.push_back("foe"); + another_list.push_back("fum"); + EXPECT_THAT(another_list, Contains(string("fee"))); +} + +TEST(ContainsTest, ListDoesNotMatchWhenElementIsNotInContainer) { + list some_list; + some_list.push_back(3); + some_list.push_back(1); + EXPECT_THAT(some_list, Not(Contains(4))); +} + +TEST(ContainsTest, SetMatchesWhenElementIsInContainer) { + set some_set; + some_set.insert(3); + some_set.insert(1); + some_set.insert(2); + EXPECT_THAT(some_set, Contains(1.0)); + EXPECT_THAT(some_set, Contains(3.0f)); + EXPECT_THAT(some_set, Contains(2)); + + set another_set; + another_set.insert("fee"); + another_set.insert("fie"); + another_set.insert("foe"); + another_set.insert("fum"); + EXPECT_THAT(another_set, Contains(string("fum"))); +} + +TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { + set some_set; + some_set.insert(3); + some_set.insert(1); + EXPECT_THAT(some_set, Not(Contains(4))); + + set c_string_set; + c_string_set.insert("hello"); + EXPECT_THAT(c_string_set, Not(Contains(string("hello").c_str()))); +} + +TEST(ContainsTest, DescribesItselfCorrectly) { + Matcher > m = Contains(1); + EXPECT_EQ("contains 1", Describe(m)); +} + +TEST(ContainsTest, MapMatchesWhenElementIsInContainer) { + map my_map; + const char* bar = "a string"; + my_map[bar] = 2; + EXPECT_THAT(my_map, Contains(pair(bar, 2))); + + map another_map; + another_map["fee"] = 1; + another_map["fie"] = 2; + another_map["foe"] = 3; + another_map["fum"] = 4; + EXPECT_THAT(another_map, Contains(pair(string("fee"), 1))); + EXPECT_THAT(another_map, Contains(pair("fie", 2))); +} + +TEST(ContainsTest, MapDoesNotMatchWhenElementIsNotInContainer) { + map some_map; + some_map[1] = 11; + some_map[2] = 22; + EXPECT_THAT(some_map, Not(Contains(pair(2, 23)))); +} + +TEST(ContainsTest, ArrayMatchesWhenElementIsInContainer) { + const char* string_array[] = { "fee", "fie", "foe", "fum" }; + EXPECT_THAT(string_array, Contains(string("fum"))); +} + +TEST(ContainsTest, ArrayDoesNotMatchWhenElementIsNotInContainer) { + int int_array[] = { 1, 2, 3, 4 }; + EXPECT_THAT(int_array, Not(Contains(5))); +} + } // namespace -- cgit v1.2.3 From 652540a278e56528e576f9ea77515f386698a326 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 23 Feb 2009 23:37:29 +0000 Subject: Cleans up macro definitions. --- include/gmock/gmock-actions.h | 4 ++-- include/gmock/gmock-matchers.h | 4 ++-- include/gmock/internal/gmock-port.h | 4 ++-- src/gmock-printers.cc | 2 +- test/gmock-actions_test.cc | 16 ++++++++-------- test/gmock-generated-function-mockers_test.cc | 14 +++++++------- test/gmock-internal-utils_test.cc | 2 +- test/gmock-matchers_test.cc | 2 +- test/gmock-port_test.cc | 2 +- test/gmock-printers_test.cc | 20 ++++++++++---------- test/gmock-spec-builders_test.cc | 6 +++--- 11 files changed, 38 insertions(+), 38 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 7aa5274c..823054bf 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -678,12 +678,12 @@ class SetArrayArgumentAction { // Microsoft compiler deprecates ::std::copy, so we want to suppress warning // 4996 (Function call with parameters that may be unsafe) there. -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. #endif // GTEST_OS_WINDOWS ::std::copy(first_, last_, ::std::tr1::get(args)); -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #pragma warning(pop) // Restores the warning state. #endif // GTEST_OS_WINDOWS } diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 525128b9..e6af144c 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1141,13 +1141,13 @@ class TrulyMatcher { // interested in the address of the argument. template bool Matches(T& x) const { -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // MSVC warns about converting a value into bool (warning 4800). #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4800) // Temporarily disables warning 4800. #endif // GTEST_OS_WINDOWS return predicate_(x); -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #pragma warning(pop) // Restores the warning state. #endif // GTEST_OS_WINDOWS } diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 45b95cde..cb352192 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -58,7 +58,7 @@ #include #endif // __GNUC__ -#ifdef GTEST_OS_LINUX +#if GTEST_OS_LINUX // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already @@ -85,7 +85,7 @@ namespace internal { // For Windows, check the compiler version. At least VS 2005 SP1 is // required to compile Google Mock. -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #if _MSC_VER < 1400 #error "At least Visual Studio 2005 SP1 is required to compile Google Mock." diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc index 611d8659..495717dc 100644 --- a/src/gmock-printers.cc +++ b/src/gmock-printers.cc @@ -55,7 +55,7 @@ namespace { using ::std::ostream; -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS #define snprintf _snprintf_s #endif diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 6fb47bca..077681b0 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -95,10 +95,10 @@ TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); -#ifndef GTEST_OS_WINDOWS +#if !GTEST_OS_WINDOWS EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); -#endif // GTEST_OS_WINDOWS +#endif // !GTEST_OS_WINDOWS EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT @@ -121,10 +121,10 @@ TEST(BuiltInDefaultValueTest, ExistsForNumericTypes) { EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); -#ifndef GTEST_OS_WINDOWS +#if !GTEST_OS_WINDOWS EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); -#endif // GTEST_OS_WINDOWS +#endif // !GTEST_OS_WINDOWS EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT @@ -196,7 +196,7 @@ TEST(BuiltInDefaultValueTest, UserTypeHasNoDefault) { EXPECT_FALSE(BuiltInDefaultValue::Exists()); } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Tests that BuiltInDefaultValue::Get() aborts the program. TEST(BuiltInDefaultValueDeathTest, IsUndefinedForReferences) { @@ -257,7 +257,7 @@ TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_EQ(0, DefaultValue::Get()); -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST EXPECT_DEATH({ // NOLINT DefaultValue::Get(); }, ""); @@ -313,7 +313,7 @@ TEST(DefaultValueOfReferenceDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_FALSE(DefaultValue::IsSet()); -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST EXPECT_DEATH({ // NOLINT DefaultValue::Get(); }, ""); @@ -556,7 +556,7 @@ TEST(DoDefaultTest, ReturnsBuiltInDefaultValueByDefault) { EXPECT_EQ(0, mock.IntFunc(true)); } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Tests that DoDefault() aborts the process when there is no built-in // default value for the return type. diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index d8e678b2..431cbd62 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -40,7 +40,7 @@ #include #include -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // MSDN says the header file to be included for STDMETHOD is BaseTyps.h but // we are getting compiler errors if we use basetyps.h, hence including // objbase.h for definition of STDMETHOD. @@ -50,9 +50,9 @@ // There is a bug in MSVC (fixed in VS 2008) that prevents creating a // mock for a function with const arguments, so we don't test such // cases for MSVC versions older than 2008. -#if !defined(GTEST_OS_WINDOWS) || (_MSC_VER >= 1500) +#if !GTEST_OS_WINDOWS || (_MSC_VER >= 1500) #define GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS -#endif // !defined(GTEST_OS_WINDOWS) || (_MSC_VER >= 1500) +#endif // !GTEST_OS_WINDOWS || (_MSC_VER >= 1500) namespace testing { namespace gmock_generated_function_mockers_test { @@ -102,7 +102,7 @@ class FooInterface { virtual int TypeWithHole(int (*func)()) = 0; virtual int TypeWithComma(const std::map& a_map) = 0; -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS STDMETHOD_(int, CTNullary)() = 0; STDMETHOD_(bool, CTUnary)(int x) = 0; STDMETHOD_(int, CTDecimal)(bool b, char c, short d, int e, long f, // NOLINT @@ -140,7 +140,7 @@ class MockFoo : public FooInterface { MOCK_METHOD1(TypeWithHole, int(int (*)())); // NOLINT MOCK_METHOD1(TypeWithComma, int(const std::map&)); // NOLINT -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, CTNullary, int()); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, CTUnary, bool(int)); MOCK_METHOD10_WITH_CALLTYPE(STDMETHODCALLTYPE, CTDecimal, int(bool b, char c, @@ -261,7 +261,7 @@ TEST_F(FunctionMockerTest, MocksFunctionsOverloadedOnConstnessOfThis) { EXPECT_EQ('a', Const(*foo_).OverloadedOnConstness()); } -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // Tests mocking a nullary function with calltype. TEST_F(FunctionMockerTest, MocksNullaryFunctionWithCallType) { EXPECT_CALL(mock_foo_, CTNullary()) @@ -373,7 +373,7 @@ TEST(TemplateMockTest, Works) { EXPECT_EQ(0, mock.GetSize()); } -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // Tests mocking template interfaces with calltype. template diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 6503ffb2..b678a9e5 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -320,7 +320,7 @@ TEST(AssertTest, SucceedsOnTrue) { Assert(true, __FILE__, __LINE__); // This should succeed too. } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Tests that Assert(false, ...) generates a fatal failure. TEST(AssertTest, FailsFatallyOnFalse) { diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 0afa6236..82820fe0 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -2462,7 +2462,7 @@ TEST(ResultOfTest, WorksForCompatibleMatcherTypes) { EXPECT_FALSE(matcher.Matches(42)); } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Tests that the program aborts when ResultOf is passed // a NULL function pointer. TEST(ResultOfDeathTest, DiesOnNullFunctionPointers) { diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index f35bc115..5c4b3a52 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -65,7 +65,7 @@ TEST(GmockCheckSyntaxTest, WorksWithSwitch) { GMOCK_CHECK_(true) << "Check failed in switch case"; } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index e5e3ff12..29a0db84 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -53,11 +53,11 @@ #include // hash_map and hash_set are available on Windows. -#ifdef GTEST_OS_WINDOWS -#define GMOCK_HAS_HASH_MAP_ // Indicates that hash_map is available. -#include // NOLINT -#define GMOCK_HAS_HASH_SET_ // Indicates that hash_set is available. -#include // NOLINT +#if GTEST_OS_WINDOWS +#define GMOCK_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. +#include // NOLINT +#define GMOCK_HAS_HASH_SET_ 1 // Indicates that hash_set is available. +#include // NOLINT #endif // GTEST_OS_WINDOWS // Some user-defined types for testing the universal value printer. @@ -160,7 +160,7 @@ using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; using ::testing::internal::UniversalPrinter; using ::testing::internal::string; -#ifdef GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // MSVC defines the following classes in the ::stdext namespace while // gcc defines them in the :: namespace. Note that they are not part // of the C++ standard. @@ -279,10 +279,10 @@ TEST(PrintBuiltInTypeTest, Integer) { // Size types. TEST(PrintBuiltInTypeTest, Size_t) { EXPECT_EQ("1", Print(sizeof('a'))); // size_t. -#ifndef GTEST_OS_WINDOWS +#if !GTEST_OS_WINDOWS // Windows has no ssize_t type. EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. -#endif // GTEST_OS_WINDOWS +#endif // !GTEST_OS_WINDOWS } // Floating-points. @@ -674,7 +674,7 @@ TEST(PrintStlContainerTest, NonEmptyDeque) { EXPECT_EQ("{ 1, 3 }", Print(non_empty)); } -#ifdef GMOCK_HAS_HASH_MAP_ +#if GMOCK_HAS_HASH_MAP_ TEST(PrintStlContainerTest, OneElementHashMap) { hash_map map1; @@ -696,7 +696,7 @@ TEST(PrintStlContainerTest, HashMultiMap) { #endif // GMOCK_HAS_HASH_MAP_ -#ifdef GMOCK_HAS_HASH_SET_ +#if GMOCK_HAS_HASH_SET_ TEST(PrintStlContainerTest, HashSet) { hash_set set1; diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 3e944ea4..4e330f0b 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -192,7 +192,7 @@ TEST(OnCallSyntaxTest, WithArgumentsCanAppearAtMostOnce) { }, ".WithArguments() cannot appear more than once in an ON_CALL()"); } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TEST(OnCallSyntaxTest, WillByDefaultIsMandatory) { MockA a; @@ -987,7 +987,7 @@ TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { #endif // GMOCK_HAS_REGEX -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) { MockA a; @@ -1143,7 +1143,7 @@ TEST(SequenceTest, AnyOrderIsOkByDefault) { } } -#ifdef GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST // Tests that the calls must be in strict order when a complete order // is specified. -- cgit v1.2.3 From 6f14769e86f17a9997809ee2a9c149b57fdc4b21 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 3 Mar 2009 06:44:08 +0000 Subject: Allows a mock object to delete itself in an action. By Simon Bowden. --- include/gmock/gmock-spec-builders.h | 16 ++++++++++++---- test/gmock-spec-builders_test.cc | 21 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index bd956f3d..77b50f80 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1426,6 +1426,7 @@ class InvokeWithHelper { bool is_excessive = false; ::std::stringstream ss; ::std::stringstream why; + ::std::stringstream loc; Action action; Expectation* exp; @@ -1435,6 +1436,11 @@ class InvokeWithHelper { args, &exp, &action, &is_excessive, &ss, &why); ss << " Function call: " << mocker->Name(); UniversalPrinter::Print(args, &ss); + // In case the action deletes a piece of the expectation, we + // generate the message beforehand. + if (found && !is_excessive) { + exp->DescribeLocationTo(&loc); + } Result result = action.IsDoDefault() ? mocker->PerformDefaultAction(args, ss.str()) : action.Perform(args); @@ -1449,8 +1455,6 @@ class InvokeWithHelper { } else { // We had an expected call and the matching expectation is // described in ss. - ::std::stringstream loc; - exp->DescribeLocationTo(&loc); Log(INFO, loc.str() + ss.str(), 3); } } else { @@ -1494,6 +1498,7 @@ class InvokeWithHelper { bool is_excessive = false; ::std::stringstream ss; ::std::stringstream why; + ::std::stringstream loc; Action action; Expectation* exp; @@ -1504,6 +1509,11 @@ class InvokeWithHelper { ss << " Function call: " << mocker->Name(); UniversalPrinter::Print(args, &ss); ss << "\n" << why.str(); + // In case the action deletes a piece of the expectation, we + // generate the message beforehand. + if (found && !is_excessive) { + exp->DescribeLocationTo(&loc); + } if (action.IsDoDefault()) { mocker->PerformDefaultAction(args, ss.str()); } else { @@ -1518,8 +1528,6 @@ class InvokeWithHelper { } else { // We had an expected call and the matching expectation is // described in ss. - ::std::stringstream loc; - exp->DescribeLocationTo(&loc); Log(INFO, loc.str() + ss.str(), 3); } } else { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 4e330f0b..287a63e2 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1304,7 +1304,24 @@ TEST(DeletingMockEarlyTest, Success2) { delete b2; } -// Tests that calls that violates the original spec yield failures. +// Tests that it's OK to delete a mock object itself in its action. + +ACTION_P(Delete, ptr) { delete ptr; } + +TEST(DeletingMockEarlyTest, CanDeleteSelfInActionReturningVoid) { + MockA* const a = new MockA; + EXPECT_CALL(*a, DoA(_)).WillOnce(Delete(a)); + a->DoA(42); // This will cause a to be deleted. +} + +TEST(DeletingMockEarlyTest, CanDeleteSelfInActionReturningValue) { + MockA* const a = new MockA; + EXPECT_CALL(*a, ReturnResult(_)) + .WillOnce(DoAll(Delete(a), Return(Result()))); + a->ReturnResult(42); // This will cause a to be deleted. +} + +// Tests that calls that violate the original spec yield failures. TEST(DeletingMockEarlyTest, Failure1) { MockB* const b1 = new MockB; MockA* const a = new MockA; @@ -1330,7 +1347,7 @@ TEST(DeletingMockEarlyTest, Failure1) { delete b2; } -// Tests that calls that violates the original spec yield failures. +// Tests that calls that violate the original spec yield failures. TEST(DeletingMockEarlyTest, Failure2) { MockB* const b1 = new MockB; MockA* const a = new MockA; -- cgit v1.2.3 From 93ad3551c060599af0d4789ee0584f1652abf80b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Mar 2009 01:21:45 +0000 Subject: Fixes gmock-port_test on Windows. --- test/gmock-port_test.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 5c4b3a52..2e85bccd 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -69,19 +69,19 @@ TEST(GmockCheckSyntaxTest, WorksWithSwitch) { TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; - EXPECT_DEATH(GMOCK_CHECK_(a_false_condition) << "Extra info", - // MSVC and gcc use different formats to print source - // file locations. Google Mock's failure messages use - // the same format as used by the compiler, in order - // for the IDE to recognize them. Therefore we look - // for different patterns here depending on the - // compiler. + // MSVC and gcc use different formats to print source file locations. + // Google Mock's failure messages use the same format as used by the + // compiler, in order for the IDE to recognize them. Therefore we look + // for different patterns here depending on the compiler. + const char regex[] = #ifdef _MSC_VER - "gmock-port_test\\.cc\\([0-9]+\\):" + "gmock-port_test\\.cc\\(\\d+\\):" #else - "gmock-port_test\\.cc:[0-9]+" + "gmock-port_test\\.cc:[0-9]+" #endif // _MSC_VER - ".*a_false_condition.*Extra info"); + ".*a_false_condition.*Extra info"; + + EXPECT_DEATH(GMOCK_CHECK_(a_false_condition) << "Extra info", regex); } TEST(GmockCheckDeathTest, LivesSilentlyOnSuccess) { -- cgit v1.2.3 From 5b5d62f19019a398167df1f1b59279e049bf24ce Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Mar 2009 23:37:56 +0000 Subject: Makes the code compile on Windows CE. --- include/gmock/gmock-actions.h | 12 ++++++++++++ src/gmock-printers.cc | 12 ++++++++---- src/gmock_main.cc | 13 ++++++++++++- test/gmock-actions_test.cc | 7 +++++++ test/gmock_link_test.h | 12 +++++++++++- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 823054bf..a228eea6 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -38,7 +38,11 @@ #include #include + +#ifndef _WIN32_WCE #include +#endif + #include #include @@ -601,6 +605,8 @@ class AssignAction { const T2 value_; }; +#ifndef _WIN32_WCE + // Implements the SetErrnoAndReturn action to simulate return from // various system calls and libc functions. template @@ -619,6 +625,8 @@ class SetErrnoAndReturnAction { const T result_; }; +#endif // _WIN32_WCE + // 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, @@ -878,6 +886,8 @@ PolymorphicAction > Assign(T1* ptr, T2 val) { return MakePolymorphicAction(internal::AssignAction(ptr, val)); } +#ifndef _WIN32_WCE + // Creates an action that sets errno and returns the appropriate error. template PolymorphicAction > @@ -886,6 +896,8 @@ SetErrnoAndReturn(int errval, T result) { internal::SetErrnoAndReturnAction(errval, result)); } +#endif // _WIN32_WCE + // Various overloads for InvokeWithoutArgs(). // Creates an action that invokes 'function_impl' with no argument. diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc index 495717dc..e6d4001a 100644 --- a/src/gmock-printers.cc +++ b/src/gmock-printers.cc @@ -55,7 +55,9 @@ namespace { using ::std::ostream; -#if GTEST_OS_WINDOWS +#ifdef _WIN32_WCE +#define snprintf _snprintf +#elif GTEST_OS_WINDOWS #define snprintf _snprintf_s #endif @@ -157,9 +159,11 @@ static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { *os << "\\v"; break; default: - // isprint() takes an int and requires it to be either EOF or in - // the range [0, 255]. We check that c is in this range before calling it. - if ((c & 0xFF) == c && isprint(c)) { + // Checks whether c is printable or not. Printable characters are in + // the range [0x20,0x7E]. + // We test the value of c directly instead of calling isprint(), as + // isprint() is buggy on Windows mobile. + if (0x20 <= c && c <= 0x7E) { *os << static_cast(c); } else { // Buffer size enough for the maximum number of digits and \0. diff --git a/src/gmock_main.cc b/src/gmock_main.cc index a97e9532..85689d5d 100644 --- a/src/gmock_main.cc +++ b/src/gmock_main.cc @@ -33,7 +33,18 @@ #include #include -int main(int argc, char **argv) { +// MS C++ compiler/linker has a bug on Windows (not on Windows CE), which +// causes a link error when _tmain is defined in a static library and UNICODE +// is enabled. For this reason instead of _tmain, main function is used on +// Windows. See the following link to track the current status of this bug: +// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=394464 // NOLINT +#ifdef _WIN32_WCE +#include // NOLINT + +int _tmain(int argc, TCHAR** argv) { +#else +int main(int argc, char** argv) { +#endif // _WIN32_WCE std::cout << "Running main() from gmock_main.cc\n"; // Since Google Mock depends on Google Test, InitGoogleMock() is // also responsible for initializing Google Test. Therefore there's diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 077681b0..e4939e1a 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -69,7 +69,10 @@ using testing::ReturnNull; using testing::ReturnRef; using testing::SetArgumentPointee; using testing::SetArrayArgument; + +#ifndef _WIN32_WCE using testing::SetErrnoAndReturn; +#endif // _WIN32_WCE #if GMOCK_HAS_PROTOBUF_ using testing::internal::TestMessage; @@ -951,6 +954,8 @@ TEST(AssignTest, CompatibleTypes) { EXPECT_DOUBLE_EQ(5, x); } +#ifndef _WIN32_WCE + class SetErrnoAndReturnTest : public testing::Test { protected: virtual void SetUp() { errno = 0; } @@ -976,4 +981,6 @@ TEST_F(SetErrnoAndReturnTest, CompatibleTypes) { EXPECT_EQ(EINVAL, errno); } +#endif // _WIN32_WCE + } // Unnamed namespace diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index 769c85d2..96cd79fb 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -116,7 +116,10 @@ #include +#ifndef _WIN32_WCE #include +#endif + #include #include #include @@ -161,7 +164,6 @@ using testing::ReturnNull; using testing::ReturnRef; using testing::SetArgumentPointee; using testing::SetArrayArgument; -using testing::SetErrnoAndReturn; using testing::StartsWith; using testing::StrCaseEq; using testing::StrCaseNe; @@ -173,6 +175,10 @@ using testing::WithArg; using testing::WithArgs; using testing::WithoutArgs; +#ifndef _WIN32_WCE +using testing::SetErrnoAndReturn; +#endif // _WIN32_WCE + #if GTEST_HAS_EXCEPTIONS using testing::Throw; #endif // GTEST_HAS_EXCEPTIONS @@ -290,6 +296,8 @@ TEST(LinkTest, TestSetArrayArgument) { mock.VoidFromString(&ch); } +#ifndef _WIN32_WCE + // Tests the linkage of the SetErrnoAndReturn action. TEST(LinkTest, TestSetErrnoAndReturn) { Mock mock; @@ -300,6 +308,8 @@ TEST(LinkTest, TestSetErrnoAndReturn) { errno = saved_errno; } +#endif // _WIN32_WCE + // Tests the linkage of the Invoke(function) and Invoke(object, method) actions. TEST(LinkTest, TestInvoke) { Mock mock; -- cgit v1.2.3 From da579bd6810322854e11162ad1cba23e070a522e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 17 Mar 2009 23:34:45 +0000 Subject: Adds release note for 1.1.0 and switches to use gtest 1.3.0. --- CHANGES | 11 +++++++++++ CONTRIBUTORS | 1 + README | 2 +- configure.ac | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index be9b0ac2..8b62defa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,14 @@ +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-up. + Changes for 1.0.0: * Initial Open Source release of Google Mock diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 50209471..a661d8fa 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -25,6 +25,7 @@ Markus Heule Matthew Simmons Mike Bland Neal Norwitz +Nermin Ozkiranartli Owen Carlsen Paneendra Ba Paul Menage diff --git a/README b/README index 9498041a..604c0130 100644 --- a/README +++ b/README @@ -41,7 +41,7 @@ with Google Test (http://code.google.com/p/googletest/), although eventually we plan to support other C++ testing frameworks. You can use either the copy of Google Test that comes with Google Mock, or a compatible version you already have. This version of Google Mock -requires Google Test 1.2.1. +requires Google Test 1.3.0. Google Mock depends on advanced C++ features and thus requires a more modern compiler. The following are needed to use Google Mock: diff --git a/configure.ac b/configure.ac index 65a48b4a..c317979f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_INIT([Google C++ Mocking Framework], - [1.0.0], + [1.1.0], [googlemock@googlegroups.com], [gmock]) -- cgit v1.2.3 From 62417be8f3dd068abefbae3920c7ad5697342cf0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 19 Mar 2009 18:39:41 +0000 Subject: Fixes outdated info in README about compatibility with other testing frameworks. --- README | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README b/README index 604c0130..f14279ce 100644 --- a/README +++ b/README @@ -36,13 +36,18 @@ License, which is different from Google Mock's license. Requirements ------------ Google Mock is not a testing framework itself. Instead, it needs a -testing framework for writing tests. Currently Google Mock only works -with Google Test (http://code.google.com/p/googletest/), although -eventually we plan to support other C++ testing frameworks. You can -use either the copy of Google Test that comes with Google Mock, or a +testing framework for writing tests. It works with Google Test +(http://code.google.com/p/googletest/) out of the box. You can use +either the copy of Google Test that comes with Google Mock, or a compatible version you already have. This version of Google Mock requires Google Test 1.3.0. +You can also easily configure Google Mock to work with another testing +framework of your choice; although it will still need Google Test as +an internal dependency. Please read +http://code.google.com/p/googlemock/wiki/ForDummies#Using_Google_Mock_with_Any_Testing_Framework +for how to do it. + Google Mock depends on advanced C++ features and thus requires a more modern compiler. The following are needed to use Google Mock: -- cgit v1.2.3 From 68be111b4c82d3422ba2b83a8651033300ad4900 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 25 Mar 2009 03:56:48 +0000 Subject: Allows mock methods overloaded on argument number or the const-ness of this object to appear on the same source line. --- include/gmock/gmock-generated-function-mockers.h | 133 +++++++++++---------- .../gmock/gmock-generated-function-mockers.h.pump | 11 +- test/gmock-generated-function-mockers_test.cc | 40 +++++++ 3 files changed, 118 insertions(+), 66 deletions(-) diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 870c53db..b6c1d82e 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -297,7 +297,8 @@ using internal::FunctionMocker; // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MOCKER_(Method) GMOCK_CONCAT_TOKEN_(gmock_##Method##_, __LINE__) +#define GMOCK_MOCKER_(arity, constness, Method) \ + GMOCK_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD0_(tn, constness, ct, Method, F) \ @@ -305,14 +306,14 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 0, \ this_method_does_not_take_0_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(); \ + GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(0, constness, Method).Invoke(); \ } \ ::testing::MockSpec& \ gmock_##Method() constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(); \ + return GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this).With(); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(0, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD1_(tn, constness, ct, Method, F) \ @@ -320,14 +321,15 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 1, \ this_method_does_not_take_1_argument); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1); \ + GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \ } \ ::testing::MockSpec& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1); \ + return GMOCK_MOCKER_(1, constness, \ + Method).RegisterOwner(this).With(gmock_a1); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(1, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD2_(tn, constness, ct, Method, F) \ @@ -336,15 +338,16 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 2, \ this_method_does_not_take_2_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2); \ + GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \ } \ ::testing::MockSpec& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ GMOCK_MATCHER_(tn, F, 2) gmock_a2) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \ + return GMOCK_MOCKER_(2, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(2, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD3_(tn, constness, ct, Method, F) \ @@ -354,17 +357,18 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 3, \ this_method_does_not_take_3_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3); \ + GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \ + gmock_a3); \ } \ ::testing::MockSpec& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ GMOCK_MATCHER_(tn, F, 3) gmock_a3) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3); \ + return GMOCK_MOCKER_(3, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(3, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD4_(tn, constness, ct, Method, F) \ @@ -375,19 +379,20 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 4, \ this_method_does_not_take_4_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4); \ + 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& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ GMOCK_MATCHER_(tn, F, 4) gmock_a4) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4); \ + return GMOCK_MOCKER_(4, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(4, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD5_(tn, constness, ct, Method, F) \ @@ -399,9 +404,9 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 5, \ this_method_does_not_take_5_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5); \ + 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& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ @@ -409,10 +414,11 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ GMOCK_MATCHER_(tn, F, 5) gmock_a5) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5); \ + return GMOCK_MOCKER_(5, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(5, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD6_(tn, constness, ct, Method, F) \ @@ -425,9 +431,9 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 6, \ this_method_does_not_take_6_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6); \ + 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& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ @@ -436,10 +442,11 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ GMOCK_MATCHER_(tn, F, 6) gmock_a6) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ + return GMOCK_MOCKER_(6, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(6, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD7_(tn, constness, ct, Method, F) \ @@ -453,9 +460,9 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 7, \ this_method_does_not_take_7_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + 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& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ @@ -465,10 +472,11 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ GMOCK_MATCHER_(tn, F, 7) gmock_a7) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + return GMOCK_MOCKER_(7, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(7, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD8_(tn, constness, ct, Method, F) \ @@ -483,9 +491,9 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 8, \ this_method_does_not_take_8_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + 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& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ @@ -496,10 +504,11 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ GMOCK_MATCHER_(tn, F, 8) gmock_a8) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + return GMOCK_MOCKER_(8, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(8, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD9_(tn, constness, ct, Method, F) \ @@ -515,9 +524,10 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 9, \ this_method_does_not_take_9_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9); \ + 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& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ @@ -529,11 +539,11 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ GMOCK_MATCHER_(tn, F, 9) gmock_a9) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ - gmock_a9); \ + return GMOCK_MOCKER_(9, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(9, constness, Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD10_(tn, constness, ct, Method, F) \ @@ -550,9 +560,9 @@ using internal::FunctionMocker; GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 10, \ this_method_does_not_take_10_arguments); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + 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& \ @@ -566,11 +576,12 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ GMOCK_MATCHER_(tn, F, 9) gmock_a9, \ GMOCK_MATCHER_(tn, F, 10) gmock_a10) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + return GMOCK_MOCKER_(10, constness, \ + Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ + gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ gmock_a10); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_(10, constness, Method) #define MOCK_METHOD0(m, F) GMOCK_METHOD0_(, , , m, F) #define MOCK_METHOD1(m, F) GMOCK_METHOD1_(, , , m, F) diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index a9abc973..54b848f6 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -118,7 +118,8 @@ using internal::FunctionMocker; // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MOCKER_(Method) GMOCK_CONCAT_TOKEN_(gmock_##Method##_, __LINE__) +#define GMOCK_MOCKER_(arity, constness, Method) \ + GMOCK_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) $for i [[ @@ -134,14 +135,14 @@ $var matcher_as = [[$for j, \ GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == $i, \ this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ - GMOCK_MOCKER_(Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(Method).Invoke($as); \ + GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \ + return GMOCK_MOCKER_($i, constness, Method).Invoke($as); \ } \ ::testing::MockSpec& \ gmock_##Method($matcher_as) constness { \ - return GMOCK_MOCKER_(Method).RegisterOwner(this).With($as); \ + return GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this).With($as); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(Method) + mutable ::testing::FunctionMocker GMOCK_MOCKER_($i, constness, Method) ]] diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index 431cbd62..7267c10e 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -422,5 +422,45 @@ TEST(TemplateMockTestWithCallType, Works) { } #endif // GTEST_OS_WINDOWS +#define MY_MOCK_METHODS1_ \ + MOCK_METHOD0(Overloaded, void()); \ + MOCK_CONST_METHOD1(Overloaded, int(int n)); \ + MOCK_METHOD2(Overloaded, bool(bool f, int n)) + +class MockOverloadedOnArgNumber { + public: + MY_MOCK_METHODS1_; +}; + +TEST(OverloadedMockMethodTest, CanOverloadOnArgNumberInMacroBody) { + MockOverloadedOnArgNumber mock; + EXPECT_CALL(mock, Overloaded()); + EXPECT_CALL(mock, Overloaded(1)).WillOnce(Return(2)); + EXPECT_CALL(mock, Overloaded(true, 1)).WillOnce(Return(true)); + + mock.Overloaded(); + EXPECT_EQ(2, mock.Overloaded(1)); + EXPECT_TRUE(mock.Overloaded(true, 1)); +} + +#define MY_MOCK_METHODS2_ \ + MOCK_CONST_METHOD1(Overloaded, int(int n)); \ + MOCK_METHOD1(Overloaded, int(int n)); + +class MockOverloadedOnConstness { + public: + MY_MOCK_METHODS2_; +}; + +TEST(OverloadedMockMethodTest, CanOverloadOnConstnessInMacroBody) { + MockOverloadedOnConstness mock; + const MockOverloadedOnConstness* const_mock = &mock; + EXPECT_CALL(mock, Overloaded(1)).WillOnce(Return(2)); + EXPECT_CALL(*const_mock, Overloaded(1)).WillOnce(Return(3)); + + EXPECT_EQ(2, mock.Overloaded(1)); + EXPECT_EQ(3, const_mock->Overloaded(1)); +} + } // namespace gmock_generated_function_mockers_test } // namespace testing -- cgit v1.2.3 From 3fbd2dd020819fcfd7cef2aa6a17fad73c41a0ee Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 26 Mar 2009 19:06:45 +0000 Subject: Makes gmock compile with gcc -Wall -Wextra -Wno-unused-parameter. --- include/gmock/gmock-actions.h | 4 ++-- include/gmock/gmock-generated-actions.h | 3 +-- include/gmock/gmock-generated-actions.h.pump | 3 ++- include/gmock/gmock-matchers.h | 19 ++++++++++--------- make/Makefile | 2 +- test/gmock_link_test.h | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index a228eea6..a283ed73 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -597,7 +597,7 @@ class AssignAction { AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} template - void Perform(const ArgumentTuple &args) const { + void Perform(const ArgumentTuple& /* args */) const { *ptr_ = value_; } private: @@ -616,7 +616,7 @@ class SetErrnoAndReturnAction { : errno_(errno_value), result_(result) {} template - Result Perform(const ArgumentTuple &args) const { + Result Perform(const ArgumentTuple& /* args */) const { errno = errno_; return result_; } diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index c2e155c2..60b5dc57 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -749,7 +749,7 @@ class SelectArgs::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { + static SelectedArgs Select(const ArgumentTuple& /* args */) { using ::std::tr1::get; return SelectedArgs(); } @@ -934,7 +934,6 @@ class WithArgsAction { const InnerAction action_; }; - // Does two actions sequentially. Used for implementing the DoAll(a1, // a2, ...) action. template diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 26f9319d..3854279e 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -314,7 +314,8 @@ class SelectArgs::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { + static SelectedArgs Select(const ArgumentTuple& [[]] +$if i == 1 [[/* args */]] $else [[args]]) { using ::std::tr1::get; return SelectedArgs($for j1, [[get(args)]]); } diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index e6af144c..f764344d 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -90,7 +90,7 @@ class MatcherInterface { // Explains why x matches, or doesn't match, the matcher. Override // this to provide any additional information that helps a user // understand the match result. - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + virtual void ExplainMatchResultTo(T /* x */, ::std::ostream* /* os */) const { // By default, nothing more needs to be explained, as Google Mock // has already printed the value of x when this function is // called. @@ -146,8 +146,9 @@ class MatcherBase { // The default implementation of ExplainMatchResultTo() for // polymorphic matchers. template -inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& impl, const T& x, - ::std::ostream* os) { +inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, + const T& /* x */, + ::std::ostream* /* os */) { // By default, nothing more needs to be said, as Google Mock already // prints the value of x elsewhere. } @@ -390,15 +391,15 @@ template <> class TuplePrefix<0> { public: template - static bool Matches(const MatcherTuple& matcher_tuple, - const ValueTuple& value_tuple) { + static bool Matches(const MatcherTuple& /* matcher_tuple */, + const ValueTuple& /* value_tuple */) { return true; } template - static void DescribeMatchFailuresTo(const MatcherTuple& matchers, - const ValueTuple& values, - ::std::ostream* os) {} + static void DescribeMatchFailuresTo(const MatcherTuple& /* matchers */, + const ValueTuple& /* values */, + ::std::ostream* /* os */) {} }; // TupleMatches(matcher_tuple, value_tuple) returns true iff all @@ -495,7 +496,7 @@ class MatcherCastImpl > { template class AnyMatcherImpl : public MatcherInterface { public: - virtual bool Matches(T x) const { return true; } + virtual bool Matches(T /* x */) 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 diff --git a/make/Makefile b/make/Makefile index 85c8b38b..0c30ebfc 100644 --- a/make/Makefile +++ b/make/Makefile @@ -31,7 +31,7 @@ CPPFLAGS += -I$(GMOCK_DIR) -I$(GMOCK_DIR)/include \ -I$(GTEST_DIR) -I$(GTEST_DIR)/include # Flags passed to the C++ compiler. -CXXFLAGS += -g +CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter # All tests produced by this Makefile. Remember to add new tests you # created to the list. diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index 96cd79fb..4e0adb71 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -501,7 +501,7 @@ TEST(LinkTest, TestMatcherRef) { // Tests the linkage of the TypedEq matcher. TEST(LinkTest, TestMatcherTypedEq) { Mock mock; - unsigned long a = 0; + long a = 0; ON_CALL(mock, VoidFromIntRef(TypedEq(a))).WillByDefault(Return()); } -- cgit v1.2.3 From 946bc64fcf473b1bd87c51d4320d9483e270d9d2 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 31 Mar 2009 00:05:30 +0000 Subject: Fixes an error when compiling with gcc 4.4. --- include/gmock/gmock-spec-builders.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 77b50f80..3b4c0853 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1083,7 +1083,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // called by the ON_CALL() and EXPECT_CALL() macros. FunctionMocker& RegisterOwner(const void* mock_obj) { Mock::Register(mock_obj, this); - return *down_cast*>(this); + return *::testing::internal::down_cast*>(this); } // The following two functions are from UntypedFunctionMockerBase. -- cgit v1.2.3 From 7e571ef537f0eb17db4bbaf8a9c1a41a2839ab81 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 31 Mar 2009 18:26:29 +0000 Subject: Makes googlemock compile with gcc 3.3. --- include/gmock/gmock-printers.h | 87 ++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 28e904c3..fa510ba2 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -36,11 +36,19 @@ // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // -// It uses the << operator when possible, and prints the bytes in the -// object otherwise. A user can override its behavior for a class -// type Foo by defining either operator<<(::std::ostream&, const Foo&) -// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that -// defines Foo. If both are defined, PrintTo() takes precedence. +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. // // To aid debugging: when T is a reference type, the address of the // value is also printed; when T is a (const) char pointer, both the @@ -76,12 +84,6 @@ #include #include -// Makes sure there is at least one << operator declared in the global -// namespace. This has no implementation and won't be called -// anywhere. We just need the declaration such that we can say "using -// ::operator <<;" in the definition of PrintTo() below. -void operator<<(::testing::internal::Unused, int); - namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are @@ -152,7 +154,48 @@ template } } // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} +} // namespace testing_internal + +namespace testing { namespace internal { // UniversalPrinter::Print(value, ostream_ptr) prints the given @@ -194,27 +237,7 @@ void DefaultPrintTo(IsContainer, const C& container, ::std::ostream* os) { // Used to print a value when the user doesn't define PrintTo() for it. template void DefaultPrintTo(IsNotContainer, const T& value, ::std::ostream* os) { - // If T has its << operator defined in the global namespace, which - // is not recommended but sometimes unavoidable (as in - // util/gtl/stl_logging-inl.h), the following statement makes it - // visible in this function. - // - // Without the statement, << in the global namespace would be hidden - // by the one in ::testing::internal2, due to the next using - // statement. - using ::operator <<; - - // When T doesn't come with a << operator, we want to fall back to - // the one defined in ::testing::internal2, which prints the bytes in - // the value. - using ::testing::internal2::operator <<; - - // Thanks to Koenig look-up, if type T has its own << operator - // defined in its namespace, which is the recommended way, that - // operator will be visible here. Since it is more specific than - // the generic one, it will be picked by the compiler in the - // following statement - exactly what we want. - *os << value; + ::testing_internal::DefaultPrintNonContainerTo(value, os); } // Prints the given value using the << operator if it has one; -- cgit v1.2.3 From 33c0af07c4c23b53ee52b8f5b6b45162d2db6321 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 3 Apr 2009 00:10:12 +0000 Subject: Makes gmock compile clean with gcc -Wall -Wextra. --- include/gmock/gmock-generated-actions.h | 97 ++++++++++++---------------- include/gmock/gmock-generated-actions.h.pump | 15 +++-- make/Makefile | 2 +- 3 files changed, 54 insertions(+), 60 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 60b5dc57..e3f3dc27 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -1557,6 +1557,20 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, // 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_ + #define ACTION(name)\ class name##Action {\ public:\ @@ -1595,11 +1609,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, typename arg6_type, typename arg7_type, typename arg8_type, \ typename arg9_type>\ typename ::testing::internal::Function::Result\ - name##Action::\ - gmock_Impl::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 + name##Action::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P(name, p0)\ template \ @@ -1644,11 +1655,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, typename arg6_type, typename arg7_type, typename arg8_type, \ typename arg9_type>\ typename ::testing::internal::Function::Result\ - name##ActionP::\ - gmock_Impl::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 + name##ActionP::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P2(name, p0, p1)\ template \ @@ -1698,11 +1706,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, typename arg6_type, typename arg7_type, typename arg8_type, \ typename arg9_type>\ typename ::testing::internal::Function::Result\ - name##ActionP2::\ - gmock_Impl::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 + name##ActionP2::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P3(name, p0, p1, p2)\ template \ @@ -1754,11 +1759,9 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, typename arg6_type, typename arg7_type, typename arg8_type, \ typename arg9_type>\ typename ::testing::internal::Function::Result\ - name##ActionP3::\ - gmock_Impl::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 + name##ActionP3::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P4(name, p0, p1, p2, p3)\ template \ typename ::testing::internal::Function::Result\ - name##ActionP4::\ - gmock_Impl::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 + name##ActionP4::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P5(name, p0, p1, p2, p3, p4)\ template \ typename ::testing::internal::Function::Result\ - name##ActionP5::\ - gmock_Impl::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 + 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 \ typename ::testing::internal::Function::Result\ name##ActionP6::\ - gmock_Impl::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 + p5##_type>::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\ template \ typename ::testing::internal::Function::Result\ name##ActionP7::\ - gmock_Impl::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 + p5##_type, p6##_type>::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 \ typename ::testing::internal::Function::Result\ name##ActionP8::\ - gmock_Impl::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 + p5##_type, p6##_type, \ + p7##_type>::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 \ typename ::testing::internal::Function::Result\ name##ActionP9::\ - gmock_Impl::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 + p5##_type, p6##_type, p7##_type, \ + p8##_type>::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 \ typename ::testing::internal::Function::Result\ name##ActionP10::\ - gmock_Impl::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 + p5##_type, p6##_type, p7##_type, p8##_type, \ + p9##_type>::gmock_Impl::gmock_PerformImpl(\ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const // TODO(wan@google.com): move the following to a different .h file // such that we don't have to run 'pump' every time the code is diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 3854279e..67359e64 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -709,6 +709,15 @@ $range j2 2..i // 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_]] + + $for i [[ @@ -735,7 +744,6 @@ $var param_field_decls2 = [[$for j ]]]] $var params = [[$for j, [[p$j]]]] $var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] -$range k 0..n-1 $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]] @@ -771,9 +779,8 @@ $arg_types_and_names) const;\$param_field_decls template \ template <$typename_arg_types>\ typename ::testing::internal::Function::Result\ - $class_name$param_types::\ - gmock_Impl::gmock_PerformImpl(const args_type& args, [[]] -$arg_types_and_names) const + $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. diff --git a/make/Makefile b/make/Makefile index 0c30ebfc..ee0527e1 100644 --- a/make/Makefile +++ b/make/Makefile @@ -31,7 +31,7 @@ CPPFLAGS += -I$(GMOCK_DIR) -I$(GMOCK_DIR)/include \ -I$(GTEST_DIR) -I$(GTEST_DIR)/include # Flags passed to the C++ compiler. -CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter +CXXFLAGS += -g -Wall -Wextra # All tests produced by this Makefile. Remember to add new tests you # created to the list. -- cgit v1.2.3 From 56fe7460a898f8d0dea4869ab4ff9c598ba90085 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 9 Apr 2009 03:01:25 +0000 Subject: Adds fuse_gmock_files.py to fuse all Google Mock and Google Test source files (by Zhanyong Wan). --- Makefile.am | 5 + scripts/fuse_gmock_files.py | 240 ++++++++++++++++++++++++++++++++++++++++++++ scripts/test/Makefile | 57 +++++++++++ 3 files changed, 302 insertions(+) create mode 100755 scripts/fuse_gmock_files.py create mode 100644 scripts/test/Makefile diff --git a/Makefile.am b/Makefile.am index 08a6b2bc..f70a8085 100644 --- a/Makefile.am +++ b/Makefile.am @@ -173,6 +173,11 @@ EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \ include/gmock/gmock-generated-nice-strict.h.pump \ include/gmock/internal/gmock-generated-internal-utils.h.pump +# Script for fusing Google Mock and Google Test source files. +EXTRA_DIST += \ + scripts/fuse_gmock_files.py \ + scripts/test/Makefile + # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ scripts/generator/COPYING \ diff --git a/scripts/fuse_gmock_files.py b/scripts/fuse_gmock_files.py new file mode 100755 index 00000000..4e892e9a --- /dev/null +++ b/scripts/fuse_gmock_files.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python +# +# Copyright 2009, 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. + +"""fuse_gmock_files.py v0.1.0 +Fuses Google Mock and Google Test source code into two .h files and a .cc file. + +SYNOPSIS + fuse_gmock_files.py [GMOCK_ROOT_DIR] OUTPUT_DIR + + Scans GMOCK_ROOT_DIR for Google Mock and Google Test source + code, assuming Google Test is in the GMOCK_ROOT_DIR/gtest + sub-directory, and generates three files: + OUTPUT_DIR/gtest/gtest.h, OUTPUT_DIR/gmock/gmock.h, and + OUTPUT_DIR/gmock-gtest-all.cc. Then you can build your tests + by adding OUTPUT_DIR to the include search path and linking + with OUTPUT_DIR/gmock-gtest-all.cc. These three files contain + everything you need to use Google Mock. Hence you can + "install" Google Mock by copying them to wherever you want. + + GMOCK_ROOT_DIR can be omitted and defaults to the parent + directory of the directory holding this script. + +EXAMPLES + ./fuse_gmock_files.py fused_gmock + ./fuse_gmock_files.py path/to/unpacked/gmock fused_gmock + +This tool is experimental. In particular, it assumes that there is no +conditional inclusion of Google Mock or Google Test headers. Please +report any problems to googlemock@googlegroups.com. You can read +http://code.google.com/p/googlemock/wiki/CookBook for more +information. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sets +import sys + +# We assume that this file is in the scripts/ directory in the Google +# Mock root directory. +DEFAULT_GMOCK_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') + +# We need to call into gtest/scripts/fuse_gtest_files.py. +sys.path.append(os.path.join(DEFAULT_GMOCK_ROOT_DIR, 'gtest/scripts')) +import fuse_gtest_files +gtest = fuse_gtest_files + +# Regex for matching '#include '. +INCLUDE_GMOCK_FILE_REGEX = re.compile(r'^\s*#\s*include\s*<(gmock/.+)>') + +# Where to find the source seed files. +GMOCK_H_SEED = 'include/gmock/gmock.h' +GMOCK_ALL_CC_SEED = 'src/gmock-all.cc' + +# Where to put the generated files. +GTEST_H_OUTPUT = 'gtest/gtest.h' +GMOCK_H_OUTPUT = 'gmock/gmock.h' +GMOCK_GTEST_ALL_CC_OUTPUT = 'gmock-gtest-all.cc' + + +def GetGTestRootDir(gmock_root): + """Returns the root directory of Google Test.""" + + return os.path.join(gmock_root, 'gtest') + + +def ValidateGMockRootDir(gmock_root): + """Makes sure gmock_root points to a valid gmock root directory. + + The function aborts the program on failure. + """ + + gtest.ValidateGTestRootDir(GetGTestRootDir(gmock_root)) + gtest.VerifyFileExists(gmock_root, GMOCK_H_SEED) + gtest.VerifyFileExists(gmock_root, GMOCK_ALL_CC_SEED) + + +def ValidateOutputDir(output_dir): + """Makes sure output_dir points to a valid output directory. + + The function aborts the program on failure. + """ + + gtest.VerifyOutputFile(output_dir, gtest.GTEST_H_OUTPUT) + gtest.VerifyOutputFile(output_dir, GMOCK_H_OUTPUT) + gtest.VerifyOutputFile(output_dir, GMOCK_GTEST_ALL_CC_OUTPUT) + + +def FuseGMockH(gmock_root, output_dir): + """Scans folder gmock_root to generate gmock/gmock.h in output_dir.""" + + output_file = file(os.path.join(output_dir, GMOCK_H_OUTPUT), 'w') + processed_files = sets.Set() # Holds all gmock headers we've processed. + + def ProcessFile(gmock_header_path): + """Processes the given gmock header file.""" + + # We don't process the same header twice. + if gmock_header_path in processed_files: + return + + processed_files.add(gmock_header_path) + + # Reads each line in the given gmock header. + for line in file(os.path.join(gmock_root, gmock_header_path), 'r'): + m = INCLUDE_GMOCK_FILE_REGEX.match(line) + if m: + # It's '#include ' - let's process it recursively. + ProcessFile('include/' + m.group(1)) + else: + m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + # It's '#include '. We translate it to + # , regardless of what foo is, since all + # gtest headers are fused into gtest/gtest.h. + + # There is no need to #include gtest.h twice. + if not gtest.GTEST_H_SEED in processed_files: + processed_files.add(gtest.GTEST_H_SEED) + output_file.write('#include <%s>\n' % (gtest.GTEST_H_OUTPUT,)) + else: + # Otherwise we copy the line unchanged to the output file. + output_file.write(line) + + ProcessFile(GMOCK_H_SEED) + output_file.close() + + +def FuseGMockAllCcToFile(gmock_root, output_file): + """Scans folder gmock_root to fuse gmock-all.cc into output_file.""" + + processed_files = sets.Set() + + def ProcessFile(gmock_source_file): + """Processes the given gmock source file.""" + + # We don't process the same #included file twice. + if gmock_source_file in processed_files: + return + + processed_files.add(gmock_source_file) + + # Reads each line in the given gmock source file. + for line in file(os.path.join(gmock_root, gmock_source_file), 'r'): + m = INCLUDE_GMOCK_FILE_REGEX.match(line) + if m: + # It's '#include '. We treat it as '#include + # ', as all other gmock headers are being fused + # into gmock.h and cannot be #included directly. + + # There is no need to #include more than once. + if not GMOCK_H_SEED in processed_files: + processed_files.add(GMOCK_H_SEED) + output_file.write('#include <%s>\n' % (GMOCK_H_OUTPUT,)) + else: + m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + # It's '#include '. + # There is no need to #include gtest.h as it has been + # #included by gtest-all.cc. + pass + else: + m = gtest.INCLUDE_SRC_FILE_REGEX.match(line) + if m: + # It's '#include "src/foo"' - let's process it recursively. + ProcessFile(m.group(1)) + else: + # Otherwise we copy the line unchanged to the output file. + output_file.write(line) + + ProcessFile(GMOCK_ALL_CC_SEED) + + +def FuseGMockGTestAllCc(gmock_root, output_dir): + """Scans folder gmock_root to generate gmock-gtest-all.cc in output_dir.""" + + output_file = file(os.path.join(output_dir, GMOCK_GTEST_ALL_CC_OUTPUT), 'w') + # First, fuse gtest-all.cc into gmock-gtest-all.cc. + gtest.FuseGTestAllCcToFile(GetGTestRootDir(gmock_root), output_file) + # Next, append fused gmock-all.cc to gmock-gtest-all.cc. + FuseGMockAllCcToFile(gmock_root, output_file) + output_file.close() + + +def FuseGMock(gmock_root, output_dir): + """Fuses gtest.h, gmock.h, and gmock-gtest-all.h.""" + + ValidateGMockRootDir(gmock_root) + ValidateOutputDir(output_dir) + + gtest.FuseGTestH(GetGTestRootDir(gmock_root), output_dir) + FuseGMockH(gmock_root, output_dir) + FuseGMockGTestAllCc(gmock_root, output_dir) + + +def main(): + argc = len(sys.argv) + if argc == 2: + # fuse_gmock_files.py OUTPUT_DIR + FuseGMock(DEFAULT_GMOCK_ROOT_DIR, sys.argv[1]) + elif argc == 3: + # fuse_gmock_files.py GMOCK_ROOT_DIR OUTPUT_DIR + FuseGMock(sys.argv[1], sys.argv[2]) + else: + print __doc__ + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/scripts/test/Makefile b/scripts/test/Makefile new file mode 100644 index 00000000..8edaea06 --- /dev/null +++ b/scripts/test/Makefile @@ -0,0 +1,57 @@ +# A Makefile for fusing Google Mock and building a sample test against it. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make check - makes everything and runs the built sample test. +# make clean - removes all files generated by make. + +# Points to the root of fused Google Mock, relative to where this file is. +FUSED_GMOCK_DIR = output + +# Paths to the fused gmock files. +FUSED_GTEST_H = $(FUSED_GMOCK_DIR)/gtest/gtest.h +FUSED_GMOCK_H = $(FUSED_GMOCK_DIR)/gmock/gmock.h +FUSED_GMOCK_GTEST_ALL_CC = $(FUSED_GMOCK_DIR)/gmock-gtest-all.cc + +# Where to find the gmock_test.cc. +GMOCK_TEST_CC = ../../test/gmock_test.cc + +# Where to find gmock_main.cc. +GMOCK_MAIN_CC = ../../src/gmock_main.cc + +# Flags passed to the preprocessor. +CPPFLAGS += -I$(FUSED_GMOCK_DIR) + +# Flags passed to the C++ compiler. +CXXFLAGS += -g + +all : gmock_test + +check : all + ./gmock_test + +clean : + rm -rf $(FUSED_GMOCK_DIR) gmock_test *.o + +$(FUSED_GTEST_H) : + ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) + +$(FUSED_GMOCK_H) : + ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) + +$(FUSED_GMOCK_GTEST_ALL_CC) : + ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) + +gmock-gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(FUSED_GMOCK_GTEST_ALL_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GMOCK_GTEST_ALL_CC) + +gmock_main.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_MAIN_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_MAIN_CC) + +gmock_test.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_TEST_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_TEST_CC) + +gmock_test : gmock_test.o gmock-gtest-all.o gmock_main.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ -- cgit v1.2.3 From 1c8eb1c059d6727d9fcf45864dc6efa3d844e184 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 9 Apr 2009 07:29:58 +0000 Subject: Adds actions ReturnNew(...) and DeleteArg(), by Jason Hsueh. --- include/gmock/gmock-generated-actions.h | 341 +++++++++++++++++++++++++++ include/gmock/gmock-generated-actions.h.pump | 69 ++++++ test/gmock-generated-actions_test.cc | 103 ++++++++ 3 files changed, 513 insertions(+) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index e3f3dc27..26308bf4 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -2320,6 +2320,240 @@ ACTION_P(SetArg0Referee, value) { arg0 = value; } +// ReturnNewAction creates and returns a new instance of an object each time +// it is performed. It is overloaded to work with constructors that take +// different numbers of arguments. +// Returns a new instance of T using a nullary constructor with the given +// arguments. +template +class ReturnNewAction0 { + public: + ReturnNewAction0() {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(); + } + private: +}; + +// Returns a new instance of T using a unary constructor with the given +// arguments. +template +class ReturnNewAction1 { + public: + explicit ReturnNewAction1(A1 a1) : arg1_(a1) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_); + } + private: + const A1 arg1_; +}; + +// Returns a new instance of T using a binary constructor with the given +// arguments. +template +class ReturnNewAction2 { + public: + ReturnNewAction2(A1 a1, A2 a2) : arg1_(a1), arg2_(a2) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_); + } + private: + const A1 arg1_; + const A2 arg2_; +}; + +// Returns a new instance of T using a ternary constructor with the given +// arguments. +template +class ReturnNewAction3 { + public: + ReturnNewAction3(A1 a1, A2 a2, A3 a3) : arg1_(a1), arg2_(a2), arg3_(a3) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; +}; + +// Returns a new instance of T using a 4-ary constructor with the given +// arguments. +template +class ReturnNewAction4 { + public: + ReturnNewAction4(A1 a1, A2 a2, A3 a3, A4 a4) : arg1_(a1), arg2_(a2), + arg3_(a3), arg4_(a4) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; +}; + +// Returns a new instance of T using a 5-ary constructor with the given +// arguments. +template +class ReturnNewAction5 { + public: + ReturnNewAction5(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : arg1_(a1), arg2_(a2), + arg3_(a3), arg4_(a4), arg5_(a5) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; +}; + +// Returns a new instance of T using a 6-ary constructor with the given +// arguments. +template +class ReturnNewAction6 { + public: + ReturnNewAction6(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : arg1_(a1), + arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; +}; + +// Returns a new instance of T using a 7-ary constructor with the given +// arguments. +template +class ReturnNewAction7 { + public: + ReturnNewAction7(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; +}; + +// Returns a new instance of T using a 8-ary constructor with the given +// arguments. +template +class ReturnNewAction8 { + public: + ReturnNewAction8(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, + A8 a8) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7), arg8_(a8) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; +}; + +// Returns a new instance of T using a 9-ary constructor with the given +// arguments. +template +class ReturnNewAction9 { + public: + ReturnNewAction9(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, + A9 a9) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7), arg8_(a8), arg9_(a9) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, arg9_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; + const A9 arg9_; +}; + +// Returns a new instance of T using a 10-ary constructor with the given +// arguments. +template +class ReturnNewAction10 { + public: + ReturnNewAction10(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, + A9 a9, A10 a10) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7), arg8_(a8), arg9_(a9), arg10_(a10) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, arg9_, + arg10_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; + const A9 arg9_; + const A10 arg10_; +}; + +// Deletes the object pointed to by argument #0. +ACTION(DeleteArg0) { delete arg0; } + } // namespace internal // Action SaveArg(pointer) saves the k-th (0-based) argument of the @@ -2338,6 +2572,113 @@ SetArgReferee(const Value& value) { return WithArg(internal::SetArg0Referee(value)); } +// 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. +template +inline PolymorphicAction > +ReturnNew() { + return MakePolymorphicAction( + internal::ReturnNewAction0()); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1) { + return MakePolymorphicAction( + internal::ReturnNewAction1(a1)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2) { + return MakePolymorphicAction( + internal::ReturnNewAction2(a1, a2)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3) { + return MakePolymorphicAction( + internal::ReturnNewAction3(a1, a2, a3)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4) { + return MakePolymorphicAction( + internal::ReturnNewAction4(a1, a2, a3, a4)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return MakePolymorphicAction( + internal::ReturnNewAction5(a1, a2, a3, a4, a5)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return MakePolymorphicAction( + internal::ReturnNewAction6(a1, a2, a3, a4, a5, + a6)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return MakePolymorphicAction( + internal::ReturnNewAction7(a1, a2, a3, a4, + a5, a6, a7)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return MakePolymorphicAction( + internal::ReturnNewAction8(a1, a2, a3, + a4, a5, a6, a7, a8)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return MakePolymorphicAction( + internal::ReturnNewAction9(a1, a2, + a3, a4, a5, a6, a7, a8, a9)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, + A10 a10) { + return MakePolymorphicAction( + internal::ReturnNewAction10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +inline internal::WithArgsAction +DeleteArg() { + return WithArg(internal::DeleteArg0()); +} + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 67359e64..942be2e5 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -806,6 +806,45 @@ ACTION_P(SetArg0Referee, value) { arg0 = value; } +// ReturnNewAction creates and returns a new instance of an object each time +// it is performed. It is overloaded to work with constructors that take +// different numbers of arguments. +$range i 0..n +$for i [[ +$var arity = [[ $if i==0 [[nullary]] + $elif i==1 [[unary]] + $elif i==2 [[binary]] + $elif i==3 [[ternary]] + $else [[$i-ary]]]] +$range j 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var args_ = [[$for j, [[arg$j[[]]_]]]] + +// Returns a new instance of T using a $arity constructor with the given +// arguments. +template +class ReturnNewAction$i { + public: + $if i==1 [[explicit ]]ReturnNewAction$i($for j, [[A$j a$j]])$if i>0 [[ : ]] +$for j, [[arg$j[[]]_(a$j)]] {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T($args_); + } + private: +$for j [[ + + const A$j arg$j[[]]_; +]] + +}; + +]] + +// Deletes the object pointed to by argument #0. +ACTION(DeleteArg0) { delete arg0; } + } // namespace internal // Action SaveArg(pointer) saves the k-th (0-based) argument of the @@ -824,6 +863,36 @@ SetArgReferee(const Value& value) { return WithArg(internal::SetArg0Referee(value)); } +// 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 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var As = [[$for j [[, A$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var as = [[$for j, [[a$j]]]] + +template +inline PolymorphicAction > +ReturnNew($Aas) { + return MakePolymorphicAction( + internal::ReturnNewAction$i($as)); +} + +]] + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +inline internal::WithArgsAction +DeleteArg() { + return WithArg(internal::DeleteArg0()); +} + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index dd25a123..922efca9 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -53,10 +53,12 @@ using testing::_; using testing::Action; using testing::ActionInterface; using testing::ByRef; +using testing::DeleteArg; using testing::DoAll; using testing::Invoke; using testing::InvokeArgument; using testing::Return; +using testing::ReturnNew; using testing::SaveArg; using testing::SetArgReferee; using testing::SetArgumentPointee; @@ -1371,6 +1373,107 @@ TEST(SetArgRefereeActionTest, WorksWithExtraArguments) { EXPECT_EQ('a', value); } +class NullaryConstructorClass { + public: + NullaryConstructorClass() : value_(123) {} + int value_; +}; + +// Tests using ReturnNew() with a nullary constructor. +TEST(ReturnNewTest, NoArgs) { + Action a = ReturnNew(); + NullaryConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(123, c->value_); + delete c; +} + +class UnaryConstructorClass { + public: + explicit UnaryConstructorClass(int value) : value_(value) {} + int value_; +}; + +// Tests using ReturnNew() with a unary constructor. +TEST(ReturnNewTest, Unary) { + Action a = ReturnNew(4000); + UnaryConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(4000, c->value_); + delete c; +} + +TEST(ReturnNewTest, UnaryWorksWhenMockMethodHasArgs) { + Action a = + ReturnNew(4000); + UnaryConstructorClass* c = a.Perform(make_tuple(false, 5)); + EXPECT_EQ(4000, c->value_); + delete c; +} + +TEST(ReturnNewTest, UnaryWorksWhenMockMethodReturnsPointerToConst) { + Action a = + ReturnNew(4000); + const UnaryConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(4000, c->value_); + delete c; +} + +class TenArgConstructorClass { + public: + TenArgConstructorClass(int a1, int a2, int a3, int a4, int a5, + int a6, int a7, int a8, int a9, int a10) + : value_(a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10) { + } + int value_; +}; + +// Tests using ReturnNew() with a 10-argument constructor. +TEST(ReturnNewTest, ConstructorThatTakes10Arguments) { + Action a = + ReturnNew(1000000000, 200000000, 30000000, + 4000000, 500000, 60000, + 7000, 800, 90, 0); + TenArgConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(1234567890, c->value_); + delete c; +} + +// A class that can be used to verify that its destructor is called: it will set +// the bool provided to the constructor to true when destroyed. +class DeletionTester { + public: + explicit DeletionTester(bool* is_deleted) + : is_deleted_(is_deleted) { + // Make sure the bit is set to false. + *is_deleted_ = false; + } + + ~DeletionTester() { + *is_deleted_ = true; + } + + private: + bool* is_deleted_; +}; + +TEST(DeleteArgActionTest, OneArg) { + bool is_deleted = false; + DeletionTester* t = new DeletionTester(&is_deleted); + const Action a1 = DeleteArg<0>(); // NOLINT + EXPECT_FALSE(is_deleted); + a1.Perform(make_tuple(t)); + EXPECT_TRUE(is_deleted); +} + +TEST(DeleteArgActionTest, TenArgs) { + bool is_deleted = false; + DeletionTester* t = new DeletionTester(&is_deleted); + const Action a1 = DeleteArg<9>(); + EXPECT_FALSE(is_deleted); + a1.Perform(make_tuple(true, 5, 6, "hi", false, 7, 8, 9, 10, t)); + EXPECT_TRUE(is_deleted); +} + #if GTEST_HAS_EXCEPTIONS TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) { -- cgit v1.2.3 From df35a763b9d98d7040a00fc1e5cffe91a80ba9e0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 22 Apr 2009 22:25:31 +0000 Subject: Implements --gmock_catch_leaked_mocks and Mock::AllowLeak. --- Makefile.am | 20 +++- include/gmock/gmock-spec-builders.h | 27 ++++- include/gmock/gmock.h | 1 + include/gmock/internal/gmock-port.h | 30 ++--- msvc/gmock-spec-builders_test.vcproj | 205 +++++++++++++++++++++++++++++++++++ msvc/gmock.sln | 6 + msvc/gmock_output_test_.vcproj | 4 +- msvc/gmock_test.vcproj | 4 - src/gmock-spec-builders.cc | 124 +++++++++++++++++++-- src/gmock.cc | 31 +++++- test/gmock-spec-builders_test.cc | 48 ++++++++ test/gmock_leak_test.py | 84 ++++++++++++++ test/gmock_leak_test_.cc | 95 ++++++++++++++++ test/gmock_output_test.py | 2 +- test/gmock_output_test_.cc | 29 +++++ test/gmock_output_test_golden.txt | 7 +- test/gmock_test.cc | 7 ++ 17 files changed, 681 insertions(+), 43 deletions(-) create mode 100755 msvc/gmock-spec-builders_test.vcproj create mode 100755 test/gmock_leak_test.py create mode 100644 test/gmock_leak_test_.cc diff --git a/Makefile.am b/Makefile.am index f70a8085..7a821a02 100644 --- a/Makefile.am +++ b/Makefile.am @@ -128,7 +128,7 @@ test_gmock_printers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la 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_main.la +test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la TESTS += test/gmock_test check_PROGRAMS += test/gmock_test @@ -147,6 +147,11 @@ dist_check_SCRIPTS = # Python modules used by multiple Python tests below. dist_check_SCRIPTS += test/gmock_test_utils.py +check_PROGRAMS += test/gmock_leak_test_ +test_gmock_leak_test__SOURCES = test/gmock_leak_test_.cc +test_gmock_leak_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la +dist_check_SCRIPTS += test/gmock_leak_test.py + check_PROGRAMS += test/gmock_output_test_ test_gmock_output_test__SOURCES = test/gmock_output_test_.cc test_gmock_output_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la @@ -155,15 +160,17 @@ EXTRA_DIST += test/gmock_output_test_golden.txt # Enable all the python driven tests when we can run them. if HAVE_PYTHON -TESTS += test/gmock_output_test.py +TESTS += \ + test/gmock_leak_test.py \ + test/gmock_output_test.py endif # Nonstandard package files for distribution. EXTRA_DIST += \ - CHANGES \ - CONTRIBUTORS \ - make/Makefile \ - src/gmock-all.cc + CHANGES \ + CONTRIBUTORS \ + make/Makefile \ + src/gmock-all.cc # Pump scripts for generating Google Mock headers. # TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump. @@ -199,4 +206,5 @@ EXTRA_DIST += \ msvc/gmock_link_test.vcproj \ msvc/gmock_main.vcproj \ msvc/gmock_output_test_.vcproj \ + msvc/gmock-spec-builders_test.vcproj \ msvc/gmock_test.vcproj diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 3b4c0853..0fc43d6d 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -246,6 +246,10 @@ class Mock { public: // The following public methods can be called concurrently. + // Tells Google Mock to ignore mock_obj when checking for leaked + // mock objects. + static void AllowLeak(const void* mock_obj); + // Verifies and clears all expectations on the given mock object. // If the expectations aren't satisfied, generates one or more // Google Test non-fatal failures and returns false. @@ -311,6 +315,13 @@ class Mock { static void Register(const void* mock_obj, internal::UntypedFunctionMockerBase* mocker); + // Tells Google Mock where in the source code mock_obj is used in an + // ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this + // information helps the user identify which object it is. + // L < g_gmock_mutex + static void RegisterUseByOnCallOrExpectCall( + const void* mock_obj, const char* file, int line); + // Unregisters a mock method; removes the owning mock object from // the registry when the last mock method associated with it has // been unregistered. This is called only in the destructor of @@ -1081,7 +1092,12 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Registers this function mocker and the mock object owning it; // returns a reference to the function mocker object. This is only // called by the ON_CALL() and EXPECT_CALL() macros. + // L < g_gmock_mutex FunctionMocker& RegisterOwner(const void* mock_obj) { + { + MutexLock l(&g_gmock_mutex); + mock_obj_ = mock_obj; + } Mock::Register(mock_obj, this); return *::testing::internal::down_cast*>(this); } @@ -1155,17 +1171,21 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { } // Adds and returns a default action spec for this mock function. + // L < g_gmock_mutex DefaultActionSpec& AddNewDefaultActionSpec( const char* file, int line, const ArgumentMatcherTuple& m) { + Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); default_actions_.push_back(DefaultActionSpec(file, line, m)); return default_actions_.back(); } // Adds and returns an expectation spec for this mock function. + // L < g_gmock_mutex Expectation& AddNewExpectation( const char* file, int line, const ArgumentMatcherTuple& m) { + Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); const linked_ptr > expectation( new Expectation(this, file, line, m)); expectations_.push_back(expectation); @@ -1314,10 +1334,13 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { } } - // Address of the mock object this mock method belongs to. + // Address of the mock object this mock method belongs to. Only + // valid after this mock method has been called or + // ON_CALL/EXPECT_CALL has been invoked on it. const void* mock_obj_; // Protected by g_gmock_mutex. - // Name of the function being mocked. + // Name of the function being mocked. Only valid after this mock + // method has been called. const char* name_; // Protected by g_gmock_mutex. // The current spec (either default action spec or expectation spec) diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index 41d175f1..22e70287 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -68,6 +68,7 @@ namespace testing { // Declares Google Mock flags that we want a user to use programmatically. +GMOCK_DECLARE_bool_(catch_leaked_mocks); GMOCK_DECLARE_string_(verbose); // Initializes Google Mock. This must be called before running the diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index cb352192..b98cb113 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -242,6 +242,21 @@ typedef ::wstring wstring; typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING +// Prints the file location in the format native to the compiler. +inline void FormatFileLocation(const char* file, int line, ::std::ostream* os) { + if (file == NULL) + file = "unknown file"; + if (line < 0) { + *os << file << ":"; + } else { +#if _MSC_VER + *os << file << "(" << line << "):"; +#else + *os << file << ":" << line << ":"; +#endif + } +} + // INTERNAL IMPLEMENTATION - DO NOT USE. // // GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition @@ -260,26 +275,13 @@ typedef ::std::wstring wstring; class GMockCheckProvider { public: GMockCheckProvider(const char* condition, const char* file, int line) { - FormatFileLocation(file, line); + FormatFileLocation(file, line, &::std::cerr); ::std::cerr << " ERROR: Condition " << condition << " failed. "; } ~GMockCheckProvider() { ::std::cerr << ::std::endl; abort(); } - void FormatFileLocation(const char* file, int line) { - if (file == NULL) - file = "unknown file"; - if (line < 0) { - ::std::cerr << file << ":"; - } else { -#if _MSC_VER - ::std::cerr << file << "(" << line << "):"; -#else - ::std::cerr << file << ":" << line << ":"; -#endif - } - } ::std::ostream& GetStream() { return ::std::cerr; } }; #define GMOCK_CHECK_(condition) \ diff --git a/msvc/gmock-spec-builders_test.vcproj b/msvc/gmock-spec-builders_test.vcproj new file mode 100755 index 00000000..84407420 --- /dev/null +++ b/msvc/gmock-spec-builders_test.vcproj @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/gmock.sln b/msvc/gmock.sln index aeb6a614..cd1502a9 100644 --- a/msvc/gmock.sln +++ b/msvc/gmock.sln @@ -11,6 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_output_test_", "gmock EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock-spec-builders_test", "gmock-spec-builders_test.vcproj", "{46972604-5BE0-4493-BAE3-878DB825FDCB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -37,6 +39,10 @@ Global {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 + {46972604-5BE0-4493-BAE3-878DB825FDCB}.Debug|Win32.ActiveCfg = Debug|Win32 + {46972604-5BE0-4493-BAE3-878DB825FDCB}.Debug|Win32.Build.0 = Debug|Win32 + {46972604-5BE0-4493-BAE3-878DB825FDCB}.Release|Win32.ActiveCfg = Release|Win32 + {46972604-5BE0-4493-BAE3-878DB825FDCB}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/msvc/gmock_output_test_.vcproj b/msvc/gmock_output_test_.vcproj index 051dd149..8e846ec1 100644 --- a/msvc/gmock_output_test_.vcproj +++ b/msvc/gmock_output_test_.vcproj @@ -172,8 +172,8 @@ diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj index 135b2e6c..60e1b4bc 100644 --- a/msvc/gmock_test.vcproj +++ b/msvc/gmock_test.vcproj @@ -226,10 +226,6 @@ RelativePath="..\test\gmock-printers_test.cc" > - - diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 353bb2df..2bb72954 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -36,9 +36,17 @@ #include +#include +#include // NOLINT +#include #include +#include #include +#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC +#include // NOLINT +#endif + namespace testing { namespace internal { @@ -148,10 +156,77 @@ void ReportUninterestingCall(CallReaction reaction, const string& msg) { namespace { typedef std::set FunctionMockers; -typedef std::map MockObjectRegistry; -// Maps a mock object to the set of mock methods it owns. Protected -// by g_gmock_mutex. +// The current state of a mock object. Such information is needed for +// detecting leaked mock objects and explicitly verifying a mock's +// expectations. +struct MockObjectState { + MockObjectState() + : first_used_file(NULL), first_used_line(-1), leakable(false) {} + + // Where in the source file an ON_CALL or EXPECT_CALL is first + // invoked on this mock object. + const char* first_used_file; + int first_used_line; + bool leakable; // true iff it's OK to leak the object. + FunctionMockers function_mockers; // All registered methods of the object. +}; + +// A global registry holding the state of all mock objects that are +// alive. A mock object is added to this registry the first time +// Mock::AllowLeak(), ON_CALL(), or EXPECT_CALL() is called on it. It +// is removed from the registry in the mock object's destructor. +class MockObjectRegistry { + public: + // Maps a mock object (identified by its address) to its state. + typedef std::map StateMap; + + // This destructor will be called when a program exits, after all + // tests in it have been run. By then, there should be no mock + // object alive. Therefore we report any living object as test + // failure, unless the user explicitly asked us to ignore it. + ~MockObjectRegistry() { + using ::std::cout; + + if (!GMOCK_FLAG(catch_leaked_mocks)) + return; + + int leaked_count = 0; + for (StateMap::const_iterator it = states_.begin(); it != states_.end(); + ++it) { + if (it->second.leakable) // The user said it's fine to leak this object. + continue; + + // TODO(wan@google.com): Print the type of the leaked object. + // This can help the user identify the leaked object. + cout << "\n"; + const MockObjectState& state = it->second; + internal::FormatFileLocation( + state.first_used_file, state.first_used_line, &cout); + cout << " ERROR: this mock object should be deleted but never is. " + << "Its address is @" << it->first << "."; + leaked_count++; + } + if (leaked_count > 0) { + cout << "\nERROR: " << leaked_count + << " leaked mock " << (leaked_count == 1 ? "object" : "objects") + << " found at program exit.\n"; + cout.flush(); + ::std::cerr.flush(); + // RUN_ALL_TESTS() has already returned when this destructor is + // called. Therefore we cannot use the normal Google Test + // failure reporting mechanism. + _exit(1); // We cannot call exit() as it is not reentrant and + // may already have been called. + } + } + + StateMap& states() { return states_; } + private: + StateMap states_; +}; + +// Protected by g_gmock_mutex. MockObjectRegistry g_mock_object_registry; // Maps a mock object to the reaction Google Mock should have when an @@ -208,6 +283,14 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls( internal::WARN : g_uninteresting_call_reaction[mock_obj]; } +// Tells Google Mock to ignore mock_obj when checking for leaked mock +// objects. +// L < g_gmock_mutex +void Mock::AllowLeak(const void* mock_obj) { + internal::MutexLock l(&internal::g_gmock_mutex); + g_mock_object_registry.states()[mock_obj].leakable = true; +} + // Verifies and clears all expectations on the given mock object. If // the expectations aren't satisfied, generates one or more Google // Test non-fatal failures and returns false. @@ -233,7 +316,7 @@ bool Mock::VerifyAndClear(void* mock_obj) { // L >= g_gmock_mutex bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) { internal::g_gmock_mutex.AssertHeld(); - if (g_mock_object_registry.count(mock_obj) == 0) { + if (g_mock_object_registry.states().count(mock_obj) == 0) { // No EXPECT_CALL() was set on the given mock object. return true; } @@ -241,7 +324,8 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) { // Verifies and clears the expectations on each mock method in the // given mock object. bool expectations_met = true; - FunctionMockers& mockers = g_mock_object_registry[mock_obj]; + FunctionMockers& mockers = + g_mock_object_registry.states()[mock_obj].function_mockers; for (FunctionMockers::const_iterator it = mockers.begin(); it != mockers.end(); ++it) { if (!(*it)->VerifyAndClearExpectationsLocked()) { @@ -259,7 +343,21 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) { void Mock::Register(const void* mock_obj, internal::UntypedFunctionMockerBase* mocker) { internal::MutexLock l(&internal::g_gmock_mutex); - g_mock_object_registry[mock_obj].insert(mocker); + g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker); +} + +// Tells Google Mock where in the source code mock_obj is used in an +// ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this +// information helps the user identify which object it is. +// L < g_gmock_mutex +void Mock::RegisterUseByOnCallOrExpectCall( + const void* mock_obj, const char* file, int line) { + internal::MutexLock l(&internal::g_gmock_mutex); + MockObjectState& state = g_mock_object_registry.states()[mock_obj]; + if (state.first_used_file == NULL) { + state.first_used_file = file; + state.first_used_line = line; + } } // Unregisters a mock method; removes the owning mock object from the @@ -269,13 +367,14 @@ void Mock::Register(const void* mock_obj, // L >= g_gmock_mutex void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) { internal::g_gmock_mutex.AssertHeld(); - for (MockObjectRegistry::iterator it = g_mock_object_registry.begin(); - it != g_mock_object_registry.end(); ++it) { - FunctionMockers& mockers = it->second; + for (MockObjectRegistry::StateMap::iterator it = + g_mock_object_registry.states().begin(); + it != g_mock_object_registry.states().end(); ++it) { + FunctionMockers& mockers = it->second.function_mockers; if (mockers.erase(mocker) > 0) { // mocker was in mockers and has been just removed. if (mockers.empty()) { - g_mock_object_registry.erase(it); + g_mock_object_registry.states().erase(it); } return; } @@ -287,14 +386,15 @@ void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) { void Mock::ClearDefaultActionsLocked(void* mock_obj) { internal::g_gmock_mutex.AssertHeld(); - if (g_mock_object_registry.count(mock_obj) == 0) { + if (g_mock_object_registry.states().count(mock_obj) == 0) { // No ON_CALL() was set on the given mock object. return; } // Clears the default actions for each mock method in the given mock // object. - FunctionMockers& mockers = g_mock_object_registry[mock_obj]; + FunctionMockers& mockers = + g_mock_object_registry.states()[mock_obj].function_mockers; for (FunctionMockers::const_iterator it = mockers.begin(); it != mockers.end(); ++it) { (*it)->ClearDefaultActionsLocked(); diff --git a/src/gmock.cc b/src/gmock.cc index c017917d..dc9d3d22 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -34,6 +34,15 @@ namespace testing { +// TODO(wan@google.com): support using environment variables to +// control the flag values, like what Google Test does. + +// TODO(wan@google.com): change the default value to true after people +// have a chance to fix their leaked mocks. +GMOCK_DEFINE_bool_(catch_leaked_mocks, false, + "true iff Google Mock should report leaked mock objects " + "as failures."); + GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity, "Controls how verbose Google Mock's output is." " Valid values:\n" @@ -76,6 +85,24 @@ static const char* ParseGoogleMockFlagValue(const char* str, return flag_end + 1; } +// Parses a string for a Google Mock bool flag, in the form of +// "--gmock_flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +static bool ParseGoogleMockBoolFlag(const char* str, const char* flag, + bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseGoogleMockFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + // Parses a string for a Google Mock string flag, in the form of // "--gmock_flag=value". // @@ -110,7 +137,9 @@ void InitGoogleMockImpl(int* argc, CharType** argv) { const char* const arg = arg_string.c_str(); // Do we see a Google Mock flag? - if (ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) { + if (ParseGoogleMockBoolFlag(arg, "catch_leaked_mocks", + &GMOCK_FLAG(catch_leaked_mocks)) || + ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 287a63e2..e8c39028 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1612,6 +1612,43 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { #endif // 0 +TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) { + MockA* a = new MockA; + Mock::AllowLeak(a); +} + +TEST(AllowLeakTest, CanBeCalledBeforeOnCall) { + MockA* a = new MockA; + Mock::AllowLeak(a); + ON_CALL(*a, DoA(_)).WillByDefault(Return()); + a->DoA(0); +} + +TEST(AllowLeakTest, CanBeCalledAfterOnCall) { + MockA* a = new MockA; + ON_CALL(*a, DoA(_)).WillByDefault(Return()); + Mock::AllowLeak(a); +} + +TEST(AllowLeakTest, CanBeCalledBeforeExpectCall) { + MockA* a = new MockA; + Mock::AllowLeak(a); + EXPECT_CALL(*a, DoA(_)); + a->DoA(0); +} + +TEST(AllowLeakTest, CanBeCalledAfterExpectCall) { + MockA* a = new MockA; + EXPECT_CALL(*a, DoA(_)).Times(AnyNumber()); + Mock::AllowLeak(a); +} + +TEST(AllowLeakTest, WorksWhenBothOnCallAndExpectCallArePresent) { + MockA* a = new MockA; + ON_CALL(*a, DoA(_)).WillByDefault(Return()); + EXPECT_CALL(*a, DoA(_)).Times(AnyNumber()); + Mock::AllowLeak(a); +} // Tests that we can verify and clear a mock object's expectations // when none of its methods has expectations. @@ -1916,3 +1953,14 @@ void Helper(MockC* c) { } } // namespace + +int main(int argc, char **argv) { + testing::InitGoogleMock(&argc, argv); + + // Ensures that the tests pass no matter what value of + // --gmock_catch_leaked_mocks and --gmock_verbose the user specifies. + testing::GMOCK_FLAG(catch_leaked_mocks) = true; + testing::GMOCK_FLAG(verbose) = testing::internal::kWarningVerbosity; + + return RUN_ALL_TESTS(); +} diff --git a/test/gmock_leak_test.py b/test/gmock_leak_test.py new file mode 100755 index 00000000..51358f06 --- /dev/null +++ b/test/gmock_leak_test.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# +# Copyright 2009, 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. + +"""Tests that leaked mock objects can be caught be Google Mock.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import gmock_test_utils +import os +import unittest + +IS_WINDOWS = os.name == 'nt' + +if IS_WINDOWS: + # TODO(wan@google.com): test the opt build too. We should do it + # when Vlad Losev's work on Google Test's Python test driver is + # done, such that we can reuse the work. + PROGRAM = r'..\build.dbg\gmock_leak_test_.exe' +else: + PROGRAM = 'gmock_leak_test_' + +PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) +TEST_WITH_EXPECT_CALL = PROGRAM_PATH + ' --gtest_filter=*ExpectCall*' +TEST_WITH_ON_CALL = PROGRAM_PATH + ' --gtest_filter=*OnCall*' +TEST_MULTIPLE_LEAKS = PROGRAM_PATH + ' --gtest_filter=*MultipleLeaked*' + + +class GMockLeakTest(unittest.TestCase): + + def testDoesNotCatchLeakedMockByDefault(self): + self.assertEquals(0, os.system(TEST_WITH_EXPECT_CALL)) + self.assertEquals(0, os.system(TEST_WITH_ON_CALL)) + + def testDoesNotCatchLeakedMockWhenDisabled(self): + self.assertEquals( + 0, os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=0')) + self.assertEquals( + 0, os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks=0')) + + def testCatchesLeakedMockWhenEnabled(self): + self.assertNotEqual( + os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks'), 0) + self.assertNotEqual( + os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks'), 0) + + def testCatchesLeakedMockWhenEnabledWithExplictFlagValue(self): + self.assertNotEqual( + os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=1'), 0) + + def testCatchesMultipleLeakedMocks(self): + self.assertNotEqual( + os.system(TEST_MULTIPLE_LEAKS + ' --gmock_catch_leaked_mocks'), 0) + + +if __name__ == '__main__': + gmock_test_utils.Main() diff --git a/test/gmock_leak_test_.cc b/test/gmock_leak_test_.cc new file mode 100644 index 00000000..157bd7ec --- /dev/null +++ b/test/gmock_leak_test_.cc @@ -0,0 +1,95 @@ +// Copyright 2009, 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 program is for verifying that a leaked mock object can be +// caught by Google Mock's leak detector. + +#include + +namespace { + +using ::testing::Return; + +class FooInterface { + public: + virtual ~FooInterface() {} + virtual void DoThis() = 0; +}; + +class MockFoo : public FooInterface { + public: + MOCK_METHOD0(DoThis, void()); +}; + +TEST(LeakTest, LeakedMockWithExpectCallCausesFailureWhenLeakCheckingIsEnabled) { + MockFoo* foo = new MockFoo; + + EXPECT_CALL(*foo, DoThis()); + foo->DoThis(); + + // In order to test the leak detector, we deliberately leak foo. + + // Makes sure Google Mock's leak detector can change the exit code + // to 1 even when the code is already exiting with 0. + exit(0); +} + +TEST(LeakTest, LeakedMockWithOnCallCausesFailureWhenLeakCheckingIsEnabled) { + MockFoo* foo = new MockFoo; + + ON_CALL(*foo, DoThis()).WillByDefault(Return()); + + // In order to test the leak detector, we deliberately leak foo. + + // Makes sure Google Mock's leak detector can change the exit code + // to 1 even when the code is already exiting with 0. + exit(0); +} + +TEST(LeakTest, CatchesMultipleLeakedMockObjects) { + MockFoo* foo1 = new MockFoo; + MockFoo* foo2 = new MockFoo; + + ON_CALL(*foo1, DoThis()).WillByDefault(Return()); + EXPECT_CALL(*foo2, DoThis()); + foo2->DoThis(); + + // In order to test the leak detector, we deliberately leak foo1 and + // foo2. + + // Makes sure Google Mock's leak detector can change the exit code + // to 1 even when the code is already exiting with 0. + exit(0); +} + +} // namespace diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py index f7f37abb..2e992190 100755 --- a/test/gmock_output_test.py +++ b/test/gmock_output_test.py @@ -59,7 +59,7 @@ else: PROGRAM = 'gmock_output_test_' PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) -COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0' +COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0 --gtest_print_time=0' GOLDEN_NAME = 'gmock_output_test_golden.txt' GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), GOLDEN_NAME) diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index bb56b7cd..c97bc78c 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -40,6 +40,7 @@ #include using testing::_; +using testing::AnyNumber; using testing::Ge; using testing::InSequence; using testing::Ref; @@ -239,3 +240,31 @@ TEST_F(GMockOutputTest, ExplicitActionsRunOutWithDefaultAction) { foo_.Bar2(2, 2); foo_.Bar2(1, 1); // Explicit actions in EXPECT_CALL run out. } + +TEST_F(GMockOutputTest, CatchesLeakedMocks) { + MockFoo* foo1 = new MockFoo; + MockFoo* foo2 = new MockFoo; + + // Invokes ON_CALL on foo1. + ON_CALL(*foo1, Bar(_, _, _)).WillByDefault(Return('a')); + + // Invokes EXPECT_CALL on foo2. + EXPECT_CALL(*foo2, Bar2(_, _)); + EXPECT_CALL(*foo2, Bar2(1, _)); + EXPECT_CALL(*foo2, Bar3(_, _)).Times(AnyNumber()); + foo2->Bar2(2, 1); + foo2->Bar2(1, 1); + + // Both foo1 and foo2 are deliberately leaked. +} + +int main(int argc, char **argv) { + testing::InitGoogleMock(&argc, argv); + + // Ensures that the tests pass no matter what value of + // --gmock_catch_leaked_mocks and --gmock_verbose the user specifies. + testing::GMOCK_FLAG(catch_leaked_mocks) = true; + testing::GMOCK_FLAG(verbose) = "warning"; + + return RUN_ALL_TESTS(); +} diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index 374e6659..50ef7b75 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -1,4 +1,3 @@ -Running main() from gmock_main.cc [ RUN ] GMockOutputTest.ExpectedCall FILE:#: EXPECT_CALL(foo_, Bar2(0, _)) invoked @@ -280,6 +279,8 @@ Called 2 times, but only 1 WillOnce() is specified - taking default action speci FILE:#: Stack trace: [ OK ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction +[ RUN ] GMockOutputTest.CatchesLeakedMocks +[ OK ] GMockOutputTest.CatchesLeakedMocks [ FAILED ] GMockOutputTest.UnexpectedCall [ FAILED ] GMockOutputTest.UnexpectedCallToVoidFunction [ FAILED ] GMockOutputTest.ExcessiveCall @@ -294,3 +295,7 @@ Stack trace: [ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction [ FAILED ] GMockOutputTest.ExcessiveCallWithDefaultAction + +FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. +FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. +ERROR: 2 leaked mock objects found at program exit. diff --git a/test/gmock_test.cc b/test/gmock_test.cc index 63c3fe8d..0c832607 100644 --- a/test/gmock_test.cc +++ b/test/gmock_test.cc @@ -246,3 +246,10 @@ TEST(WideInitGoogleMockTest, CallsInitGoogleTest) { TestInitGoogleMock(argv, new_argv, "error"); EXPECT_EQ(old_init_gtest_count + 1, g_init_gtest_count); } + +// Makes sure Google Mock flags can be accessed in code. +TEST(FlagTest, IsAccessibleInCode) { + bool dummy = testing::GMOCK_FLAG(catch_leaked_mocks) && + testing::GMOCK_FLAG(verbose) == ""; + dummy = dummy; // Avoids the "unused local variable" warning. +} -- cgit v1.2.3 From bf0d0a44812f97449d7401d0eeb8da954f76ba2a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 29 Apr 2009 23:52:29 +0000 Subject: Turns --gmock_catch_leaked_mocks on by default. --- src/gmock.cc | 4 +--- test/gmock_leak_test.py | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/gmock.cc b/src/gmock.cc index dc9d3d22..caafb015 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -37,9 +37,7 @@ namespace testing { // TODO(wan@google.com): support using environment variables to // control the flag values, like what Google Test does. -// TODO(wan@google.com): change the default value to true after people -// have a chance to fix their leaked mocks. -GMOCK_DEFINE_bool_(catch_leaked_mocks, false, +GMOCK_DEFINE_bool_(catch_leaked_mocks, true, "true iff Google Mock should report leaked mock objects " "as failures."); diff --git a/test/gmock_leak_test.py b/test/gmock_leak_test.py index 51358f06..1337e0b0 100755 --- a/test/gmock_leak_test.py +++ b/test/gmock_leak_test.py @@ -55,9 +55,9 @@ TEST_MULTIPLE_LEAKS = PROGRAM_PATH + ' --gtest_filter=*MultipleLeaked*' class GMockLeakTest(unittest.TestCase): - def testDoesNotCatchLeakedMockByDefault(self): - self.assertEquals(0, os.system(TEST_WITH_EXPECT_CALL)) - self.assertEquals(0, os.system(TEST_WITH_ON_CALL)) + def testCatchesLeakedMockByDefault(self): + self.assertNotEqual(os.system(TEST_WITH_EXPECT_CALL), 0) + self.assertNotEqual(os.system(TEST_WITH_ON_CALL), 0) def testDoesNotCatchLeakedMockWhenDisabled(self): self.assertEquals( -- cgit v1.2.3 From 125783fb87488239c062422bece2a9302489aafd Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 May 2009 19:36:44 +0000 Subject: Fixes tr1 tuple's path when compiled with gcc version < 4.0.0 (by Zhanyong Wan). --- include/gmock/internal/gmock-port.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index b98cb113..cad195ad 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -48,12 +48,14 @@ // To avoid conditional compilation everywhere, we make it // gmock-port.h's responsibility to #include the header implementing // tr1/tuple. -#if defined(__GNUC__) -// GCC implements tr1/tuple in the header. This does not -// conform to the TR1 spec, which requires the header to be . +#if defined(__GNUC__) && GTEST_GCC_VER_ >= 40000 +// GTEST_GCC_VER_ is defined in gtest-port.h and 40000 corresponds to +// version 4.0.0. +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . #include #else -// If the compiler is not GCC, we assume the user is using a +// If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. #include #endif // __GNUC__ -- cgit v1.2.3 From e7bb5ededa4df6ec430c1e84154bc01bf84d4ecc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 May 2009 23:14:47 +0000 Subject: Improves the error message for leaked mocks to include the test name (by Zhanyong Wan). --- include/gmock/internal/gmock-port.h | 8 +++---- src/gmock-spec-builders.cc | 20 ++++++++++++++-- test/gmock_output_test.py | 48 ++++++++++++++++++++++++++++++------- test/gmock_output_test_.cc | 11 +++++++++ test/gmock_output_test_golden.txt | 3 ++- 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index cad195ad..d242c8e4 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -166,16 +166,16 @@ inline To down_cast(From* f) { // so we only accept pointers return static_cast(f); } -// The GMOCK_COMPILE_ASSERT macro can be used to verify that a compile time +// The GMOCK_COMPILE_ASSERT_ macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // -// GMOCK_COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); +// GMOCK_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // -// GMOCK_COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// GMOCK_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 2bb72954..65a74b81 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -168,6 +168,8 @@ struct MockObjectState { // invoked on this mock object. const char* first_used_file; int first_used_line; + ::std::string first_used_test_case; + ::std::string first_used_test; bool leakable; // true iff it's OK to leak the object. FunctionMockers function_mockers; // All registered methods of the object. }; @@ -203,8 +205,13 @@ class MockObjectRegistry { const MockObjectState& state = it->second; internal::FormatFileLocation( state.first_used_file, state.first_used_line, &cout); - cout << " ERROR: this mock object should be deleted but never is. " - << "Its address is @" << it->first << "."; + cout << " ERROR: this mock object"; + if (state.first_used_test != "") { + cout << " (used in test " << state.first_used_test_case << "." + << state.first_used_test << ")"; + } + cout << " should be deleted but never is. Its address is @" + << it->first << "."; leaked_count++; } if (leaked_count > 0) { @@ -357,6 +364,15 @@ void Mock::RegisterUseByOnCallOrExpectCall( if (state.first_used_file == NULL) { state.first_used_file = file; state.first_used_line = line; + const TestInfo* const test_info = + UnitTest::GetInstance()->current_test_info(); + if (test_info != NULL) { + // TODO(wan@google.com): record the test case name when the + // ON_CALL or EXPECT_CALL is invoked from SetUpTestCase() or + // TearDownTestCase(). + state.first_used_test_case = test_info->test_case_name(); + state.first_used_test = test_info->name(); + } } } diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py index 2e992190..f43f7074 100755 --- a/test/gmock_output_test.py +++ b/test/gmock_output_test.py @@ -64,6 +64,7 @@ GOLDEN_NAME = 'gmock_output_test_golden.txt' GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), GOLDEN_NAME) + def ToUnixLineEnding(s): """Changes all Windows/Mac line endings in s to UNIX line endings.""" @@ -109,15 +110,38 @@ def RemoveMemoryAddresses(output): return re.sub(r'@\w+', '@0x#', output) -def NormalizeOutput(output): - """Normalizes output (the output of gmock_output_test_.exe).""" +def RemoveTestNamesOfLeakedMocks(output): + """Removes the test names of leaked mock objects from the test output.""" + + return re.sub(r'\(used in test .+\) ', '', output) + + +def GetLeakyTests(output): + """Returns a list of test names that leak mock objects.""" + + # findall() returns a list of all matches of the regex in output. + # For example, if '(used in test FooTest.Bar)' is in output, the + # list will contain 'FooTest.Bar'. + return re.findall(r'\(used in test (.+)\)', output) + + +def GetNormalizedOutputAndLeakyTests(output): + """Normalizes the output of gmock_output_test_. + + Args: + output: The test output. + + Returns: + A tuple (the normalized test output, the list of test names that have + leaked mocks). + """ output = ToUnixLineEnding(output) output = RemoveReportHeaderAndFooter(output) output = NormalizeErrorMarker(output) output = RemoveLocations(output) output = RemoveMemoryAddresses(output) - return output + return (RemoveTestNamesOfLeakedMocks(output), GetLeakyTests(output)) def IterShellCommandOutput(cmd, stdin_string=None): @@ -167,9 +191,8 @@ def GetShellCommandOutput(cmd, stdin_string=None): return string.join(lines, '') -def GetCommandOutput(cmd): - """Runs a command and returns its output with all file location - info stripped off. +def GetNormalizedCommandOutputAndLeakyTests(cmd): + """Runs a command and returns its normalized output and a list of leaky tests. Args: cmd: the shell command. @@ -177,22 +200,29 @@ def GetCommandOutput(cmd): # Disables exception pop-ups on Windows. os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' - return NormalizeOutput(GetShellCommandOutput(cmd, '')) + return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd, '')) class GMockOutputTest(unittest.TestCase): def testOutput(self): - output = GetCommandOutput(COMMAND) + (output, leaky_tests) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) golden_file = open(GOLDEN_PATH, 'rb') golden = golden_file.read() golden_file.close() + # The normalized output should match the golden file. self.assertEquals(golden, output) + # The raw output should contain 2 leaked mock object errors for + # test GMockOutputTest.CatchesLeakedMocks. + self.assertEquals(['GMockOutputTest.CatchesLeakedMocks', + 'GMockOutputTest.CatchesLeakedMocks'], + leaky_tests) + if __name__ == '__main__': if sys.argv[1:] == [GENGOLDEN_FLAG]: - output = GetCommandOutput(COMMAND) + (output, _) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) golden_file = open(GOLDEN_PATH, 'wb') golden_file.write(output) golden_file.close() diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index c97bc78c..97619af1 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -258,6 +258,16 @@ TEST_F(GMockOutputTest, CatchesLeakedMocks) { // Both foo1 and foo2 are deliberately leaked. } +void TestCatchesLeakedMocksInAdHocTests() { + MockFoo* foo = new MockFoo; + + // Invokes EXPECT_CALL on foo. + EXPECT_CALL(*foo, Bar2(_, _)); + foo->Bar2(2, 1); + + // foo is deliberately leaked. +} + int main(int argc, char **argv) { testing::InitGoogleMock(&argc, argv); @@ -266,5 +276,6 @@ int main(int argc, char **argv) { testing::GMOCK_FLAG(catch_leaked_mocks) = true; testing::GMOCK_FLAG(verbose) = "warning"; + TestCatchesLeakedMocksInAdHocTests(); return RUN_ALL_TESTS(); } diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index 50ef7b75..887b7be7 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -298,4 +298,5 @@ Stack trace: FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. -ERROR: 2 leaked mock objects found at program exit. +FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. +ERROR: 3 leaked mock objects found at program exit. -- cgit v1.2.3 From 987a978c3c525cbc796824493436195872b89a0b Mon Sep 17 00:00:00 2001 From: nnorwitz Date: Wed, 6 May 2009 05:01:46 +0000 Subject: Issue 44: "const" is missing for const return types The modifiers (things like const, volatile, etc) were not being added to return types. --- scripts/generator/cpp/gmock_class.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index f2b3521f..99a89655 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -54,7 +54,11 @@ def _GenerateMethods(output_lines, source, class_node): const = 'CONST_' return_type = 'void' if node.return_type: - return_type = node.return_type.name + # Add modifier bits like const. + modifiers = '' + if node.return_type.modifiers: + modifiers = ' '.join(node.return_type.modifiers) + ' ' + return_type = modifiers + node.return_type.name if node.return_type.pointer: return_type += '*' if node.return_type.reference: -- cgit v1.2.3 From 60df3efe3971fb54d3a10c557fbc30ff32512bb5 Mon Sep 17 00:00:00 2001 From: nnorwitz Date: Wed, 6 May 2009 05:31:57 +0000 Subject: Fix grammar in comment --- scripts/generator/cpp/gmock_class.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index 99a89655..a4435de4 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -35,7 +35,7 @@ import sys from cpp import ast from cpp import utils -# How many spaces to indent. Can me set with INDENT environment variable. +# How many spaces to indent. Can set me with INDENT environment variable. _INDENT = 2 -- cgit v1.2.3 From ce60784fb51a5a0e28c14edd53bacbf0d2abb36b Mon Sep 17 00:00:00 2001 From: nnorwitz Date: Wed, 6 May 2009 05:57:09 +0000 Subject: Allow any number of ClassNames to be specified on the command line. 0 ClassNames means emit all classes found in the file. --- scripts/generator/README | 4 +++- scripts/generator/cpp/gmock_class.py | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/scripts/generator/README b/scripts/generator/README index a3ba784b..2fc695a6 100644 --- a/scripts/generator/README +++ b/scripts/generator/README @@ -14,7 +14,9 @@ to generate a Google Mock class. Make sure to install the scripts somewhere in your path. Then you can run the program. - gmock_gen.py header-file.h ClassName + gmock_gen.py header-file.h [ClassName1] [ClassName2] ... + +If no ClassNames are specified, all classes in the file are emitted. To change the indentation from the default of 2, set INDENT in the environment. For example to use an indent of 4 spaces: diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index a4435de4..ab2da32d 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -20,7 +20,7 @@ This program will read in a C++ source file and output the Google Mock class for the specified class. Usage: - gmock_class.py header-file.h ClassName + gmock_class.py header-file.h [ClassName1] [ClassName2] ... Output is sent to stdout. """ @@ -79,10 +79,12 @@ def _GenerateMethods(output_lines, source, class_node): output_lines.append(line) -def _GenerateMock(filename, source, ast_list, class_name): +def _GenerateMock(filename, source, ast_list, desired_class_names): lines = [] for node in ast_list: - if isinstance(node, ast.Class) and node.body and node.name == class_name: + if (isinstance(node, ast.Class) and node.body and + (desired_class_names is None or node.name in desired_class_names)): + class_name = node.name class_node = node # Add namespace before the class. if class_node.namespace: @@ -115,11 +117,15 @@ def _GenerateMock(filename, source, ast_list, class_name): if lines: sys.stdout.write('\n'.join(lines)) else: - sys.stderr.write('Class %s not found\n' % class_name) + if desired_class_names is None: + sys.stderr.write('No classes not found\n') + else: + class_names = ', '.join(sorted(desired_class_names)) + sys.stderr.write('Class(es) not found: %s\n' % class_names) def main(argv=sys.argv): - if len(argv) != 3: + if len(argv) < 2: sys.stdout.write(__doc__) return 1 @@ -131,7 +137,10 @@ def main(argv=sys.argv): except: sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT')) - filename, class_name = argv[1:] + filename = argv[1] + class_name = None + if len(argv) >= 3: + class_name = set(argv[2:]) source = utils.ReadFile(filename) if source is None: return 1 -- cgit v1.2.3 From 84b8e4c65d0847ab4262bb70619182292482529a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 7 May 2009 20:38:25 +0000 Subject: Cleans up the mock generator script: - updates the doc string. - adds a version number. - fixes the condition for error messages in _GenerateMocks(). --- scripts/generator/README | 2 +- scripts/generator/cpp/gmock_class.py | 51 +++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/scripts/generator/README b/scripts/generator/README index 2fc695a6..ddaa9d44 100644 --- a/scripts/generator/README +++ b/scripts/generator/README @@ -14,7 +14,7 @@ to generate a Google Mock class. Make sure to install the scripts somewhere in your path. Then you can run the program. - gmock_gen.py header-file.h [ClassName1] [ClassName2] ... + gmock_gen.py header-file.h [ClassName]... If no ClassNames are specified, all classes in the file are emitted. diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index ab2da32d..ba11f9e6 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -14,13 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Generate a Google Mock class from a production class. +"""Generate Google Mock classes from base classes. -This program will read in a C++ source file and output the Google Mock class -for the specified class. +This program will read in a C++ source file and output the Google Mock +classes for the specified classes. If no class is specified, all +classes in the source file are emitted. Usage: - gmock_class.py header-file.h [ClassName1] [ClassName2] ... + gmock_class.py header-file.h [ClassName]... Output is sent to stdout. """ @@ -35,7 +36,8 @@ import sys from cpp import ast from cpp import utils -# How many spaces to indent. Can set me with INDENT environment variable. +_VERSION = (1, 0, 1) # The version of this script. +# How many spaces to indent. Can set me with the INDENT environment variable. _INDENT = 2 @@ -54,7 +56,7 @@ def _GenerateMethods(output_lines, source, class_node): const = 'CONST_' return_type = 'void' if node.return_type: - # Add modifier bits like const. + # Add modifiers like 'const'. modifiers = '' if node.return_type.modifiers: modifiers = ' '.join(node.return_type.modifiers) + ' ' @@ -79,12 +81,15 @@ def _GenerateMethods(output_lines, source, class_node): output_lines.append(line) -def _GenerateMock(filename, source, ast_list, desired_class_names): +def _GenerateMocks(filename, source, ast_list, desired_class_names): + processed_class_names = set() lines = [] for node in ast_list: - if (isinstance(node, ast.Class) and node.body and - (desired_class_names is None or node.name in desired_class_names)): + if (isinstance(node, ast.Class) and node.body and + # desired_class_names being None means that all classes are selected. + (not desired_class_names or node.name in desired_class_names)): class_name = node.name + processed_class_names.add(class_name) class_node = node # Add namespace before the class. if class_node.namespace: @@ -114,19 +119,23 @@ def _GenerateMock(filename, source, ast_list, desired_class_names): lines.append('} // namespace %s' % class_node.namespace[i]) lines.append('') # Add an extra newline. - if lines: - sys.stdout.write('\n'.join(lines)) - else: - if desired_class_names is None: - sys.stderr.write('No classes not found\n') - else: - class_names = ', '.join(sorted(desired_class_names)) - sys.stderr.write('Class(es) not found: %s\n' % class_names) + sys.stdout.write('\n'.join(lines)) + + if desired_class_names: + missing_class_names = ', '.join( + sorted(desired_class_names - processed_class_names)) + if missing_class_names: + sys.stderr.write('Class(es) not found in %s: %s\n' % + (filename, missing_class_names)) + elif not processed_class_names: + sys.stderr.write('No class found in %s\n' % filename) def main(argv=sys.argv): if len(argv) < 2: - sys.stdout.write(__doc__) + sys.stderr.write('Google Mock Class Generator v%s\n\n' % + '.'.join(map(str, _VERSION))) + sys.stderr.write(__doc__) return 1 global _INDENT @@ -138,9 +147,9 @@ def main(argv=sys.argv): sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT')) filename = argv[1] - class_name = None + desired_class_names = None # None means all classes in the source file. if len(argv) >= 3: - class_name = set(argv[2:]) + desired_class_names = set(argv[2:]) source = utils.ReadFile(filename) if source is None: return 1 @@ -154,7 +163,7 @@ def main(argv=sys.argv): # An error message was already printed since we couldn't parse. pass else: - _GenerateMock(filename, source, entire_ast, class_name) + _GenerateMocks(filename, source, entire_ast, desired_class_names) if __name__ == '__main__': -- cgit v1.2.3 From d955e83bee3919b871616223b777bab2f04942d9 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 7 May 2009 21:20:57 +0000 Subject: Makes the mock generator work with python2.3.5, which comes with Mac OS X Tiger. --- scripts/generator/README | 2 +- scripts/generator/cpp/gmock_class.py | 13 +++++++------ scripts/generator/cpp/keywords.py | 1 + scripts/generator/gmock_gen.py | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/generator/README b/scripts/generator/README index ddaa9d44..071bf0fb 100644 --- a/scripts/generator/README +++ b/scripts/generator/README @@ -3,7 +3,7 @@ The Google Mock class generator is an application that is part of cppclean. For more information about cppclean, see the README.cppclean file or visit http://code.google.com/p/cppclean/ -cppclean requires Python 2.4 or later. If you don't have Python installed +cppclean requires Python 2.3.5 or later. If you don't have Python installed on your system, you will also need to install it. You can download Python from: http://www.python.org/download/releases/ diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index ba11f9e6..29204247 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -31,6 +31,7 @@ __author__ = 'nnorwitz@google.com (Neal Norwitz)' import os import re +import sets import sys from cpp import ast @@ -82,7 +83,7 @@ def _GenerateMethods(output_lines, source, class_node): def _GenerateMocks(filename, source, ast_list, desired_class_names): - processed_class_names = set() + processed_class_names = sets.Set() lines = [] for node in ast_list: if (isinstance(node, ast.Class) and node.body and @@ -122,11 +123,11 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names): sys.stdout.write('\n'.join(lines)) if desired_class_names: - missing_class_names = ', '.join( - sorted(desired_class_names - processed_class_names)) - if missing_class_names: + missing_class_name_list = list(desired_class_names - processed_class_names) + if missing_class_name_list: + missing_class_name_list.sort() sys.stderr.write('Class(es) not found in %s: %s\n' % - (filename, missing_class_names)) + (filename, ', '.join(missing_class_name_list))) elif not processed_class_names: sys.stderr.write('No class found in %s\n' % filename) @@ -149,7 +150,7 @@ def main(argv=sys.argv): filename = argv[1] desired_class_names = None # None means all classes in the source file. if len(argv) >= 3: - desired_class_names = set(argv[2:]) + desired_class_names = sets.Set(argv[2:]) source = utils.ReadFile(filename) if source is None: return 1 diff --git a/scripts/generator/cpp/keywords.py b/scripts/generator/cpp/keywords.py index 73f0202c..f694450e 100755 --- a/scripts/generator/cpp/keywords.py +++ b/scripts/generator/cpp/keywords.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # # Copyright 2007 Neal Norwitz # Portions Copyright 2007 Google Inc. diff --git a/scripts/generator/gmock_gen.py b/scripts/generator/gmock_gen.py index 5a3f6583..8cc0d135 100755 --- a/scripts/generator/gmock_gen.py +++ b/scripts/generator/gmock_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.4 +#!/usr/bin/env python # # Copyright 2008 Google Inc. All Rights Reserved. # -- cgit v1.2.3 From 18490653e80d484b4650d8799184fd1e021efc7b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 11 May 2009 18:54:08 +0000 Subject: Partially implemented SafeMatcherCast (by Vlad Losev); updated the implementation of Not, AnyOf, and AllOf to use SafeMatcherCast (by Vlad Losev); implemented ACTION_TEMPLATE (by Zhanyong Wan); worked around bugs on Symbian (by Zhanyong Wan). --- include/gmock/gmock-generated-actions.h | 410 +++++++++++++++++++++++++++ include/gmock/gmock-generated-actions.h.pump | 234 +++++++++++++++ include/gmock/gmock-matchers.h | 113 +++++--- include/gmock/gmock-printers.h | 9 +- include/gmock/gmock-spec-builders.h | 12 +- test/gmock-generated-actions_test.cc | 152 ++++++++++ test/gmock-matchers_test.cc | 113 +++++++- 7 files changed, 999 insertions(+), 44 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 26308bf4..6d49c600 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -1571,6 +1571,416 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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(std::tr1::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)\ + GMOCK_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:\ + 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\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(\ + new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ + }\ + GMOCK_INTERNAL_DEFN_##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:\ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 942be2e5..39f80804 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -3,6 +3,7 @@ $$ This is a Pump source file. Please use Pump to convert it to $$ gmock-generated-variadic-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. // @@ -718,6 +719,239 @@ $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(std::tr1::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)\ + GMOCK_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:\ + 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\ + };\ + template operator ::testing::Action() const {\ + return ::testing::Action(\ + new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ + }\ + GMOCK_INTERNAL_DEFN_##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 [[ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index f764344d..5700fb25 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -171,7 +171,7 @@ class Matcher : public internal::MatcherBase { explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} - // Implicit constructor here allows ipeople to write + // 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 }; @@ -310,6 +310,39 @@ inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { template Matcher MatcherCast(M m); +// TODO(vladl@google.com): Modify the implementation to reject casting +// Matcher to Matcher. +// Implements SafeMatcherCast(). +// +// This overload handles polymorphic matchers only since monomorphic +// matchers are handled by the next one. +template +inline Matcher SafeMatcherCast(M polymorphic_matcher) { + return Matcher(polymorphic_matcher); +} + +// 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 +Matcher SafeMatcherCast(const Matcher& matcher) { + // Enforce that T can be implicitly converted to U. + GMOCK_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. + GMOCK_COMPILE_ASSERT_( + internal::is_reference::value || !internal::is_reference::value, + cannot_convert_non_referentce_arg_to_reference); + return MatcherCast(matcher); +} + // A() returns a matcher that matches any value of type T. template Matcher A(); @@ -927,6 +960,10 @@ GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "not equal to"); #undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ +// TODO(vladl@google.com): Move Impl outside of NotMatcher and rename it +// NotMatcherImpl to reduce compilation overhead and the size of the binary. +// This also applies to BothOfMatcher::Impl and EitherOfMatcher::Impl. +// // Implements the Not(m) matcher, which matches a value that doesn't // match matcher m. template @@ -945,7 +982,8 @@ class NotMatcher { template class Impl : public MatcherInterface { public: - explicit Impl(const Matcher& matcher) : matcher_(matcher) {} + explicit Impl(InnerMatcher matcher) + : matcher_(SafeMatcherCast(matcher)) {} virtual bool Matches(T x) const { return !matcher_.Matches(x); @@ -990,8 +1028,9 @@ class BothOfMatcher { template class Impl : public MatcherInterface { public: - Impl(const Matcher& matcher1, const Matcher& matcher2) - : matcher1_(matcher1), matcher2_(matcher2) {} + Impl(Matcher1 matcher1, Matcher2 matcher2) + : matcher1_(SafeMatcherCast(matcher1)), + matcher2_(SafeMatcherCast(matcher2)) {} virtual bool Matches(T x) const { return matcher1_.Matches(x) && matcher2_.Matches(x); @@ -1071,8 +1110,9 @@ class EitherOfMatcher { template class Impl : public MatcherInterface { public: - Impl(const Matcher& matcher1, const Matcher& matcher2) - : matcher1_(matcher1), matcher2_(matcher2) {} + Impl(Matcher1 matcher1, Matcher2 matcher2) + : matcher1_(SafeMatcherCast(matcher1)), + matcher2_(SafeMatcherCast(matcher2)) {} virtual bool Matches(T x) const { return matcher1_.Matches(x) || matcher2_.Matches(x); @@ -1433,7 +1473,11 @@ class FieldMatcher { matcher_.DescribeNegationTo(os); } - void ExplainMatchResultTo(const Class& obj, ::std::ostream* os) const { + // The first argument of ExplainMatchResultTo() is needed to help + // Symbian's C++ compiler choose which overload to use. Its type is + // true_type iff the Field() matcher is used to match a pointer. + void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, + ::std::ostream* os) const { ::std::stringstream ss; matcher_.ExplainMatchResultTo(obj.*field_, &ss); const internal::string s = ss.str(); @@ -1442,9 +1486,13 @@ class FieldMatcher { } } - void ExplainMatchResultTo(const Class* p, ::std::ostream* os) const { + void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, + ::std::ostream* os) const { if (p != NULL) { - ExplainMatchResultTo(*p, os); + // Since *p has a field, it must be a class/struct/union type + // and thus cannot be a pointer. Therefore we pass false_type() + // as the first argument. + ExplainMatchResultTo(false_type(), *p, os); } } private: @@ -1452,18 +1500,12 @@ class FieldMatcher { const Matcher matcher_; }; -// Explains the result of matching an object against a field matcher. -template +// Explains the result of matching an object or pointer against a field matcher. +template void ExplainMatchResultTo(const FieldMatcher& matcher, - const Class& obj, ::std::ostream* os) { - matcher.ExplainMatchResultTo(obj, os); -} - -// Explains the result of matching a pointer against a field matcher. -template -void ExplainMatchResultTo(const FieldMatcher& matcher, - const Class* p, ::std::ostream* os) { - matcher.ExplainMatchResultTo(p, os); + const T& value, ::std::ostream* os) { + matcher.ExplainMatchResultTo( + typename ::testing::internal::is_pointer::type(), value, os); } // Implements the Property() matcher for matching a property @@ -1501,7 +1543,11 @@ class PropertyMatcher { matcher_.DescribeNegationTo(os); } - void ExplainMatchResultTo(const Class& obj, ::std::ostream* os) const { + // The first argument of ExplainMatchResultTo() is needed to help + // Symbian's C++ compiler choose which overload to use. Its type is + // true_type iff the Property() matcher is used to match a pointer. + void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, + ::std::ostream* os) const { ::std::stringstream ss; matcher_.ExplainMatchResultTo((obj.*property_)(), &ss); const internal::string s = ss.str(); @@ -1510,9 +1556,13 @@ class PropertyMatcher { } } - void ExplainMatchResultTo(const Class* p, ::std::ostream* os) const { + void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, + ::std::ostream* os) const { if (p != NULL) { - ExplainMatchResultTo(*p, os); + // Since *p has a property method, it must be a + // class/struct/union type and thus cannot be a pointer. + // Therefore we pass false_type() as the first argument. + ExplainMatchResultTo(false_type(), *p, os); } } private: @@ -1520,18 +1570,13 @@ class PropertyMatcher { const Matcher matcher_; }; -// Explains the result of matching an object against a property matcher. -template -void ExplainMatchResultTo(const PropertyMatcher& matcher, - const Class& obj, ::std::ostream* os) { - matcher.ExplainMatchResultTo(obj, os); -} - -// Explains the result of matching a pointer against a property matcher. -template +// Explains the result of matching an object or pointer against a +// property matcher. +template void ExplainMatchResultTo(const PropertyMatcher& matcher, - const Class* p, ::std::ostream* os) { - matcher.ExplainMatchResultTo(p, os); + const T& value, ::std::ostream* os) { + matcher.ExplainMatchResultTo( + typename ::testing::internal::is_pointer::type(), value, os); } // Type traits specifying various features of different functors for ResultOf. diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index fa510ba2..bbe44c38 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -263,11 +263,10 @@ void PrintTo(const T& value, ::std::ostream* os) { // // For protocol messages, we want to give people a chance to // override Google Mock's format by defining a PrintTo() or - // operator<<. For STL containers, we believe the Google Mock's - // format is superior to what util/gtl/stl-logging.h offers. - // Therefore we don't want it to be accidentally overridden by the - // latter (even if the user includes stl-logging.h through other - // headers indirectly, Google Mock's format will still be used). + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. DefaultPrintTo(IsContainerTest(0), value, os); } diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 0fc43d6d..af2e8ad2 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -143,7 +143,11 @@ class DefaultActionSpec { : file_(file), line_(line), matchers_(matchers), - extra_matcher_(_), + // By default, extra_matcher_ should match anything. However, + // we cannot initialize it with _ as that triggers a compiler + // bug in Symbian's C++ compiler (cannot decide between two + // overloaded constructors of Matcher). + extra_matcher_(A()), last_clause_(NONE) { } @@ -576,7 +580,11 @@ class Expectation : public ExpectationBase { : ExpectationBase(file, line), owner_(owner), matchers_(m), - extra_matcher_(_), + // By default, extra_matcher_ should match anything. However, + // we cannot initialize it with _ as that triggers a compiler + // bug in Symbian's C++ compiler (cannot decide between two + // overloaded constructors of Matcher). + extra_matcher_(A()), repeated_action_specified_(false), repeated_action_(DoDefault()), retires_on_saturation_(false), diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 922efca9..84e5a413 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -1495,5 +1495,157 @@ TEST(ThrowActionTest, ThrowsGivenExceptionInNullaryFunction) { #endif // GTEST_HAS_EXCEPTIONS +// Tests that ACTION_TEMPLATE works when there is no value parameter. +ACTION_TEMPLATE(CreateNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_0_VALUE_PARAMS()) { + return new T; +} + +TEST(ActionTemplateTest, WorksWithoutValueParam) { + const Action a = CreateNew(); + int* p = a.Perform(make_tuple()); + delete p; +} + +// Tests that ACTION_TEMPLATE works when there are value parameters. +ACTION_TEMPLATE(CreateNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_1_VALUE_PARAMS(a0)) { + return new T(a0); +} + +TEST(ActionTemplateTest, WorksWithValueParams) { + const Action a = CreateNew(42); + int* p = a.Perform(make_tuple()); + EXPECT_EQ(42, *p); + delete p; +} + +// Tests that ACTION_TEMPLATE works for integral template parameters. +ACTION_TEMPLATE(MyDeleteArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + delete std::tr1::get(args); +} + +// Resets a bool variable in the destructor. +class BoolResetter { + public: + explicit BoolResetter(bool* value) : value_(value) {} + ~BoolResetter() { *value_ = false; } + private: + bool* const value_; +}; + +TEST(ActionTemplateTest, WorksForIntegralTemplateParams) { + const Action a = MyDeleteArg<1>(); + int n = 0; + bool b = true; + BoolResetter* resetter = new BoolResetter(&b); + a.Perform(make_tuple(&n, resetter)); + EXPECT_FALSE(b); // Verifies that resetter is deleted. +} + +// Tests that ACTION_TEMPLATES works for template template parameters. +ACTION_TEMPLATE(ReturnSmartPointer, + HAS_1_TEMPLATE_PARAMS(template class, + Pointer), + AND_1_VALUE_PARAMS(pointee)) { + return Pointer(new pointee_type(pointee)); +} + +TEST(ActionTemplateTest, WorksForTemplateTemplateParameters) { + using ::testing::internal::linked_ptr; + const Action()> a = ReturnSmartPointer(42); + linked_ptr p = a.Perform(make_tuple()); + EXPECT_EQ(42, *p); +} + +// Tests that ACTION_TEMPLATE works for 10 template parameters. +template +struct GiantTemplate { + public: + explicit GiantTemplate(int a_value) : value(a_value) {} + int value; +}; + +ACTION_TEMPLATE(ReturnGiant, + HAS_10_TEMPLATE_PARAMS( + typename, T1, + typename, T2, + typename, T3, + int, k4, + bool, k5, + unsigned int, k6, + class, T7, + class, T8, + class, T9, + template class, T10), + AND_1_VALUE_PARAMS(value)) { + return GiantTemplate, T2, T3, k4, k5, k6, T7, T8, T9>(value); +} + +TEST(ActionTemplateTest, WorksFor10TemplateParameters) { + using ::testing::internal::linked_ptr; + typedef GiantTemplate, bool, double, 5, + true, 6, char, unsigned, int> Giant; + const Action a = ReturnGiant< + int, bool, double, 5, true, 6, char, unsigned, int, linked_ptr>(42); + Giant giant = a.Perform(make_tuple()); + EXPECT_EQ(42, giant.value); +} + +// Tests that ACTION_TEMPLATE works for 10 value parameters. +ACTION_TEMPLATE(ReturnSum, + HAS_1_TEMPLATE_PARAMS(typename, Number), + AND_10_VALUE_PARAMS(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)) { + return static_cast(v1) + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10; +} + +TEST(ActionTemplateTest, WorksFor10ValueParameters) { + const Action a = ReturnSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + EXPECT_EQ(55, a.Perform(make_tuple())); +} + +// Tests that ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded +// on the number of value parameters. + +ACTION(ReturnSum) { return 0; } + +ACTION_P(ReturnSum, x) { return x; } + +ACTION_TEMPLATE(ReturnSum, + HAS_1_TEMPLATE_PARAMS(typename, Number), + AND_2_VALUE_PARAMS(v1, v2)) { + return static_cast(v1) + v2; +} + +ACTION_TEMPLATE(ReturnSum, + HAS_1_TEMPLATE_PARAMS(typename, Number), + AND_3_VALUE_PARAMS(v1, v2, v3)) { + return static_cast(v1) + v2 + v3; +} + +ACTION_TEMPLATE(ReturnSum, + HAS_2_TEMPLATE_PARAMS(typename, Number, int, k), + AND_4_VALUE_PARAMS(v1, v2, v3, v4)) { + return static_cast(v1) + v2 + v3 + v4 + k; +} + +TEST(ActionTemplateTest, CanBeOverloadedOnNumberOfValueParameters) { + const Action a0 = ReturnSum(); + const Action a1 = ReturnSum(1); + const Action a2 = ReturnSum(1, 2); + const Action a3 = ReturnSum(1, 2, 3); + const Action a4 = ReturnSum(2000, 300, 40, 5); + EXPECT_EQ(0, a0.Perform(make_tuple())); + EXPECT_EQ(1, a1.Perform(make_tuple())); + EXPECT_EQ(3, a2.Perform(make_tuple())); + EXPECT_EQ(6, a3.Perform(make_tuple())); + EXPECT_EQ(12345, a4.Perform(make_tuple())); +} + } // namespace gmock_generated_actions_test } // namespace testing diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 82820fe0..ab5ca35c 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -366,6 +366,76 @@ TEST(MatcherCastTest, FromSameType) { EXPECT_FALSE(m2.Matches(1)); } +class Base {}; +class Derived : public Base {}; + +// Tests that SafeMatcherCast(m) works when m is a polymorphic matcher. +TEST(SafeMatcherCastTest, FromPolymorphicMatcher) { + Matcher m2 = SafeMatcherCast(Eq(32)); + EXPECT_TRUE(m2.Matches(' ')); + EXPECT_FALSE(m2.Matches('\n')); +} + +// Tests that SafeMatcherCast(m) works when m is a Matcher where T +// can be implicitly converted to U. +TEST(SafeMatcherCastTest, FromImplicitlyConvertibleType) { + Matcher m1 = DoubleEq(1.0); + Matcher m2 = SafeMatcherCast(m1); + EXPECT_TRUE(m2.Matches(1)); + EXPECT_FALSE(m2.Matches(2)); +} + +// Tests that SafeMatcherCast(m) works when m is a Matcher where T and U +// are pointers or references to a derived and a base class, correspondingly. +TEST(SafeMatcherCastTest, FromBaseClass) { + Derived d, d2; + Matcher m1 = Eq(&d); + Matcher m2 = SafeMatcherCast(m1); + EXPECT_TRUE(m2.Matches(&d)); + EXPECT_FALSE(m2.Matches(&d2)); + + Matcher m3 = Ref(d); + Matcher m4 = SafeMatcherCast(m3); + EXPECT_TRUE(m4.Matches(d)); + EXPECT_FALSE(m4.Matches(d2)); +} + +// Tests that SafeMatcherCast(m) works when m is a Matcher. +TEST(SafeMatcherCastTest, FromConstReferenceToReference) { + int n = 0; + Matcher m1 = Ref(n); + Matcher m2 = SafeMatcherCast(m1); + int n1 = 0; + EXPECT_TRUE(m2.Matches(n)); + EXPECT_FALSE(m2.Matches(n1)); +} + +// Tests that MatcherCast(m) works when m is a Matcher. +TEST(SafeMatcherCastTest, FromNonReferenceToConstReference) { + Matcher m1 = Eq(0); + Matcher m2 = SafeMatcherCast(m1); + EXPECT_TRUE(m2.Matches(0)); + EXPECT_FALSE(m2.Matches(1)); +} + +// Tests that SafeMatcherCast(m) works when m is a Matcher. +TEST(SafeMatcherCastTest, FromNonReferenceToReference) { + Matcher m1 = Eq(0); + Matcher m2 = SafeMatcherCast(m1); + int n = 0; + EXPECT_TRUE(m2.Matches(n)); + n = 1; + EXPECT_FALSE(m2.Matches(n)); +} + +// Tests that SafeMatcherCast(m) works when m is a Matcher. +TEST(SafeMatcherCastTest, FromSameType) { + Matcher m1 = Eq(0); + Matcher m2 = SafeMatcherCast(m1); + EXPECT_TRUE(m2.Matches(0)); + EXPECT_FALSE(m2.Matches(1)); +} + // Tests that A() matches any value of type T. TEST(ATest, MatchesAnyValue) { // Tests a matcher for a value type. @@ -626,9 +696,6 @@ TEST(RefTest, CanBeUsedAsMatcherForConstReference) { // used wherever Ref(base) can be used (Ref(derived) is a sub-type // of Ref(base), but not vice versa. -class Base {}; -class Derived : public Base {}; - TEST(RefTest, IsCovariant) { Base base, base2; Derived derived; @@ -1355,6 +1422,16 @@ TEST(NotTest, CanDescribeSelf) { EXPECT_EQ("is not equal to 5", Describe(m)); } +// Tests that monomorphic matchers are safely cast by the Not matcher. +TEST(NotTest, NotMatcherSafelyCastsMonomorphicMatchers) { + // greater_than_5 is a monomorphic matcher. + Matcher greater_than_5 = Gt(5); + + Matcher m = Not(greater_than_5); + Matcher m2 = Not(greater_than_5); + Matcher m3 = Not(m); +} + // Tests that AllOf(m1, ..., mn) matches any value that matches all of // the given matchers. TEST(AllOfTest, MatchesWhenAllMatch) { @@ -1415,6 +1492,21 @@ TEST(AllOfTest, CanDescribeSelf) { "(is not equal to 7))))", Describe(m)); } +// Tests that monomorphic matchers are safely cast by the AllOf matcher. +TEST(AllOfTest, AllOfMatcherSafelyCastsMonomorphicMatchers) { + // greater_than_5 and less_than_10 are monomorphic matchers. + Matcher greater_than_5 = Gt(5); + Matcher less_than_10 = Lt(10); + + Matcher m = AllOf(greater_than_5, less_than_10); + Matcher m2 = AllOf(greater_than_5, less_than_10); + Matcher m3 = AllOf(greater_than_5, m2); + + // Tests that BothOf works when composing itself. + Matcher m4 = AllOf(greater_than_5, less_than_10, less_than_10); + Matcher m5 = AllOf(greater_than_5, less_than_10, less_than_10); +} + // Tests that AnyOf(m1, ..., mn) matches any value that matches at // least one of the given matchers. TEST(AnyOfTest, MatchesWhenAnyMatches) { @@ -1473,6 +1565,21 @@ TEST(AnyOfTest, CanDescribeSelf) { Describe(m)); } +// Tests that monomorphic matchers are safely cast by the AnyOf matcher. +TEST(AnyOfTest, AnyOfMatcherSafelyCastsMonomorphicMatchers) { + // greater_than_5 and less_than_10 are monomorphic matchers. + Matcher greater_than_5 = Gt(5); + Matcher less_than_10 = Lt(10); + + Matcher m = AnyOf(greater_than_5, less_than_10); + Matcher m2 = AnyOf(greater_than_5, less_than_10); + Matcher m3 = AnyOf(greater_than_5, m2); + + // Tests that EitherOf works when composing itself. + Matcher m4 = AnyOf(greater_than_5, less_than_10, less_than_10); + Matcher m5 = AnyOf(greater_than_5, less_than_10, less_than_10); +} + // The following predicate function and predicate functor are for // testing the Truly(predicate) matcher. -- cgit v1.2.3 From c6a412397bc98f120d5e79d4a64e3972854b5af3 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 13 May 2009 23:38:40 +0000 Subject: Adds more tests for using SetArgumentPointee with protobufs; works around a compiler bug on Symbian that gmock-printers.h triggers; reduces template code bloat in gmock-matchers.h; avoids RTTI when it's disabled. --- include/gmock/gmock-matchers.h | 291 ++++++++++++++++++------------------ include/gmock/gmock-printers.h | 64 +++++--- include/gmock/internal/gmock-port.h | 2 + test/gmock-actions_test.cc | 64 +++++++- 4 files changed, 245 insertions(+), 176 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 5700fb25..bf049d45 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -960,10 +960,35 @@ GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "not equal to"); #undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ -// TODO(vladl@google.com): Move Impl outside of NotMatcher and rename it -// NotMatcherImpl to reduce compilation overhead and the size of the binary. -// This also applies to BothOfMatcher::Impl and EitherOfMatcher::Impl. -// +// 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 Matches(T x) const { + return !matcher_.Matches(x); + } + + virtual void DescribeTo(::std::ostream* os) const { + matcher_.DescribeNegationTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + matcher_.DescribeTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + matcher_.ExplainMatchResultTo(x, os); + } + private: + const Matcher matcher_; +}; + // Implements the Not(m) matcher, which matches a value that doesn't // match matcher m. template @@ -975,36 +1000,72 @@ class NotMatcher { // to match any type m can match. template operator Matcher() const { - return Matcher(new Impl(matcher_)); + return Matcher(new NotMatcherImpl(SafeMatcherCast(matcher_))); } private: - // Implements the Not(...) matcher for a particular argument type T. - template - class Impl : public MatcherInterface { - public: - explicit Impl(InnerMatcher matcher) - : matcher_(SafeMatcherCast(matcher)) {} + InnerMatcher matcher_; +}; - virtual bool Matches(T x) const { - return !matcher_.Matches(x); - } +// 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 { - matcher_.DescribeNegationTo(os); - } + virtual bool Matches(T x) const { + return matcher1_.Matches(x) && matcher2_.Matches(x); + } - virtual void DescribeNegationTo(::std::ostream* os) const { - matcher_.DescribeTo(os); - } + virtual void DescribeTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeTo(os); + *os << ") and ("; + matcher2_.DescribeTo(os); + *os << ")"; + } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - matcher_.ExplainMatchResultTo(x, os); - } - private: - const Matcher matcher_; - }; + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not "; + DescribeTo(os); + } - InnerMatcher matcher_; + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + if (Matches(x)) { + // When both matcher1_ and matcher2_ match x, we need to + // explain why *both* of them match. + ::std::stringstream ss1; + matcher1_.ExplainMatchResultTo(x, &ss1); + const internal::string s1 = ss1.str(); + + ::std::stringstream ss2; + matcher2_.ExplainMatchResultTo(x, &ss2); + const internal::string s2 = ss2.str(); + + if (s1 == "") { + *os << s2; + } else { + *os << s1; + if (s2 != "") { + *os << "; " << s2; + } + } + } else { + // Otherwise we only need to explain why *one* of them fails + // to match. + if (!matcher1_.Matches(x)) { + matcher1_.ExplainMatchResultTo(x, os); + } else { + matcher2_.ExplainMatchResultTo(x, os); + } + } + } + private: + const Matcher matcher1_; + const Matcher matcher2_; }; // Used for implementing the AllOf(m_1, ..., m_n) matcher, which @@ -1020,72 +1081,73 @@ class BothOfMatcher { // both Matcher1 and Matcher2 can match. template operator Matcher() const { - return Matcher(new Impl(matcher1_, matcher2_)); + return Matcher(new BothOfMatcherImpl(SafeMatcherCast(matcher1_), + SafeMatcherCast(matcher2_))); } private: - // Implements the AllOf(m1, m2) matcher for a particular argument - // type T. - template - class Impl : public MatcherInterface { - public: - Impl(Matcher1 matcher1, Matcher2 matcher2) - : matcher1_(SafeMatcherCast(matcher1)), - matcher2_(SafeMatcherCast(matcher2)) {} + Matcher1 matcher1_; + Matcher2 matcher2_; +}; - virtual bool Matches(T x) const { - return matcher1_.Matches(x) && matcher2_.Matches(x); - } +// Implements the AnyOf(m1, m2) matcher for a particular argument type +// T. We do not nest it inside the AnyOfMatcher class template, as +// that will prevent different instantiations of AnyOfMatcher from +// sharing the same EitherOfMatcherImpl class. +template +class EitherOfMatcherImpl : public MatcherInterface { + public: + EitherOfMatcherImpl(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 bool Matches(T x) const { + return matcher1_.Matches(x) || matcher2_.Matches(x); + } - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not "; - DescribeTo(os); - } + virtual void DescribeTo(::std::ostream* os) const { + *os << "("; + matcher1_.DescribeTo(os); + *os << ") or ("; + matcher2_.DescribeTo(os); + *os << ")"; + } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - if (Matches(x)) { - // When both matcher1_ and matcher2_ match x, we need to - // explain why *both* of them match. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); - - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); - - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } - } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not "; + DescribeTo(os); + } + + virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { + if (Matches(x)) { + // If either matcher1_ or matcher2_ matches x, we just need + // to explain why *one* of them matches. + if (matcher1_.Matches(x)) { + matcher1_.ExplainMatchResultTo(x, os); } else { - // Otherwise we only need to explain why *one* of them fails - // to match. - if (!matcher1_.Matches(x)) { - matcher1_.ExplainMatchResultTo(x, os); - } else { - matcher2_.ExplainMatchResultTo(x, os); + matcher2_.ExplainMatchResultTo(x, os); + } + } else { + // Otherwise we need to explain why *neither* matches. + ::std::stringstream ss1; + matcher1_.ExplainMatchResultTo(x, &ss1); + const internal::string s1 = ss1.str(); + + ::std::stringstream ss2; + matcher2_.ExplainMatchResultTo(x, &ss2); + const internal::string s2 = ss2.str(); + + if (s1 == "") { + *os << s2; + } else { + *os << s1; + if (s2 != "") { + *os << "; " << s2; } } } - private: - const Matcher matcher1_; - const Matcher matcher2_; - }; - - Matcher1 matcher1_; - Matcher2 matcher2_; + } + private: + const Matcher matcher1_; + const Matcher matcher2_; }; // Used for implementing the AnyOf(m_1, ..., m_n) matcher, which @@ -1102,69 +1164,10 @@ class EitherOfMatcher { // both Matcher1 and Matcher2 can match. template operator Matcher() const { - return Matcher(new Impl(matcher1_, matcher2_)); + return Matcher(new EitherOfMatcherImpl(SafeMatcherCast(matcher1_), + SafeMatcherCast(matcher2_))); } private: - // Implements the AnyOf(m1, m2) matcher for a particular argument - // type T. - template - class Impl : public MatcherInterface { - public: - Impl(Matcher1 matcher1, Matcher2 matcher2) - : matcher1_(SafeMatcherCast(matcher1)), - matcher2_(SafeMatcherCast(matcher2)) {} - - virtual bool Matches(T x) const { - return matcher1_.Matches(x) || matcher2_.Matches(x); - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "("; - matcher1_.DescribeTo(os); - *os << ") or ("; - matcher2_.DescribeTo(os); - *os << ")"; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not "; - DescribeTo(os); - } - - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - if (Matches(x)) { - // If either matcher1_ or matcher2_ matches x, we just need - // to explain why *one* of them matches. - if (matcher1_.Matches(x)) { - matcher1_.ExplainMatchResultTo(x, os); - } else { - matcher2_.ExplainMatchResultTo(x, os); - } - } else { - // Otherwise we need to explain why *neither* matches. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); - - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); - - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } - } - } - } - private: - const Matcher matcher1_; - const Matcher matcher2_; - }; - Matcher1 matcher1_; Matcher2 matcher2_; }; diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index bbe44c38..6997a6c1 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -211,7 +211,9 @@ class UniversalPrinter; // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template -void DefaultPrintTo(IsContainer, const C& container, ::std::ostream* os) { +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; size_t count = 0; @@ -234,9 +236,31 @@ void DefaultPrintTo(IsContainer, const C& container, ::std::ostream* os) { *os << '}'; } -// Used to print a value when the user doesn't define PrintTo() for it. +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) template -void DefaultPrintTo(IsNotContainer, const T& value, ::std::ostream* os) { +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // We cannot use implicit_cast or static_cast here, as they don't + // work when p is a function pointer. + *os << reinterpret_cast(p); + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -253,10 +277,11 @@ void DefaultPrintTo(IsNotContainer, const T& value, ::std::ostream* os) { // wants). template void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first argument - // determines which version will be picked. If T is an STL-style - // container, the version for container will be called. Otherwise - // the generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -267,7 +292,14 @@ void PrintTo(const T& value, ::std::ostream* os) { // incompatible with Google Mock's format for the container // elements; therefore we check for container types here to ensure // that our format is used. - DefaultPrintTo(IsContainerTest(0), value, os); + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells @@ -323,22 +355,6 @@ inline void PrintTo(wchar_t* s, ::std::ostream* os) { } #endif -// Overload for pointers that are neither char pointers nor member -// pointers. (A member variable pointer or member function pointer -// doesn't really points to a location in the address space. Their -// representation is implementation-defined. Therefore they will be -// printed as raw bytes.) -template -void PrintTo(T* p, ::std::ostream* os) { - if (p == NULL) { - *os << "NULL"; - } else { - // We cannot use implicit_cast or static_cast here, as they don't - // work when p is a function pointer. - *os << reinterpret_cast(p); - } -} - // Overload for C arrays. Multi-dimensional arrays are printed // properly. diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index d242c8e4..75be9edd 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -162,7 +162,9 @@ inline To down_cast(From* f) { // so we only accept pointers implicit_cast(0); } +#if GTEST_HAS_RTTI assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif return static_cast(f); } diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index e4939e1a..24462609 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -646,16 +646,15 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointee) { #if GMOCK_HAS_PROTOBUF_ -// Tests that SetArgumentPointee(proto_buffer) sets the variable -// pointed to by the N-th (0-based) argument to proto_buffer. +// Tests that SetArgumentPointee(proto_buffer) sets the v1 protobuf +// variable pointed to by the N-th (0-based) argument to proto_buffer. TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferType) { - typedef void MyFunction(bool, TestMessage*); TestMessage* const msg = new TestMessage; msg->set_member("yes"); TestMessage orig_msg; orig_msg.CopyFrom(*msg); - Action a = SetArgumentPointee<1>(*msg); + Action a = SetArgumentPointee<1>(*msg); // SetArgumentPointee(proto_buffer) makes a copy of proto_buffer // s.t. the action works even when the original proto_buffer has // died. We ensure this behavior by deleting msg before using the @@ -668,18 +667,41 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferType) { EXPECT_TRUE(orig_msg.Equals(dest)); } -// Tests that SetArgumentPointee(proto2_buffer) sets the variable -// pointed to by the N-th (0-based) argument to proto2_buffer. +// Tests that SetArgumentPointee(proto_buffer) sets the +// ::ProtocolMessage variable pointed to by the N-th (0-based) +// argument to proto_buffer. +TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferBaseType) { + TestMessage* const msg = new TestMessage; + msg->set_member("yes"); + TestMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgumentPointee<1>(*msg); + // SetArgumentPointee(proto_buffer) makes a copy of proto_buffer + // s.t. the action works even when the original proto_buffer has + // died. We ensure this behavior by deleting msg before using the + // action. + delete msg; + + TestMessage dest; + ::ProtocolMessage* const dest_base = &dest; + EXPECT_FALSE(orig_msg.Equals(dest)); + a.Perform(make_tuple(true, dest_base)); + EXPECT_TRUE(orig_msg.Equals(dest)); +} + +// Tests that SetArgumentPointee(proto2_buffer) sets the v2 +// protobuf variable pointed to by the N-th (0-based) argument to +// proto2_buffer. TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferType) { using testing::internal::FooMessage; - typedef void MyFunction(bool, FooMessage*); FooMessage* const msg = new FooMessage; msg->set_int_field(2); msg->set_string_field("hi"); FooMessage orig_msg; orig_msg.CopyFrom(*msg); - Action a = SetArgumentPointee<1>(*msg); + Action a = SetArgumentPointee<1>(*msg); // SetArgumentPointee(proto2_buffer) makes a copy of // proto2_buffer s.t. the action works even when the original // proto2_buffer has died. We ensure this behavior by deleting msg @@ -693,6 +715,32 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferType) { EXPECT_EQ("hi", dest.string_field()); } +// Tests that SetArgumentPointee(proto2_buffer) sets the +// proto2::Message variable pointed to by the N-th (0-based) argument +// to proto2_buffer. +TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferBaseType) { + using testing::internal::FooMessage; + FooMessage* const msg = new FooMessage; + msg->set_int_field(2); + msg->set_string_field("hi"); + FooMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgumentPointee<1>(*msg); + // SetArgumentPointee(proto2_buffer) makes a copy of + // proto2_buffer s.t. the action works even when the original + // proto2_buffer has died. We ensure this behavior by deleting msg + // before using the action. + delete msg; + + FooMessage dest; + dest.set_int_field(0); + ::proto2::Message* const dest_base = &dest; + a.Perform(make_tuple(true, dest_base)); + EXPECT_EQ(2, dest.int_field()); + EXPECT_EQ("hi", dest.string_field()); +} + #endif // GMOCK_HAS_PROTOBUF_ // Tests that SetArrayArgument(first, last) sets the elements of the array -- cgit v1.2.3 From 16cf473930c01cd7a1a51dff65f22c541fbad5b8 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 May 2009 20:55:30 +0000 Subject: Finishes SafeMatcherCast by catching lossy arithmetic conversions at compile-time; uses ACTION_TEMPLATE to simplify the definition of many actions; makes mock object uncopyable; teaches gmock doctor about wrong MOCK_METHODn. --- include/gmock/gmock-generated-actions.h | 890 +++++--------------------- include/gmock/gmock-generated-actions.h.pump | 290 +++------ include/gmock/gmock-matchers.h | 17 +- include/gmock/gmock-printers.h | 11 +- include/gmock/gmock-spec-builders.h | 14 + include/gmock/internal/gmock-internal-utils.h | 157 ++++- scripts/gmock_doctor.py | 29 +- test/gmock-internal-utils_test.cc | 146 ++++- test/gmock-matchers_test.cc | 17 +- 9 files changed, 617 insertions(+), 954 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 6d49c600..fa02faaa 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -443,264 +443,6 @@ class CallableHelper { }; // class CallableHelper -// Invokes a nullary callable argument. -template -class InvokeArgumentAction0 { - public: - template - static Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args)); - } -}; - -// Invokes a unary callable argument with the given argument. -template -class InvokeArgumentAction1 { - public: - // We deliberately pass a1 by value instead of const reference here - // in case it is a C-string literal. - // - // Since this function is defined inline, the compiler can get rid - // of the copying of the arguments. Therefore the performance won't - // be hurt. - explicit InvokeArgumentAction1(A1 a1) : arg1_(a1) {} - - template - Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args), arg1_); - } - private: - const A1 arg1_; -}; - -// Invokes a binary callable argument with the given arguments. -template -class InvokeArgumentAction2 { - public: - InvokeArgumentAction2(A1 a1, A2 a2) : - arg1_(a1), arg2_(a2) {} - - template - Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args), arg1_, arg2_); - } - private: - const A1 arg1_; - const A2 arg2_; -}; - -// Invokes a ternary callable argument with the given arguments. -template -class InvokeArgumentAction3 { - public: - InvokeArgumentAction3(A1 a1, A2 a2, A3 a3) : - arg1_(a1), arg2_(a2), arg3_(a3) {} - - template - Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args), arg1_, arg2_, - arg3_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; -}; - -// Invokes a 4-ary callable argument with the given arguments. -template -class InvokeArgumentAction4 { - public: - InvokeArgumentAction4(A1 a1, A2 a2, A3 a3, A4 a4) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4) {} - - template - Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args), arg1_, arg2_, - arg3_, arg4_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; -}; - -// Invokes a 5-ary callable argument with the given arguments. -template -class InvokeArgumentAction5 { - public: - InvokeArgumentAction5(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5) {} - - template - Result Perform(const ArgumentTuple& args) { - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function(arg1_, arg2_, arg3_, arg4_, arg5_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; -}; - -// Invokes a 6-ary callable argument with the given arguments. -template -class InvokeArgumentAction6 { - public: - InvokeArgumentAction6(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6) {} - - template - Result Perform(const ArgumentTuple& args) { - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; -}; - -// Invokes a 7-ary callable argument with the given arguments. -template -class InvokeArgumentAction7 { - public: - InvokeArgumentAction7(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), - arg7_(a7) {} - - template - Result Perform(const ArgumentTuple& args) { - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; -}; - -// Invokes a 8-ary callable argument with the given arguments. -template -class InvokeArgumentAction8 { - public: - InvokeArgumentAction8(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, - A8 a8) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), - arg7_(a7), arg8_(a8) {} - - template - Result Perform(const ArgumentTuple& args) { - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; - const A8 arg8_; -}; - -// Invokes a 9-ary callable argument with the given arguments. -template -class InvokeArgumentAction9 { - public: - InvokeArgumentAction9(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, - A9 a9) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), - arg7_(a7), arg8_(a8), arg9_(a9) {} - - template - Result Perform(const ArgumentTuple& args) { - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, - arg9_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; - const A8 arg8_; - const A9 arg9_; -}; - -// Invokes a 10-ary callable argument with the given arguments. -template -class InvokeArgumentAction10 { - public: - InvokeArgumentAction10(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, - A8 a8, A9 a9, A10 a10) : - arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6), - arg7_(a7), arg8_(a8), arg9_(a9), arg10_(a10) {} - - template - Result Perform(const ArgumentTuple& args) { - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, - arg9_, arg10_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; - const A8 arg8_; - const A9 arg9_; - const A10 arg10_; -}; - // 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) \ @@ -1140,140 +882,6 @@ inline internal::ReferenceWrapper ByRef(T& l_value) { // NOLINT return internal::ReferenceWrapper(l_value); } -// 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. -template -inline PolymorphicAction > InvokeArgument() { - return MakePolymorphicAction(internal::InvokeArgumentAction0()); -} - -// We deliberately pass a1 by value instead of const reference here in -// case it is a C-string literal. If we had declared the parameter as -// 'const A1& a1' and write InvokeArgument<0>("Hi"), the compiler -// would've thought A1 is 'char[3]', which causes trouble as the -// implementation needs to copy a value of type A1. By declaring the -// parameter as 'A1 a1', the compiler will correctly infer that A1 is -// 'const char*' when it sees InvokeArgument<0>("Hi"). -// -// Since this function is defined inline, the compiler can get rid of -// the copying of the arguments. Therefore the performance won't be -// hurt. -template -inline PolymorphicAction > -InvokeArgument(A1 a1) { - return MakePolymorphicAction(internal::InvokeArgumentAction1(a1)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2) { - return MakePolymorphicAction( - internal::InvokeArgumentAction2(a1, a2)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3) { - return MakePolymorphicAction( - internal::InvokeArgumentAction3(a1, a2, a3)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4) { - return MakePolymorphicAction( - internal::InvokeArgumentAction4(a1, a2, a3, a4)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - return MakePolymorphicAction( - internal::InvokeArgumentAction5(a1, a2, a3, a4, - a5)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { - return MakePolymorphicAction( - internal::InvokeArgumentAction6(a1, a2, a3, - a4, a5, a6)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { - return MakePolymorphicAction( - internal::InvokeArgumentAction7(a1, a2, - a3, a4, a5, a6, a7)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { - return MakePolymorphicAction( - internal::InvokeArgumentAction8(a1, - a2, a3, a4, a5, a6, a7, a8)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { - return MakePolymorphicAction( - internal::InvokeArgumentAction9(a1, a2, a3, a4, a5, a6, a7, a8, a9)); -} - -template -inline PolymorphicAction > -InvokeArgument(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, - A10 a10) { - return MakePolymorphicAction( - internal::InvokeArgumentAction10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); -} - // WithoutArgs(inner_action) can be used in a mock function with a // non-empty argument list to perform inner_action, which takes no // argument. In other words, it adapts an action accepting no @@ -2715,271 +2323,153 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, // updated. namespace testing { -namespace internal { - -// Saves argument #0 to where the pointer points. -ACTION_P(SaveArg0, pointer) { *pointer = arg0; } +// 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. -// Assigns 'value' to the variable referenced by argument #0. -ACTION_P(SetArg0Referee, value) { - // Ensures that argument #0 is a reference. If you get a compiler - // error on the next line, you are using SetArgReferee(value) in - // a mock function whose k-th (0-based) argument is not a reference. - GMOCK_COMPILE_ASSERT_(internal::is_reference::value, - SetArgReferee_must_be_used_with_a_reference_argument); - arg0 = value; +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + return internal::CallableHelper::Call( + ::std::tr1::get(args)); } -// ReturnNewAction creates and returns a new instance of an object each time -// it is performed. It is overloaded to work with constructors that take -// different numbers of arguments. -// Returns a new instance of T using a nullary constructor with the given -// arguments. -template -class ReturnNewAction0 { - public: - ReturnNewAction0() {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(); - } - private: -}; - -// Returns a new instance of T using a unary constructor with the given -// arguments. -template -class ReturnNewAction1 { - public: - explicit ReturnNewAction1(A1 a1) : arg1_(a1) {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_); - } - private: - const A1 arg1_; -}; - -// Returns a new instance of T using a binary constructor with the given -// arguments. -template -class ReturnNewAction2 { - public: - ReturnNewAction2(A1 a1, A2 a2) : arg1_(a1), arg2_(a2) {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_); - } - private: - const A1 arg1_; - const A2 arg2_; -}; - -// Returns a new instance of T using a ternary constructor with the given -// arguments. -template -class ReturnNewAction3 { - public: - ReturnNewAction3(A1 a1, A2 a2, A3 a3) : arg1_(a1), arg2_(a2), arg3_(a3) {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; -}; - -// Returns a new instance of T using a 4-ary constructor with the given -// arguments. -template -class ReturnNewAction4 { - public: - ReturnNewAction4(A1 a1, A2 a2, A3 a3, A4 a4) : arg1_(a1), arg2_(a2), - arg3_(a3), arg4_(a4) {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; -}; - -// Returns a new instance of T using a 5-ary constructor with the given -// arguments. -template -class ReturnNewAction5 { - public: - ReturnNewAction5(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : arg1_(a1), arg2_(a2), - arg3_(a3), arg4_(a4), arg5_(a5) {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_, arg5_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; -}; - -// Returns a new instance of T using a 6-ary constructor with the given -// arguments. -template -class ReturnNewAction6 { - public: - ReturnNewAction6(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : arg1_(a1), - arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6) {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; -}; - -// Returns a new instance of T using a 7-ary constructor with the given -// arguments. -template -class ReturnNewAction7 { - public: - ReturnNewAction7(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, - A7 a7) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), - arg6_(a6), arg7_(a7) {} +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(p0)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0); +} - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; -}; +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_2_VALUE_PARAMS(p0, p1)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1); +} -// Returns a new instance of T using a 8-ary constructor with the given -// arguments. -template -class ReturnNewAction8 { - public: - ReturnNewAction8(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, - A8 a8) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), - arg6_(a6), arg7_(a7), arg8_(a8) {} +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_3_VALUE_PARAMS(p0, p1, p2)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2); +} - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; - const A8 arg8_; -}; +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3); +} -// Returns a new instance of T using a 9-ary constructor with the given -// arguments. -template -class ReturnNewAction9 { - public: - ReturnNewAction9(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, - A9 a9) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), - arg6_(a6), arg7_(a7), arg8_(a8), arg9_(a9) {} +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4); +} - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, arg9_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; - const A8 arg8_; - const A9 arg9_; -}; +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5); +} -// Returns a new instance of T using a 10-ary constructor with the given -// arguments. -template -class ReturnNewAction10 { - public: - ReturnNewAction10(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, - A9 a9, A10 a10) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), - arg6_(a6), arg7_(a7), arg8_(a8), arg9_(a9), arg10_(a10) {} +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6); +} - template - Result Perform(const ArgumentTuple& /* args */) { - return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, arg9_, - arg10_); - } - private: - const A1 arg1_; - const A2 arg2_; - const A3 arg3_; - const A4 arg4_; - const A5 arg5_; - const A6 arg6_; - const A7 arg7_; - const A8 arg8_; - const A9 arg9_; - const A10 arg10_; -}; +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7); +} -// Deletes the object pointed to by argument #0. -ACTION(DeleteArg0) { delete arg0; } +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8); +} -} // namespace internal +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { + return internal::CallableHelper::Call( + ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); +} // Action SaveArg(pointer) saves the k-th (0-based) argument of the // mock function to *pointer. -template -inline internal::WithArgsAction, k> -SaveArg(const Pointer& pointer) { - return WithArg(internal::SaveArg0(pointer)); +ACTION_TEMPLATE(SaveArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(pointer)) { + *pointer = ::std::tr1::get(args); } // Action SetArgReferee(value) assigns 'value' to the variable // referenced by the k-th (0-based) argument of the mock function. -template -inline internal::WithArgsAction, k> -SetArgReferee(const Value& value) { - return WithArg(internal::SetArg0Referee(value)); +ACTION_TEMPLATE(SetArgReferee, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(value)) { + typedef typename ::std::tr1::tuple_element::type argk_type; + // Ensures that argument #k is a reference. If you get a compiler + // error on the next line, you are using SetArgReferee(value) in + // a mock function whose k-th (0-based) argument is not a reference. + GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + SetArgReferee_must_be_used_with_a_reference_argument); + ::std::tr1::get(args) = value; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-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. +ACTION_TEMPLATE(SetArrayArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_2_VALUE_PARAMS(first, last)) { + // Microsoft compiler deprecates ::std::copy, so we want to suppress warning + // 4996 (Function call with parameters that may be unsafe) there. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. +#endif + ::std::copy(first, last, ::std::tr1::get(args)); +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif } // Various overloads for ReturnNew(). @@ -2987,106 +2477,78 @@ SetArgReferee(const Value& value) { // 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. -template -inline PolymorphicAction > -ReturnNew() { - return MakePolymorphicAction( - internal::ReturnNewAction0()); +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_0_VALUE_PARAMS()) { + return new T(); } -template -inline PolymorphicAction > -ReturnNew(A1 a1) { - return MakePolymorphicAction( - internal::ReturnNewAction1(a1)); +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_1_VALUE_PARAMS(p0)) { + return new T(p0); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2) { - return MakePolymorphicAction( - internal::ReturnNewAction2(a1, a2)); +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_2_VALUE_PARAMS(p0, p1)) { + return new T(p0, p1); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3) { - return MakePolymorphicAction( - internal::ReturnNewAction3(a1, a2, a3)); +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_3_VALUE_PARAMS(p0, p1, p2)) { + return new T(p0, p1, p2); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4) { - return MakePolymorphicAction( - internal::ReturnNewAction4(a1, a2, a3, a4)); +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { + return new T(p0, p1, p2, p3); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - return MakePolymorphicAction( - internal::ReturnNewAction5(a1, a2, a3, a4, a5)); +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); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { - return MakePolymorphicAction( - internal::ReturnNewAction6(a1, a2, a3, a4, a5, - a6)); +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); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { - return MakePolymorphicAction( - internal::ReturnNewAction7(a1, a2, a3, a4, - a5, a6, a7)); +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); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { - return MakePolymorphicAction( - internal::ReturnNewAction8(a1, a2, a3, - a4, a5, a6, a7, a8)); +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); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { - return MakePolymorphicAction( - internal::ReturnNewAction9(a1, a2, - a3, a4, a5, a6, a7, a8, a9)); +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); } -template -inline PolymorphicAction > -ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, - A10 a10) { - return MakePolymorphicAction( - internal::ReturnNewAction10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); +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); } // Action DeleteArg() deletes the k-th (0-based) argument of the mock // function. -template -inline internal::WithArgsAction -DeleteArg() { - return WithArg(internal::DeleteArg0()); +ACTION_TEMPLATE(DeleteArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + delete ::std::tr1::get(args); } // Action Throw(exception) can be used in a mock function of any type diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 39f80804..b5223a34 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -198,77 +198,6 @@ $var Ts = [[$for j, [[T$j]]]] }; // class CallableHelper -// Invokes a nullary callable argument. -template -class InvokeArgumentAction0 { - public: - template - static Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args)); - } -}; - -// Invokes a unary callable argument with the given argument. -template -class InvokeArgumentAction1 { - public: - // We deliberately pass a1 by value instead of const reference here - // in case it is a C-string literal. - // - // Since this function is defined inline, the compiler can get rid - // of the copying of the arguments. Therefore the performance won't - // be hurt. - explicit InvokeArgumentAction1(A1 a1) : arg1_(a1) {} - - template - Result Perform(const ArgumentTuple& args) { - return CallableHelper::Call(::std::tr1::get(args), arg1_); - } - private: - const A1 arg1_; -}; - -$range i 2..n -$for i [[ -$var arity = [[$if i==2 [[binary]] $elif i==3 [[ternary]] $else [[$i-ary]]]] -$range j 1..i -$var typename_As = [[$for j, [[typename A$j]]]] -$var args_ = [[$for j, [[arg$j[[]]_]]]] - -// Invokes a $arity callable argument with the given arguments. -template -class InvokeArgumentAction$i { - public: - InvokeArgumentAction$i($for j, [[A$j a$j]]) : - $for j, [[arg$j[[]]_(a$j)]] {} - - template - Result Perform(const ArgumentTuple& args) { -$if i <= 4 [[ - - return CallableHelper::Call(::std::tr1::get(args), $args_); - -]] $else [[ - - // We extract the callable to a variable before invoking it, in - // case it is a functor passed by value and its operator() is not - // const. - typename ::std::tr1::tuple_element::type function = - ::std::tr1::get(args); - return function($args_); - -]] - } - private: -$for j [[ - - const A$j arg$j[[]]_; -]] - -}; - -]] - // 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) \ @@ -478,74 +407,6 @@ inline internal::ReferenceWrapper ByRef(T& l_value) { // NOLINT return internal::ReferenceWrapper(l_value); } -// 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. -template -inline PolymorphicAction > InvokeArgument() { - return MakePolymorphicAction(internal::InvokeArgumentAction0()); -} - -// We deliberately pass a1 by value instead of const reference here in -// case it is a C-string literal. If we had declared the parameter as -// 'const A1& a1' and write InvokeArgument<0>("Hi"), the compiler -// would've thought A1 is 'char[3]', which causes trouble as the -// implementation needs to copy a value of type A1. By declaring the -// parameter as 'A1 a1', the compiler will correctly infer that A1 is -// 'const char*' when it sees InvokeArgument<0>("Hi"). -// -// Since this function is defined inline, the compiler can get rid of -// the copying of the arguments. Therefore the performance won't be -// hurt. -template -inline PolymorphicAction > -InvokeArgument(A1 a1) { - return MakePolymorphicAction(internal::InvokeArgumentAction1(a1)); -} - -$range i 2..n -$for i [[ -$range j 1..i -$var typename_As = [[$for j, [[typename A$j]]]] -$var As = [[$for j, [[A$j]]]] -$var Aas = [[$for j, [[A$j a$j]]]] -$var as = [[$for j, [[a$j]]]] - -template -inline PolymorphicAction > -InvokeArgument($Aas) { - return MakePolymorphicAction( - internal::InvokeArgumentAction$i($as)); -} - -]] - // WithoutArgs(inner_action) can be used in a mock function with a // non-empty argument list to perform inner_action, which takes no // argument. In other words, it adapts an action accepting no @@ -1025,76 +886,89 @@ $$ // show up in the generated code. // updated. namespace testing { -namespace internal { - -// Saves argument #0 to where the pointer points. -ACTION_P(SaveArg0, pointer) { *pointer = arg0; } - -// Assigns 'value' to the variable referenced by argument #0. -ACTION_P(SetArg0Referee, value) { - // Ensures that argument #0 is a reference. If you get a compiler - // error on the next line, you are using SetArgReferee(value) in - // a mock function whose k-th (0-based) argument is not a reference. - GMOCK_COMPILE_ASSERT_(internal::is_reference::value, - SetArgReferee_must_be_used_with_a_reference_argument); - arg0 = value; -} +// 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. -// ReturnNewAction creates and returns a new instance of an object each time -// it is performed. It is overloaded to work with constructors that take -// different numbers of arguments. $range i 0..n $for i [[ -$var arity = [[ $if i==0 [[nullary]] - $elif i==1 [[unary]] - $elif i==2 [[binary]] - $elif i==3 [[ternary]] - $else [[$i-ary]]]] -$range j 1..i -$var typename_As = [[$for j [[, typename A$j]]]] -$var args_ = [[$for j, [[arg$j[[]]_]]]] - -// Returns a new instance of T using a $arity constructor with the given -// arguments. -template -class ReturnNewAction$i { - public: - $if i==1 [[explicit ]]ReturnNewAction$i($for j, [[A$j a$j]])$if i>0 [[ : ]] -$for j, [[arg$j[[]]_(a$j)]] {} - - template - Result Perform(const ArgumentTuple& /* args */) { - return new T($args_); - } - private: -$for j [[ - - const A$j arg$j[[]]_; -]] +$range j 0..i-1 -}; +ACTION_TEMPLATE(InvokeArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) { + return internal::CallableHelper::Call( + ::std::tr1::get(args)$for j [[, p$j]]); +} ]] -// Deletes the object pointed to by argument #0. -ACTION(DeleteArg0) { delete arg0; } - -} // namespace internal - // Action SaveArg(pointer) saves the k-th (0-based) argument of the // mock function to *pointer. -template -inline internal::WithArgsAction, k> -SaveArg(const Pointer& pointer) { - return WithArg(internal::SaveArg0(pointer)); +ACTION_TEMPLATE(SaveArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(pointer)) { + *pointer = ::std::tr1::get(args); } // Action SetArgReferee(value) assigns 'value' to the variable // referenced by the k-th (0-based) argument of the mock function. -template -inline internal::WithArgsAction, k> -SetArgReferee(const Value& value) { - return WithArg(internal::SetArg0Referee(value)); +ACTION_TEMPLATE(SetArgReferee, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(value)) { + typedef typename ::std::tr1::tuple_element::type argk_type; + // Ensures that argument #k is a reference. If you get a compiler + // error on the next line, you are using SetArgReferee(value) in + // a mock function whose k-th (0-based) argument is not a reference. + GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + SetArgReferee_must_be_used_with_a_reference_argument); + ::std::tr1::get(args) = value; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-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. +ACTION_TEMPLATE(SetArrayArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_2_VALUE_PARAMS(first, last)) { + // Microsoft compiler deprecates ::std::copy, so we want to suppress warning + // 4996 (Function call with parameters that may be unsafe) there. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. +#endif + ::std::copy(first, last, ::std::tr1::get(args)); +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif } // Various overloads for ReturnNew(). @@ -1104,27 +978,23 @@ SetArgReferee(const Value& value) { // a1, a2, ..., and a_k. The caller assumes ownership of the returned value. $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 Aas = [[$for j, [[A$j a$j]]]] -$var as = [[$for j, [[a$j]]]] +$range j 0..i-1 +$var ps = [[$for j, [[p$j]]]] -template -inline PolymorphicAction > -ReturnNew($Aas) { - return MakePolymorphicAction( - internal::ReturnNewAction$i($as)); +ACTION_TEMPLATE(ReturnNew, + HAS_1_TEMPLATE_PARAMS(typename, T), + AND_$i[[]]_VALUE_PARAMS($ps)) { + return new T($ps); } ]] // Action DeleteArg() deletes the k-th (0-based) argument of the mock // function. -template -inline internal::WithArgsAction -DeleteArg() { - return WithArg(internal::DeleteArg0()); +ACTION_TEMPLATE(DeleteArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + delete ::std::tr1::get(args); } // Action Throw(exception) can be used in a mock function of any type diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index bf049d45..0497be27 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -39,6 +39,7 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #include +#include #include // NOLINT #include #include @@ -340,6 +341,16 @@ Matcher SafeMatcherCast(const Matcher& matcher) { GMOCK_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 GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU; + const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; + const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; + GMOCK_COMPILE_ASSERT_( + kTIsOther || kUIsOther || + (internal::LosslessArithmeticConvertible::value), + conversion_of_arithmetic_types_must_be_lossless); return MatcherCast(matcher); } @@ -1164,8 +1175,8 @@ class EitherOfMatcher { // both Matcher1 and Matcher2 can match. template operator Matcher() const { - return Matcher(new EitherOfMatcherImpl(SafeMatcherCast(matcher1_), - SafeMatcherCast(matcher2_))); + return Matcher(new EitherOfMatcherImpl( + SafeMatcherCast(matcher1_), SafeMatcherCast(matcher2_))); } private: Matcher1 matcher1_; @@ -1184,7 +1195,7 @@ class TrulyMatcher { // argument is passed by reference as the predicate may be // interested in the address of the argument. template - bool Matches(T& x) const { + bool Matches(T& x) const { // NOLINT #if GTEST_OS_WINDOWS // MSVC warns about converting a value into bool (warning 4800). #pragma warning(push) // Saves the current warning state. diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 6997a6c1..99002434 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -341,12 +341,11 @@ inline void PrintTo(char* s, ::std::ostream* os) { PrintTo(implicit_cast(s), os); } -// MSVC compiler can be configured to define whar_t as a typedef -// of unsigned short. Defining an overload for const wchar_t* in that case -// would cause pointers to unsigned shorts be printed as wide strings, -// possibly accessing more memory than intended and causing invalid -// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when -// wchar_t is implemented as a native type. +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Overloads for wide C strings void PrintTo(const wchar_t* s, ::std::ostream* os); diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index af2e8ad2..cc48bc0b 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1359,6 +1359,20 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { std::vector > default_actions_; // All expectations for this function mocker. Expectations expectations_; + + // There is no generally useful and implementable semantics of + // copying a mock object, so copying a mock is usually a user error. + // Thus we disallow copying function mockers. If the user really + // wants to copy a mock object, he should implement his own copy + // operation, for example: + // + // class MockFoo : public Foo { + // public: + // // Defines a copy constructor explicitly. + // MockFoo(const MockFoo& src) {} + // ... + // }; + GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase); }; // class FunctionMockerBase #ifdef _MSC_VER diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index b3d1a1d1..b02682f8 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -157,7 +157,7 @@ inline Element* GetRawPointer(Element* p) { return p; } // This comparator allows linked_ptr to be stored in sets. template struct LinkedPtrLessThan { - bool operator()(const ::testing::internal::linked_ptr& lhs, + bool operator()(const ::testing::internal::linked_ptr& lhs, const ::testing::internal::linked_ptr& rhs) const { return lhs.get() < rhs.get(); } @@ -210,17 +210,154 @@ class ImplicitlyConvertible { template const bool ImplicitlyConvertible::value; +// In what follows, we use the term "kind" to indicate whether a type +// is bool, an integer type (excluding bool), a floating-point type, +// or none of them. This categorization is useful for determining +// when a matcher argument type can be safely converted to another +// type in the implementation of SafeMatcherCast. +enum TypeKind { + kBool, kInteger, kFloatingPoint, kOther +}; + +// KindOf::value is the kind of type T. +template struct KindOf { + enum { value = kOther }; // The default kind. +}; + +// This macro declares that the kind of 'type' is 'kind'. +#define GMOCK_DECLARE_KIND_(type, kind) \ + template <> struct KindOf { enum { value = kind }; } + +GMOCK_DECLARE_KIND_(bool, kBool); + +// All standard integer types. +GMOCK_DECLARE_KIND_(char, kInteger); +GMOCK_DECLARE_KIND_(signed char, kInteger); +GMOCK_DECLARE_KIND_(unsigned char, kInteger); +GMOCK_DECLARE_KIND_(short, kInteger); // NOLINT +GMOCK_DECLARE_KIND_(unsigned short, kInteger); // NOLINT +GMOCK_DECLARE_KIND_(int, kInteger); +GMOCK_DECLARE_KIND_(unsigned int, kInteger); +GMOCK_DECLARE_KIND_(long, kInteger); // NOLINT +GMOCK_DECLARE_KIND_(unsigned long, kInteger); // NOLINT + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t is a +// native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +GMOCK_DECLARE_KIND_(wchar_t, kInteger); +#endif + +// Non-standard integer types. +GMOCK_DECLARE_KIND_(Int64, kInteger); +GMOCK_DECLARE_KIND_(UInt64, kInteger); + +// All standard floating-point types. +GMOCK_DECLARE_KIND_(float, kFloatingPoint); +GMOCK_DECLARE_KIND_(double, kFloatingPoint); +GMOCK_DECLARE_KIND_(long double, kFloatingPoint); + +#undef GMOCK_DECLARE_KIND_ + +// Evaluates to the kind of 'type'. +#define GMOCK_KIND_OF_(type) \ + static_cast< ::testing::internal::TypeKind>( \ + ::testing::internal::KindOf::value) + +// Evaluates to true iff integer type T is signed. +#define GMOCK_IS_SIGNED_(T) (static_cast(-1) < 0) + +// LosslessArithmeticConvertibleImpl::value +// is true iff arithmetic type From can be losslessly converted to +// arithmetic type To. +// +// It's the user's responsibility to ensure that both From and To are +// raw (i.e. has no CV modifier, is not a pointer, and is not a +// reference) built-in arithmetic types, kFromKind is the kind of +// From, and kToKind is the kind of To; the value is +// implementation-defined when the above pre-condition is violated. +template +struct LosslessArithmeticConvertibleImpl : public false_type {}; + +// Converting bool to bool is lossless. +template <> +struct LosslessArithmeticConvertibleImpl + : public true_type {}; // NOLINT + +// Converting bool to any integer type is lossless. +template +struct LosslessArithmeticConvertibleImpl + : public true_type {}; // NOLINT + +// Converting bool to any floating-point type is lossless. +template +struct LosslessArithmeticConvertibleImpl + : public true_type {}; // NOLINT + +// Converting an integer to bool is lossy. +template +struct LosslessArithmeticConvertibleImpl + : public false_type {}; // NOLINT + +// Converting an integer to another non-bool integer is lossless iff +// the target type's range encloses the source type's range. +template +struct LosslessArithmeticConvertibleImpl + : public bool_constant< + // When converting from a smaller size to a larger size, we are + // fine as long as we are not converting from signed to unsigned. + ((sizeof(From) < sizeof(To)) && + (!GMOCK_IS_SIGNED_(From) || GMOCK_IS_SIGNED_(To))) || + // When converting between the same size, the signedness must match. + ((sizeof(From) == sizeof(To)) && + (GMOCK_IS_SIGNED_(From) == GMOCK_IS_SIGNED_(To)))> {}; // NOLINT + +#undef GMOCK_IS_SIGNED_ + +// Converting an integer to a floating-point type may be lossy, since +// the format of a floating-point number is implementation-defined. +template +struct LosslessArithmeticConvertibleImpl + : public false_type {}; // NOLINT + +// Converting a floating-point to bool is lossy. +template +struct LosslessArithmeticConvertibleImpl + : public false_type {}; // NOLINT + +// Converting a floating-point to an integer is lossy. +template +struct LosslessArithmeticConvertibleImpl + : public false_type {}; // NOLINT + +// Converting a floating-point to another floating-point is lossless +// iff the target type is at least as big as the source type. +template +struct LosslessArithmeticConvertibleImpl< + kFloatingPoint, From, kFloatingPoint, To> + : public bool_constant {}; // NOLINT + +// LosslessArithmeticConvertible::value is true iff arithmetic +// type From can be losslessly converted to arithmetic type To. +// +// It's the user's responsibility to ensure that both From and To are +// raw (i.e. has no CV modifier, is not a pointer, and is not a +// reference) built-in arithmetic types; the value is +// implementation-defined when the above pre-condition is violated. +template +struct LosslessArithmeticConvertible + : public LosslessArithmeticConvertibleImpl< + GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {}; // NOLINT + // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template -struct IsAProtocolMessage { - static const bool value = - ImplicitlyConvertible::value || - ImplicitlyConvertible::value; +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible::value || + ImplicitlyConvertible::value> { }; -template -const bool IsAProtocolMessage::value; // When the compiler sees expression IsContainerTest(0), the first // overload of IsContainerTest will be picked if C is an STL-style @@ -314,6 +451,8 @@ void Log(LogSeverity severity, const string& message, int stack_frames_to_skip); // to declare an unused << operator in the global namespace. struct Unused {}; +// TODO(wan@google.com): group all type utilities together. + // Type traits. // is_reference::value is non-zero iff T is a reference type. @@ -325,8 +464,8 @@ template struct type_equals : public false_type {}; template struct type_equals : public true_type {}; // remove_reference::type removes the reference from type T, if any. -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; // NOLINT +template struct remove_reference { typedef T type; }; // NOLINT // Invalid() returns an invalid value of type T. This is useful // when a value of type T is needed for compilation, but the statement diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index ca7935ca..907089e9 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import re import sys -_VERSION = '0.1.0.80421' +_VERSION = '1.0.0' _COMMON_GMOCK_SYMBOLS = [ # Matchers @@ -148,11 +148,14 @@ Please use ReturnRef() instead.""" def _NeedToReturnSomethingDiagnoser(msg): """Diagnoses the NRS disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' - r'.*gmock-actions\.h.*error: void value not ignored') + regex = (r'(?P.*):(?P\d+):\s+' + r'(instantiated from here\n.' + r'*gmock-actions\.h.*error: void value not ignored)' + r'|(error: control reaches end of non-void function)') diagnosis = """%(file)s:%(line)s: You are using an action that returns void, but it needs to return -*something*. Please tell it *what* to return.""" +*something*. Please tell it *what* to return. Perhaps you can use +the pattern DoAll(some_action, Return(some_value))?""" return _GenericDiagnoser('NRS', 'Need to Return Something', regex, diagnosis, msg) @@ -324,6 +327,23 @@ Note: the line number may be off; please fix all instances of Return(NULL).""" regex, diagnosis, msg) +def _WrongMockMethodMacroDiagnoser(msg): + """Diagnoses the WMM disease, given the error messages by gcc.""" + + regex = (r'(?P.*):(?P\d+):\s+' + r'.*this_method_does_not_take_(?P\d+)_argument.*\n' + r'.*\n' + r'.*candidates are.*FunctionMocker<[^>]+A(?P\d+)\)>' + ) + + diagnosis = """%(file)s:%(line)s: +You are using MOCK_METHOD%(wrong_args)s to define a mock method that has +%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, +MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" + return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn macro', + regex, diagnosis, msg) + + _DIAGNOSERS = [ _IncompleteByReferenceArgumentDiagnoser, @@ -337,6 +357,7 @@ _DIAGNOSERS = [ _OverloadedFunctionMatcherDiagnoser, _OverloadedMethodActionDiagnoser1, _OverloadedMethodActionDiagnoser2, + _WrongMockMethodMacroDiagnoser, ] diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index b678a9e5..5e4dc030 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -34,6 +34,7 @@ // This file tests the internal utilities. #include +#include #include #include #include @@ -43,6 +44,10 @@ #include #include +#if GTEST_OS_CYGWIN +#include // For ssize_t. NOLINT +#endif + namespace testing { namespace internal { @@ -232,6 +237,141 @@ TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { EXPECT_FALSE((ImplicitlyConvertible::value)); } +// Tests KindOf. + +TEST(KindOfTest, Bool) { + EXPECT_EQ(kBool, GMOCK_KIND_OF_(bool)); // NOLINT +} + +TEST(KindOfTest, Integer) { + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(char)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(signed char)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned char)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(short)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned short)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(int)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned int)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(long)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned long)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(wchar_t)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(Int64)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(UInt64)); // NOLINT + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(size_t)); // NOLINT +#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN + // ssize_t is not defined on Windows and possibly some other OSes. + EXPECT_EQ(kInteger, GMOCK_KIND_OF_(ssize_t)); // NOLINT +#endif +} + +TEST(KindOfTest, FloatingPoint) { + EXPECT_EQ(kFloatingPoint, GMOCK_KIND_OF_(float)); // NOLINT + EXPECT_EQ(kFloatingPoint, GMOCK_KIND_OF_(double)); // NOLINT + EXPECT_EQ(kFloatingPoint, GMOCK_KIND_OF_(long double)); // NOLINT +} + +TEST(KindOfTest, Other) { + EXPECT_EQ(kOther, GMOCK_KIND_OF_(void*)); // NOLINT + EXPECT_EQ(kOther, GMOCK_KIND_OF_(char**)); // NOLINT + EXPECT_EQ(kOther, GMOCK_KIND_OF_(Base)); // NOLINT +} + +// Tests LosslessArithmeticConvertible. + +TEST(LosslessArithmeticConvertibleTest, BoolToBool) { + EXPECT_TRUE((LosslessArithmeticConvertible::value)); +} + +TEST(LosslessArithmeticConvertibleTest, BoolToInteger) { + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE( + (LosslessArithmeticConvertible::value)); // NOLINT +} + +TEST(LosslessArithmeticConvertibleTest, BoolToFloatingPoint) { + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); +} + +TEST(LosslessArithmeticConvertibleTest, IntegerToBool) { + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); +} + +TEST(LosslessArithmeticConvertibleTest, IntegerToInteger) { + // Unsigned => larger signed is fine. + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + + // Unsigned => larger unsigned is fine. + EXPECT_TRUE( + (LosslessArithmeticConvertible::value)); // NOLINT + + // Signed => unsigned is not fine. + EXPECT_FALSE((LosslessArithmeticConvertible::value)); // NOLINT + EXPECT_FALSE((LosslessArithmeticConvertible< + signed char, unsigned int>::value)); // NOLINT + + // Same size and same signedness: fine too. + EXPECT_TRUE((LosslessArithmeticConvertible< + unsigned char, unsigned char>::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible< + unsigned long, unsigned long>::value)); // NOLINT + + // Same size, different signedness: not fine. + EXPECT_FALSE((LosslessArithmeticConvertible< + unsigned char, signed char>::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + + // Larger size => smaller size is not fine. + EXPECT_FALSE((LosslessArithmeticConvertible::value)); // NOLINT + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); +} + +TEST(LosslessArithmeticConvertibleTest, IntegerToFloatingPoint) { + // Integers cannot be losslessly converted to floating-points, as + // the format of the latter is implementation-defined. + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible< + short, long double>::value)); // NOLINT +} + +TEST(LosslessArithmeticConvertibleTest, FloatingPointToBool) { + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); +} + +TEST(LosslessArithmeticConvertibleTest, FloatingPointToInteger) { + EXPECT_FALSE((LosslessArithmeticConvertible::value)); // NOLINT + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + EXPECT_FALSE((LosslessArithmeticConvertible::value)); +} + +TEST(LosslessArithmeticConvertibleTest, FloatingPointToFloatingPoint) { + // Smaller size => larger size is fine. + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + + // Same size: fine. + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + + // Larger size => smaller size is not fine. + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + if (sizeof(double) == sizeof(long double)) { // NOLINT + // In some implementations (e.g. MSVC), double and long double + // have the same size. + EXPECT_TRUE((LosslessArithmeticConvertible::value)); + } else { + EXPECT_FALSE((LosslessArithmeticConvertible::value)); + } +} + // Tests that IsAProtocolMessage::value is a compile-time constant. TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { GMOCK_COMPILE_ASSERT_(IsAProtocolMessage::value, const_true); @@ -265,8 +405,10 @@ TEST(IsContainerTestTest, WorksForNonContainer) { } TEST(IsContainerTestTest, WorksForContainer) { - EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); - EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest >(0))); + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest >(0))); } // Tests the TupleMatches() template function. diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index ab5ca35c..e7709018 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -376,13 +376,18 @@ TEST(SafeMatcherCastTest, FromPolymorphicMatcher) { EXPECT_FALSE(m2.Matches('\n')); } -// Tests that SafeMatcherCast(m) works when m is a Matcher where T -// can be implicitly converted to U. -TEST(SafeMatcherCastTest, FromImplicitlyConvertibleType) { +// Tests that SafeMatcherCast(m) works when m is a Matcher where +// T and U are arithmetic types and T can be losslessly converted to +// U. +TEST(SafeMatcherCastTest, FromLosslesslyConvertibleArithmeticType) { Matcher m1 = DoubleEq(1.0); - Matcher m2 = SafeMatcherCast(m1); - EXPECT_TRUE(m2.Matches(1)); - EXPECT_FALSE(m2.Matches(2)); + Matcher m2 = SafeMatcherCast(m1); + EXPECT_TRUE(m2.Matches(1.0f)); + EXPECT_FALSE(m2.Matches(2.0f)); + + Matcher m3 = SafeMatcherCast(TypedEq('a')); + EXPECT_TRUE(m3.Matches('a')); + EXPECT_FALSE(m3.Matches('b')); } // Tests that SafeMatcherCast(m) works when m is a Matcher where T and U -- cgit v1.2.3 From 9413f2ff615ae1b933580576183d316c4cb6376c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 29 May 2009 19:50:06 +0000 Subject: Avoids unnecessary printing of call into to internal buffers; Made the universal value printer safer when printing char[]; Removed duplicated code in InvokeWith; Improved gmock_doctor.py. --- include/gmock/gmock-printers.h | 67 ++--- include/gmock/gmock-spec-builders.h | 348 +++++++++++++------------- include/gmock/internal/gmock-internal-utils.h | 4 + scripts/gmock_doctor.py | 93 ++++--- src/gmock-internal-utils.cc | 27 +- src/gmock-printers.cc | 5 + src/gmock-spec-builders.cc | 4 +- test/gmock-internal-utils_test.cc | 28 +++ test/gmock-printers_test.cc | 54 ++-- test/gmock-spec-builders_test.cc | 47 ++++ 10 files changed, 396 insertions(+), 281 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 99002434..e233ef3e 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -580,6 +580,41 @@ class UniversalPrinter { #endif // _MSC_VER }; +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os); + +// Prints an array of 'len' elements, starting at address 'begin', to a string. +template +string UniversalPrintArrayToString(const T* begin, size_t len) { + ::std::stringstream ss; + UniversalPrintArray(begin, len, &ss); + return ss.str(); +} + // Implements printing an array type T[N]. template class UniversalPrinter { @@ -587,41 +622,13 @@ class UniversalPrinter { // Prints the given array, omitting some elements when there are too // many. static void Print(const T (&a)[N], ::std::ostream* os) { - // Prints a char array as a C string. Note that we compare 'const - // T' with 'const char' instead of comparing T with char, in case - // that T is already a const type. - if (internal::type_equals::value) { - UniversalPrinter::Print(a, os); - return; - } - - if (N == 0) { - *os << "{}"; - } else { - *os << "{ "; - const size_t kThreshold = 18; - const size_t kChunkSize = 8; - // If the array has more than kThreshold elements, we'll have to - // omit some details by printing only the first and the last - // kChunkSize elements. - // TODO(wan): let the user control the threshold using a flag. - if (N <= kThreshold) { - PrintRawArrayTo(a, N, os); - } else { - PrintRawArrayTo(a, kChunkSize, os); - *os << ", ..., "; - PrintRawArrayTo(a + N - kChunkSize, kChunkSize, os); - } - *os << " }"; - } + UniversalPrintArray(a, N, os); } // A convenient wrapper for Print() that returns the print-out as a // string. static string PrintToString(const T (&a)[N]) { - ::std::stringstream ss; - Print(a, &ss); - return ss.str(); + return UniversalPrintArrayToString(a, N); } }; diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index cc48bc0b..d4578ac7 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -93,10 +93,6 @@ class ExpectationTester; template class FunctionMockerBase; -// Helper class for implementing FunctionMockerBase::InvokeWith(). -template -class InvokeWithHelper; - // Protects the mock object registry (in class Mock), all function // mockers, and all expectations. // @@ -269,9 +265,6 @@ class Mock { template friend class internal::FunctionMockerBase; - template - friend class internal::InvokeWithHelper; - template friend class NiceMock; @@ -763,9 +756,6 @@ class Expectation : public ExpectationBase { template friend class FunctionMockerBase; - template - friend class InvokeWithHelper; - // The following methods will be called only after the EXPECT_CALL() // statement finishes and when the current thread holds // g_gmock_mutex. @@ -1042,6 +1032,78 @@ class MockSpec { #pragma warning(disable:4355) // Temporarily disables warning 4355. #endif // _MSV_VER +// C++ treats the void type specially. For example, you cannot define +// a void-typed variable or pass a void value to a function. +// ActionResultHolder holds a value of type T, where T must be a +// copyable type or void (T doesn't need to be default-constructable). +// It hides the syntactic difference between void and other types, and +// is used to unify the code for invoking both void-returning and +// non-void-returning mock functions. This generic definition is used +// when T is not void. +template +class ActionResultHolder { + public: + explicit ActionResultHolder(T value) : value_(value) {} + + // The compiler-generated copy constructor and assignment operator + // are exactly what we need, so we don't need to define them. + + T value() const { return value_; } + + // Prints the held value as an action's result to os. + void PrintAsActionResult(::std::ostream* os) const { + *os << "\n Returns: "; + UniversalPrinter::Print(value_, os); + } + + // Performs the given mock function's default action and returns the + // result in a ActionResultHolder. + template + static ActionResultHolder PerformDefaultAction( + const FunctionMockerBase* func_mocker, + const Arguments& args, + const string& call_description) { + return ActionResultHolder( + func_mocker->PerformDefaultAction(args, call_description)); + } + + // Performs the given action and returns the result in a + // ActionResultHolder. + template + static ActionResultHolder PerformAction(const Action& action, + const Arguments& args) { + return ActionResultHolder(action.Perform(args)); + } + + private: + T value_; +}; + +// Specialization for T = void. +template <> +class ActionResultHolder { + public: + ActionResultHolder() {} + void value() const {} + void PrintAsActionResult(::std::ostream* /* os */) const {} + + template + static ActionResultHolder PerformDefaultAction( + const FunctionMockerBase* func_mocker, + const Arguments& args, + const string& call_description) { + func_mocker->PerformDefaultAction(args, call_description); + return ActionResultHolder(); + } + + template + static ActionResultHolder PerformAction(const Action& action, + const Arguments& args) { + action.Perform(args); + return ActionResultHolder(); + } +}; + // The base of the function mocker class for the given function type. // We put the methods in this class instead of its child to avoid code // bloat. @@ -1167,16 +1229,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { template friend class MockSpec; - template - friend class InvokeWithHelper; - // Returns the result of invoking this mock function with the given // arguments. This function can be safely called from multiple // threads concurrently. // L < g_gmock_mutex - Result InvokeWith(const ArgumentTuple& args) { - return InvokeWithHelper::InvokeAndPrintResult(this, args); - } + Result InvokeWith(const ArgumentTuple& args); // Adds and returns a default action spec for this mock function. // L < g_gmock_mutex @@ -1417,170 +1474,109 @@ bool FunctionMockerBase::VerifyAndClearExpectationsLocked() { // manner specified by 'reaction'. void ReportUninterestingCall(CallReaction reaction, const string& msg); -// When an uninteresting or unexpected mock function is called, we -// want to print its return value to assist the user debugging. Since -// there's nothing to print when the function returns void, we need to -// specialize the logic of FunctionMockerBase::InvokeWith() for -// void return values. -// -// C++ doesn't allow us to specialize a member function template -// unless we also specialize its enclosing class, so we had to let -// InvokeWith() delegate its work to a helper class InvokeWithHelper, -// which can then be specialized. -// -// Note that InvokeWithHelper must be a class template (as opposed to -// a function template), as only class templates can be partially -// specialized. -template -class InvokeWithHelper { - public: - typedef typename Function::ArgumentTuple ArgumentTuple; - - // Calculates the result of invoking the function mocked by mocker - // with the given arguments, prints it, and returns it. - // L < g_gmock_mutex - static Result InvokeAndPrintResult( - FunctionMockerBase* mocker, - const ArgumentTuple& args) { - if (mocker->expectations_.size() == 0) { - // No expectation is set on this mock method - we have an - // uninteresting call. - - // Warns about the uninteresting call. - ::std::stringstream ss; - mocker->DescribeUninterestingCall(args, &ss); - - // We must get Google Mock's reaction on uninteresting calls - // made on this mock object BEFORE performing the action, - // because the action may DELETE the mock object and make the - // following expression meaningless. - const CallReaction reaction = - Mock::GetReactionOnUninterestingCalls(mocker->MockObject()); - - // Calculates the function result. - Result result = mocker->PerformDefaultAction(args, ss.str()); - - // Prints the function result. - ss << "\n Returns: "; - UniversalPrinter::Print(result, &ss); - ReportUninterestingCall(reaction, ss.str()); - - return result; - } - - bool is_excessive = false; - ::std::stringstream ss; - ::std::stringstream why; - ::std::stringstream loc; - Action action; - Expectation* exp; - - // The FindMatchingExpectationAndAction() function acquires and - // releases g_gmock_mutex. - const bool found = mocker->FindMatchingExpectationAndAction( - args, &exp, &action, &is_excessive, &ss, &why); - ss << " Function call: " << mocker->Name(); - UniversalPrinter::Print(args, &ss); - // In case the action deletes a piece of the expectation, we - // generate the message beforehand. - if (found && !is_excessive) { - exp->DescribeLocationTo(&loc); - } - Result result = action.IsDoDefault() ? - mocker->PerformDefaultAction(args, ss.str()) - : action.Perform(args); - ss << "\n Returns: "; - UniversalPrinter::Print(result, &ss); - ss << "\n" << why.str(); - - if (found) { - if (is_excessive) { - // We had an upper-bound violation and the failure message is in ss. - Expect(false, exp->file(), exp->line(), ss.str()); - } else { - // We had an expected call and the matching expectation is - // described in ss. - Log(INFO, loc.str() + ss.str(), 3); - } - } else { - // No expectation matches this call - reports a failure. - Expect(false, NULL, -1, ss.str()); - } - return result; - } -}; // class InvokeWithHelper - -// This specialization helps to implement -// FunctionMockerBase::InvokeWith() for void-returning functions. +// Calculates the result of invoking this mock function with the given +// arguments, prints it, and returns it. +// L < g_gmock_mutex template -class InvokeWithHelper { - public: - typedef typename Function::ArgumentTuple ArgumentTuple; - - // Invokes the function mocked by mocker with the given arguments. - // L < g_gmock_mutex - static void InvokeAndPrintResult(FunctionMockerBase* mocker, - const ArgumentTuple& args) { - const int count = static_cast(mocker->expectations_.size()); - if (count == 0) { - // No expectation is set on this mock method - we have an - // uninteresting call. - ::std::stringstream ss; - mocker->DescribeUninterestingCall(args, &ss); - - // We must get Google Mock's reaction on uninteresting calls - // made on this mock object BEFORE performing the action, - // because the action may DELETE the mock object and make the - // following expression meaningless. - const CallReaction reaction = - Mock::GetReactionOnUninterestingCalls(mocker->MockObject()); - - mocker->PerformDefaultAction(args, ss.str()); - ReportUninterestingCall(reaction, ss.str()); - return; +typename Function::Result FunctionMockerBase::InvokeWith( + const typename Function::ArgumentTuple& args) { + typedef ActionResultHolder ResultHolder; + + if (expectations_.size() == 0) { + // No expectation is set on this mock method - we have an + // uninteresting call. + + // We must get Google Mock's reaction on uninteresting calls + // made on this mock object BEFORE performing the action, + // because the action may DELETE the mock object and make the + // following expression meaningless. + const CallReaction reaction = + Mock::GetReactionOnUninterestingCalls(MockObject()); + + // True iff we need to print this call's arguments and return + // value. This definition must be kept in sync with + // the behavior of ReportUninterestingCall(). + const bool need_to_report_uninteresting_call = + // If the user allows this uninteresting call, we print it + // only when he wants informational messages. + reaction == ALLOW ? LogIsVisible(INFO) : + // If the user wants this to be a warning, we print it only + // when he wants to see warnings. + reaction == WARN ? LogIsVisible(WARNING) : + // Otherwise, the user wants this to be an error, and we + // should always print detailed information in the error. + true; + + if (!need_to_report_uninteresting_call) { + // Perform the action without printing the call information. + return PerformDefaultAction(args, ""); } - bool is_excessive = false; + // Warns about the uninteresting call. ::std::stringstream ss; - ::std::stringstream why; - ::std::stringstream loc; - Action action; - Expectation* exp; - - // The FindMatchingExpectationAndAction() function acquires and - // releases g_gmock_mutex. - const bool found = mocker->FindMatchingExpectationAndAction( - args, &exp, &action, &is_excessive, &ss, &why); - ss << " Function call: " << mocker->Name(); - UniversalPrinter::Print(args, &ss); - ss << "\n" << why.str(); - // In case the action deletes a piece of the expectation, we - // generate the message beforehand. - if (found && !is_excessive) { - exp->DescribeLocationTo(&loc); - } - if (action.IsDoDefault()) { - mocker->PerformDefaultAction(args, ss.str()); - } else { - action.Perform(args); - } - - if (found) { - // A matching expectation and corresponding action were found. - if (is_excessive) { - // We had an upper-bound violation and the failure message is in ss. - Expect(false, exp->file(), exp->line(), ss.str()); - } else { - // We had an expected call and the matching expectation is - // described in ss. - Log(INFO, loc.str() + ss.str(), 3); - } - } else { - // No matching expectation was found - reports an error. - Expect(false, NULL, -1, ss.str()); - } - } -}; // class InvokeWithHelper + DescribeUninterestingCall(args, &ss); + + // Calculates the function result. + const ResultHolder result = + ResultHolder::PerformDefaultAction(this, args, ss.str()); + + // Prints the function result. + result.PrintAsActionResult(&ss); + + ReportUninterestingCall(reaction, ss.str()); + return result.value(); + } + + bool is_excessive = false; + ::std::stringstream ss; + ::std::stringstream why; + ::std::stringstream loc; + Action action; + Expectation* exp; + + // The FindMatchingExpectationAndAction() function acquires and + // releases g_gmock_mutex. + const bool found = FindMatchingExpectationAndAction( + args, &exp, &action, &is_excessive, &ss, &why); + + // True iff we need to print the call's arguments and return value. + // This definition must be kept in sync with the uses of Expect() + // and Log() in this function. + const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO); + if (!need_to_report_call) { + // Perform the action without printing the call information. + return action.IsDoDefault() ? PerformDefaultAction(args, "") : + action.Perform(args); + } + + ss << " Function call: " << Name(); + UniversalPrinter::Print(args, &ss); + + // In case the action deletes a piece of the expectation, we + // generate the message beforehand. + if (found && !is_excessive) { + exp->DescribeLocationTo(&loc); + } + + const ResultHolder result = action.IsDoDefault() ? + ResultHolder::PerformDefaultAction(this, args, ss.str()) : + ResultHolder::PerformAction(action, args); + result.PrintAsActionResult(&ss); + ss << "\n" << why.str(); + + if (!found) { + // No expectation matches this call - reports a failure. + Expect(false, NULL, -1, ss.str()); + } else if (is_excessive) { + // We had an upper-bound violation and the failure message is in ss. + Expect(false, exp->file(), exp->line(), ss.str()); + } else { + // We had an expected call and the matching expectation is + // described in ss. + Log(INFO, loc.str() + ss.str(), 2); + } + return result.value(); +} } // namespace internal diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index b02682f8..b5e38db3 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -438,6 +438,10 @@ const char kWarningVerbosity[] = "warning"; // No logs are printed. const char kErrorVerbosity[] = "error"; +// Returns true iff a log with the given severity is visible according +// to the --gmock_verbose flag. +bool LogIsVisible(LogSeverity severity); + // Prints the given message to stdout iff 'severity' >= the level // specified by the --gmock_verbose flag. If stack_frames_to_skip >= // 0, also prints the stack trace excluding the top diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 907089e9..1980977c 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import re import sys -_VERSION = '1.0.0' +_VERSION = '1.0.1' _COMMON_GMOCK_SYMBOLS = [ # Matchers @@ -46,8 +46,12 @@ _COMMON_GMOCK_SYMBOLS = [ 'AllOf', 'An', 'AnyOf', + 'ContainerEq', + 'Contains', 'ContainsRegex', 'DoubleEq', + 'ElementsAre', + 'ElementsAreArray', 'EndsWith', 'Eq', 'Field', @@ -60,6 +64,8 @@ _COMMON_GMOCK_SYMBOLS = [ 'Lt', 'MatcherCast', 'MatchesRegex', + 'NanSensitiveDoubleEq', + 'NanSensitiveFloatEq', 'Ne', 'Not', 'NotNull', @@ -67,6 +73,8 @@ _COMMON_GMOCK_SYMBOLS = [ 'PointeeIsInitializedProto', 'Property', 'Ref', + 'ResultOf', + 'SafeMatcherCast', 'StartsWith', 'StrCaseEq', 'StrCaseNe', @@ -76,7 +84,9 @@ _COMMON_GMOCK_SYMBOLS = [ 'TypedEq', # Actions + 'Assign', 'ByRef', + 'DeleteArg', 'DoAll', 'DoDefault', 'IgnoreResult', @@ -84,11 +94,18 @@ _COMMON_GMOCK_SYMBOLS = [ 'InvokeArgument', 'InvokeWithoutArgs', 'Return', + 'ReturnNew', 'ReturnNull', 'ReturnRef', + 'SaveArg', + 'SetArgReferee', 'SetArgumentPointee', 'SetArrayArgument', + 'SetErrnoAndReturn', + 'Throw', + 'WithArg', 'WithArgs', + 'WithoutArgs', # Cardinalities 'AnyNumber', @@ -106,6 +123,9 @@ _COMMON_GMOCK_SYMBOLS = [ 'Mock', ] +# Regex for matching source file path and line number in gcc's errors. +_FILE_LINE_RE = r'(?P.*):(?P\d+):\s+' + def _FindAllMatches(regex, s): """Generates all matches of regex in string s.""" @@ -128,6 +148,7 @@ def _GenericDiagnoser(short_name, long_name, regex, diagnosis, msg): (short name of disease, long name of disease, diagnosis). """ + diagnosis = '%(file)s:%(line)s:' + diagnosis for m in _FindAllMatches(regex, msg): yield (short_name, long_name, diagnosis % m.groupdict()) @@ -136,9 +157,9 @@ def _NeedToReturnReferenceDiagnoser(msg): """Diagnoses the NRR disease, given the error messages by gcc.""" regex = (r'In member function \'testing::internal::ReturnAction.*\n' - r'(?P.*):(?P\d+):\s+instantiated from here\n' + + _FILE_LINE_RE + r'instantiated from here\n' r'.*gmock-actions\.h.*error: creating array with negative size') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ You are using an Return() action in a function that returns a reference. Please use ReturnRef() instead.""" return _GenericDiagnoser('NRR', 'Need to Return Reference', @@ -148,11 +169,11 @@ Please use ReturnRef() instead.""" def _NeedToReturnSomethingDiagnoser(msg): """Diagnoses the NRS disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+):\s+' + regex = (_FILE_LINE_RE + r'(instantiated from here\n.' r'*gmock-actions\.h.*error: void value not ignored)' r'|(error: control reaches end of non-void function)') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ You are using an action that returns void, but it needs to return *something*. Please tell it *what* to return. Perhaps you can use the pattern DoAll(some_action, Return(some_value))?""" @@ -163,10 +184,10 @@ the pattern DoAll(some_action, Return(some_value))?""" def _NeedToReturnNothingDiagnoser(msg): """Diagnoses the NRN disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + regex = (_FILE_LINE_RE + r'instantiated from here\n' r'.*gmock-actions\.h.*error: return-statement with a value, ' r'in function returning \'void\'') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ You are using an action that returns *something*, but it needs to return void. Please use a void-returning action instead. @@ -179,10 +200,10 @@ to re-arrange the order of actions in a DoAll(), if you are using one?""" def _IncompleteByReferenceArgumentDiagnoser(msg): """Diagnoses the IBRA disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + regex = (_FILE_LINE_RE + r'instantiated from here\n' r'.*gmock-printers\.h.*error: invalid application of ' r'\'sizeof\' to incomplete type \'(?P.*)\'') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ In order to mock this function, Google Mock needs to see the definition of type "%(type)s" - declaration alone is not enough. Either #include the header that defines it, or change the argument to be passed @@ -194,9 +215,9 @@ by pointer.""" def _OverloadedFunctionMatcherDiagnoser(msg): """Diagnoses the OFM disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+): error: no matching function for ' + regex = (_FILE_LINE_RE + r'error: no matching function for ' r'call to \'Truly\(\)') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ The argument you gave to Truly() is an overloaded function. Please tell gcc which overloaded version you want to use. @@ -211,10 +232,9 @@ you should write def _OverloadedFunctionActionDiagnoser(msg): """Diagnoses the OFA disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+): error: ' - r'no matching function for call to \'Invoke\(' + regex = (_FILE_LINE_RE + r'error: no matching function for call to \'Invoke\(' r'') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ You are passing an overloaded function to Invoke(). Please tell gcc which overloaded version you want to use. @@ -229,10 +249,10 @@ you should write something like def _OverloadedMethodActionDiagnoser1(msg): """Diagnoses the OMA disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+): error: ' + regex = (_FILE_LINE_RE + r'error: ' r'.*no matching function for call to \'Invoke\(.*, ' r'unresolved overloaded function type>') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ The second argument you gave to Invoke() is an overloaded method. Please tell gcc which overloaded version you want to use. @@ -250,10 +270,10 @@ you should write something like def _MockObjectPointerDiagnoser(msg): """Diagnoses the MOP disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+): error: request for member ' + regex = (_FILE_LINE_RE + r'error: request for member ' r'\'gmock_(?P.+)\' in \'(?P.+)\', ' r'which is of non-class type \'(.*::)*(?P.+)\*\'') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*, not a *pointer* to it. Please write '*(%(mock_object)s)' instead of '%(mock_object)s' as your first argument. @@ -279,9 +299,9 @@ you should use the EXPECT_CALL like this: def _OverloadedMethodActionDiagnoser2(msg): """Diagnoses the OMA disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+): error: no matching function for ' + regex = (_FILE_LINE_RE + r'error: no matching function for ' r'call to \'Invoke\(.+, \)') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ The second argument you gave to Invoke() is an overloaded method. Please tell gcc which overloaded version you want to use. @@ -299,9 +319,9 @@ you should write something like def _NeedToUseSymbolDiagnoser(msg): """Diagnoses the NUS disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+): error: \'(?P.+)\' ' + regex = (_FILE_LINE_RE + r'error: \'(?P.+)\' ' r'(was not declared in this scope|has not been declared)') - diagnosis = """%(file)s:%(line)s: + diagnosis = """ '%(symbol)s' is defined by Google Mock in the testing namespace. Did you forget to write using testing::%(symbol)s; @@ -315,11 +335,10 @@ Did you forget to write def _NeedToUseReturnNullDiagnoser(msg): """Diagnoses the NRNULL disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+):\s+instantiated from here\n' + regex = (_FILE_LINE_RE + r'instantiated from here\n' r'.*gmock-actions\.h.*error: invalid conversion from ' r'\'long int\' to \'(?P.+\*)') - - diagnosis = """%(file)s:%(line)s: + diagnosis = """ You are probably calling Return(NULL) and the compiler isn't sure how to turn NULL into a %(type)s*. Use ReturnNull() instead. Note: the line number may be off; please fix all instances of Return(NULL).""" @@ -330,13 +349,11 @@ Note: the line number may be off; please fix all instances of Return(NULL).""" def _WrongMockMethodMacroDiagnoser(msg): """Diagnoses the WMM disease, given the error messages by gcc.""" - regex = (r'(?P.*):(?P\d+):\s+' + regex = (_FILE_LINE_RE + r'.*this_method_does_not_take_(?P\d+)_argument.*\n' r'.*\n' - r'.*candidates are.*FunctionMocker<[^>]+A(?P\d+)\)>' - ) - - diagnosis = """%(file)s:%(line)s: + r'.*candidates are.*FunctionMocker<[^>]+A(?P\d+)\)>') + diagnosis = """ You are using MOCK_METHOD%(wrong_args)s to define a mock method that has %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" @@ -344,6 +361,21 @@ MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" regex, diagnosis, msg) +def _WrongParenPositionDiagnoser(msg): + """Diagnoses the WPP disease, given the error messages by gcc.""" + + regex = (_FILE_LINE_RE + + r'error:.*testing::internal::MockSpec<.* has no member named \'' + r'(?P\w+)\'') + diagnosis = """ +The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* +".%(method)s". For example, you should write: + EXPECT_CALL(my_mock, Foo(_)).%(method)s(...); +instead of: + EXPECT_CALL(my_mock, Foo(_).%(method)s(...));""" + return _GenericDiagnoser('WPP', 'Wrong parenthesis position', + regex, diagnosis, msg) + _DIAGNOSERS = [ _IncompleteByReferenceArgumentDiagnoser, @@ -358,6 +390,7 @@ _DIAGNOSERS = [ _OverloadedMethodActionDiagnoser1, _OverloadedMethodActionDiagnoser2, _WrongMockMethodMacroDiagnoser, + _WrongParenPositionDiagnoser, ] diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 735abce5..ce17d715 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -101,6 +101,22 @@ FailureReporterInterface* GetFailureReporter() { // Protects global resources (stdout in particular) used by Log(). static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); +// Returns true iff a log with the given severity is visible according +// to the --gmock_verbose flag. +bool LogIsVisible(LogSeverity severity) { + if (GMOCK_FLAG(verbose) == kInfoVerbosity) { + // Always show the log if --gmock_verbose=info. + return true; + } else if (GMOCK_FLAG(verbose) == kErrorVerbosity) { + // Always hide it if --gmock_verbose=error. + return false; + } else { + // If --gmock_verbose is neither "info" nor "error", we treat it + // as "warning" (its default value). + return severity == WARNING; + } +} + // Prints the given message to stdout iff 'severity' >= the level // specified by the --gmock_verbose flag. If stack_frames_to_skip >= // 0, also prints the stack trace excluding the top @@ -110,17 +126,8 @@ static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); // conservative. void Log(LogSeverity severity, const string& message, int stack_frames_to_skip) { - if (GMOCK_FLAG(verbose) == kErrorVerbosity) { - // The user is not interested in logs. + if (!LogIsVisible(severity)) return; - } else if (GMOCK_FLAG(verbose) != kInfoVerbosity) { - // The user is interested in warnings but not informational logs. - // Note that invalid values of GMOCK_FLAG(verbose) are treated as - // "warning", which is the default value of the flag. - if (severity == INFO) { - return; - } - } // Ensures that logs from different threads don't interleave. MutexLock l(&g_log_mutex); diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc index e6d4001a..922a7b2d 100644 --- a/src/gmock-printers.cc +++ b/src/gmock-printers.cc @@ -242,6 +242,11 @@ static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { *os << "\""; } +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + // Prints the given array of wide characters to the ostream. // The array starts at *begin, the length is len, it may include L'\0' // characters and may not be null-terminated. diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 65a74b81..465e4d63 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -139,10 +139,10 @@ ThreadLocal g_gmock_implicit_sequence; void ReportUninterestingCall(CallReaction reaction, const string& msg) { switch (reaction) { case ALLOW: - Log(INFO, msg, 4); + Log(INFO, msg, 3); break; case WARN: - Log(WARNING, msg, 4); + Log(WARNING, msg, 3); break; default: // FAIL Expect(false, NULL, -1, msg); diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 5e4dc030..7886f6d3 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -494,6 +494,34 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) { }, "Expectation failed"); } +// Tests LogIsVisible(). + +class LogIsVisibleTest : public ::testing::Test { + protected: + virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); } + virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; } + + string original_verbose_; +}; + +TEST_F(LogIsVisibleTest, AlwaysReturnsTrueIfVerbosityIsInfo) { + GMOCK_FLAG(verbose) = kInfoVerbosity; + EXPECT_TRUE(LogIsVisible(INFO)); + EXPECT_TRUE(LogIsVisible(WARNING)); +} + +TEST_F(LogIsVisibleTest, AlwaysReturnsFalseIfVerbosityIsError) { + GMOCK_FLAG(verbose) = kErrorVerbosity; + EXPECT_FALSE(LogIsVisible(INFO)); + EXPECT_FALSE(LogIsVisible(WARNING)); +} + +TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) { + GMOCK_FLAG(verbose) = kWarningVerbosity; + EXPECT_FALSE(LogIsVisible(INFO)); + EXPECT_TRUE(LogIsVisible(WARNING)); +} + // TODO(wan@google.com): find a way to re-enable these tests. #if 0 diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 29a0db84..f03be292 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -485,75 +485,58 @@ TEST(PrintPointerTest, MemberFunctionPointer) { // Tests printing C arrays. -// One-dimensional array. - -void ArrayHelper1(int (&a)[5]) { // NOLINT - EXPECT_EQ("{ 1, 2, 3, 4, 5 }", Print(a)); +// The difference between this and Print() is that it ensures that the +// argument is a reference to an array. +template +string PrintArrayHelper(T (&a)[N]) { + return Print(a); } +// One-dimensional array. TEST(PrintArrayTest, OneDimensionalArray) { int a[5] = { 1, 2, 3, 4, 5 }; - ArrayHelper1(a); + EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); } // Two-dimensional array. - -void ArrayHelper2(int (&a)[2][5]) { // NOLINT - EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", Print(a)); -} - TEST(PrintArrayTest, TwoDimensionalArray) { int a[2][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }; - ArrayHelper2(a); + EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); } // Array of const elements. - -void ArrayHelper3(const bool (&a)[1]) { // NOLINT - EXPECT_EQ("{ false }", Print(a)); -} - TEST(PrintArrayTest, ConstArray) { const bool a[1] = { false }; - ArrayHelper3(a); + EXPECT_EQ("{ false }", PrintArrayHelper(a)); } // Char array. - -void ArrayHelper4(char (&a)[3]) { // NOLINT - EXPECT_EQ(PrintPointer(a) + " pointing to \"Hi\"", Print(a)); -} - TEST(PrintArrayTest, CharArray) { - char a[3] = "Hi"; - ArrayHelper4(a); + // Array a contains '\0' in the middle and doesn't end with '\0'. + char a[3] = { 'H', '\0', 'i' }; + EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a)); } // Const char array. - -void ArrayHelper5(const char (&a)[3]) { // NOLINT - EXPECT_EQ(Print(a), PrintPointer(a) + " pointing to \"Hi\""); -} - TEST(PrintArrayTest, ConstCharArray) { - const char a[3] = "Hi"; - ArrayHelper5(a); + const char a[4] = "\0Hi"; + EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a)); } // Array of objects. TEST(PrintArrayTest, ObjectArray) { string a[3] = { "Hi", "Hello", "Ni hao" }; - EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", Print(a)); + EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); } // Array with many elements. TEST(PrintArrayTest, BigArray) { int a[100] = { 1, 2, 3 }; EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", - Print(a)); + PrintArrayHelper(a)); } // Tests printing ::string and ::std::string. @@ -995,6 +978,11 @@ TEST(PrintToStringTest, WorksForReference) { UniversalPrinter::PrintToString(n)); } +TEST(PrintToStringTest, WorksForArray) { + int n[3] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3 }", UniversalPrinter::PrintToString(n)); +} + TEST(UniversalTersePrintTest, WorksForNonReference) { ::std::stringstream ss; UniversalTersePrint(123, &ss); diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index e8c39028..4711899d 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1612,6 +1612,53 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { #endif // 0 +// A helper class that generates a failure when printed. We use it to +// ensure that Google Mock doesn't print a value (even to an internal +// buffer) when it is not supposed to do so. +class PrintMeNot {}; + +void PrintTo(PrintMeNot /* dummy */, ::std::ostream* /* os */) { + ADD_FAILURE() << "Google Mock is printing a value that shouldn't be " + << "printed even to an internal buffer."; +} + +class LogTestHelper { + public: + MOCK_METHOD1(Foo, PrintMeNot(PrintMeNot)); +}; + +class GMockLogTest : public ::testing::Test { + protected: + virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); } + virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; } + + LogTestHelper helper_; + string original_verbose_; +}; + +TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsWarning) { + GMOCK_FLAG(verbose) = kWarningVerbosity; + EXPECT_CALL(helper_, Foo(_)) + .WillOnce(Return(PrintMeNot())); + helper_.Foo(PrintMeNot()); // This is an expected call. +} + +TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsError) { + GMOCK_FLAG(verbose) = kErrorVerbosity; + EXPECT_CALL(helper_, Foo(_)) + .WillOnce(Return(PrintMeNot())); + helper_.Foo(PrintMeNot()); // This is an expected call. +} + +TEST_F(GMockLogTest, DoesNotPrintWarningInternallyIfVerbosityIsError) { + GMOCK_FLAG(verbose) = kErrorVerbosity; + ON_CALL(helper_, Foo(_)) + .WillByDefault(Return(PrintMeNot())); + helper_.Foo(PrintMeNot()); // This should generate a warning. +} + +// Tests Mock::AllowLeak(). + TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) { MockA* a = new MockA; Mock::AllowLeak(a); -- cgit v1.2.3 From c2ad46a5df4414fc2b804c53525f4578f01a3dfe Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 2 Jun 2009 20:41:21 +0000 Subject: Improves gmock generator and adds a test for it (by Neal Norwitz). --- scripts/generator/cpp/ast.py | 14 +-- scripts/generator/cpp/gmock_class.py | 19 +++-- scripts/generator/cpp/gmock_class_test.py | 137 ++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 11 deletions(-) create mode 100755 scripts/generator/cpp/gmock_class_test.py diff --git a/scripts/generator/cpp/ast.py b/scripts/generator/cpp/ast.py index 6d1c8d3e..47dc9a07 100755 --- a/scripts/generator/cpp/ast.py +++ b/scripts/generator/cpp/ast.py @@ -782,7 +782,7 @@ class AstBuilder(object): parts = self.converter.DeclarationToParts(temp_tokens, True) (name, type_name, templated_types, modifiers, default, unused_other_tokens) = parts - + t0 = temp_tokens[0] names = [t.name for t in temp_tokens] if templated_types: @@ -1551,18 +1551,22 @@ class AstBuilder(object): token = self._GetNextToken() self.namespace_stack.append(name) assert token.token_type == tokenize.SYNTAX, token + # Create an internal token that denotes when the namespace is complete. + internal_token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP, + None, None) + internal_token.whence = token.whence if token.name == '=': # TODO(nnorwitz): handle aliasing namespaces. name, next_token = self.GetName() assert next_token.name == ';', next_token + self._AddBackToken(internal_token) else: assert token.name == '{', token tokens = list(self.GetScope()) - del tokens[-1] # Remove trailing '}'. + # Replace the trailing } with the internal namespace pop token. + tokens[-1] = internal_token # Handle namespace with nothing in it. self._AddBackTokens(tokens) - token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP, None, None) - self._AddBackToken(token) return None def handle_using(self): @@ -1672,7 +1676,7 @@ def PrintIndentifiers(filename, should_print): if should_print(node): print(node.name) except KeyboardInterrupt: - return + return except: pass diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index 29204247..3ad0bcdd 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2008 Google Inc. +# Copyright 2008 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. @@ -73,7 +73,13 @@ def _GenerateMethods(output_lines, source, class_node): # of the first parameter to the end of the last parameter. start = node.parameters[0].start end = node.parameters[-1].end - args = re.sub(' +', ' ', source[start:end].replace('\n', '')) + # Remove // comments. + args_strings = re.sub(r'//.*', '', source[start:end]) + # Condense multiple spaces and eliminate newlines putting the + # parameters together on a single line. Ensure there is a + # space in an argument which is split by a newline without + # intervening whitespace, e.g.: int\nBar + args = re.sub(' +', ' ', args_strings.replace('\n', ' ')) # Create the prototype. indent = ' ' * _INDENT @@ -120,8 +126,6 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names): lines.append('} // namespace %s' % class_node.namespace[i]) lines.append('') # Add an extra newline. - sys.stdout.write('\n'.join(lines)) - if desired_class_names: missing_class_name_list = list(desired_class_names - processed_class_names) if missing_class_name_list: @@ -129,7 +133,9 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names): sys.stderr.write('Class(es) not found in %s: %s\n' % (filename, ', '.join(missing_class_name_list))) elif not processed_class_names: - sys.stderr.write('No class found in %s\n' % filename) + sys.stderr.write('No class found in %s\n' % filename) + + return lines def main(argv=sys.argv): @@ -164,7 +170,8 @@ def main(argv=sys.argv): # An error message was already printed since we couldn't parse. pass else: - _GenerateMocks(filename, source, entire_ast, desired_class_names) + lines = _GenerateMocks(filename, source, entire_ast, desired_class_names) + sys.stdout.write('\n'.join(lines)) if __name__ == '__main__': diff --git a/scripts/generator/cpp/gmock_class_test.py b/scripts/generator/cpp/gmock_class_test.py new file mode 100755 index 00000000..0132eef4 --- /dev/null +++ b/scripts/generator/cpp/gmock_class_test.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# +# Copyright 2009 Neal Norwitz All Rights Reserved. +# Portions Copyright 2009 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. + +"""Tests for gmock.scripts.generator.cpp.gmock_class.""" + +__author__ = 'nnorwitz@google.com (Neal Norwitz)' + + +import os +import sys +import unittest + +# Allow the cpp imports below to work when run as a standalone script. +sys.path.append(os.path.dirname(os.path.dirname(__file__))) + +from cpp import ast +from cpp import gmock_class + + +class TestCase(unittest.TestCase): + """Helper class that adds assert methods.""" + + def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines): + """Specialized assert that ignores the indent level.""" + stripped_lines = '\n'.join([s.lstrip() for s in lines.split('\n')]) + self.assertEqual(expected_lines, stripped_lines) + + +class GenerateMethodsTest(TestCase): + + def GenerateMethodSource(self, cpp_source): + """Helper method to convert C++ source to gMock output source lines.""" + method_source_lines = [] + # is a pseudo-filename, it is not read or written. + builder = ast.BuilderFromSource(cpp_source, '') + ast_list = list(builder.Generate()) + gmock_class._GenerateMethods(method_source_lines, cpp_source, ast_list[0]) + return ''.join(method_source_lines) + + def testStrangeNewlineInParameter(self): + source = """ +class Foo { + public: + virtual void Bar(int +a) = 0; +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD1(Bar,\nvoid(int a));', + self.GenerateMethodSource(source)) + + def testDoubleSlashCommentsInParameterListAreRemoved(self): + source = """ +class Foo { + public: + virtual void Bar(int a, // inline comments should be elided. + int b // inline comments should be elided. + ) const = 0; +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));', + self.GenerateMethodSource(source)) + + def testCStyleCommentsInParameterListAreNotRemoved(self): + # NOTE(nnorwitz): I'm not sure if it's the best behavior to keep these + # comments. Also note that C style comments after the last parameter + # are still elided. + source = """ +class Foo { + public: + virtual const string& Bar(int /* keeper */, int b); +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nconst string&(int /* keeper */, int b));', + self.GenerateMethodSource(source)) + + +class GenerateMocksTest(TestCase): + + def GenerateMocks(self, cpp_source): + """Helper method to convert C++ source to complete gMock output source.""" + # is a pseudo-filename, it is not read or written. + filename = '' + builder = ast.BuilderFromSource(cpp_source, filename) + ast_list = list(builder.Generate()) + lines = gmock_class._GenerateMocks(filename, cpp_source, ast_list, None) + return '\n'.join(lines) + + def testNamespaces(self): + source = """ +namespace Foo { +namespace Bar { class Forward; } +namespace Baz { + +class Test { + public: + virtual void Foo(); +}; + +} // namespace Baz +} // namespace Foo +""" + expected = """\ +namespace Foo { +namespace Baz { + +class MockTest : public Test { +public: +MOCK_METHOD0(Foo, +void()); +}; + +} // namespace Baz +} // namespace Foo +""" + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) + + +if __name__ == '__main__': + unittest.main() -- cgit v1.2.3 From b82431625d1842d1498f3c0e6f1923ce81837c6e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 4 Jun 2009 05:48:20 +0000 Subject: Makes all container matchers work with (possibly multi-dimensional) native arrays; makes Contains() accept a matcher; adds Value(x, m); improves gmock doctor to diagnose the Type in Template Base disease. --- include/gmock/gmock-generated-matchers.h | 108 +++++------ include/gmock/gmock-generated-matchers.h.pump | 81 +++------ include/gmock/gmock-matchers.h | 170 ++++++++++++++++-- include/gmock/gmock-printers.h | 34 +++- include/gmock/internal/gmock-internal-utils.h | 247 +++++++++++++++++++++++++- scripts/generator/README | 2 +- scripts/generator/cpp/gmock_class_test.py | 2 +- scripts/gmock_doctor.py | 67 ++++++- test/gmock-generated-matchers_test.cc | 123 ++++++++++++- test/gmock-internal-utils_test.cc | 231 ++++++++++++++++++++++++ test/gmock-matchers_test.cc | 78 +++++++- test/gmock-printers_test.cc | 45 +++++ 12 files changed, 1026 insertions(+), 162 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index afe1bd48..f3484cb4 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -50,7 +50,10 @@ template class ElementsAreMatcherImpl : public MatcherInterface { public: typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef internal::StlContainerView View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + typedef typename StlContainer::value_type Element; // Constructs the matcher from a sequence of element values or // element matchers. @@ -65,12 +68,13 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Returns true iff 'container' matches. virtual bool Matches(Container container) const { - if (container.size() != count()) + StlContainerReference stl_container = View::ConstReference(container); + if (stl_container.size() != count()) return false; - typename RawContainer::const_iterator container_iter = container.begin(); - for (size_t i = 0; i != count(); ++container_iter, ++i) { - if (!matchers_[i].Matches(*container_iter)) + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + if (!matchers_[i].Matches(*it)) return false; } @@ -116,15 +120,16 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Explains why 'container' matches, or doesn't match, this matcher. virtual void ExplainMatchResultTo(Container container, ::std::ostream* os) const { + StlContainerReference stl_container = View::ConstReference(container); if (Matches(container)) { // We need to explain why *each* element matches (the obvious // ones can be skipped). bool reason_printed = false; - typename RawContainer::const_iterator container_iter = container.begin(); - for (size_t i = 0; i != count(); ++container_iter, ++i) { + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + matchers_[i].ExplainMatchResultTo(*it, &ss); const string s = ss.str(); if (!s.empty()) { @@ -137,7 +142,7 @@ class ElementsAreMatcherImpl : public MatcherInterface { } } else { // We need to explain why the container doesn't match. - const size_t actual_count = container.size(); + const size_t actual_count = stl_container.size(); if (actual_count != count()) { // The element count doesn't match. If the container is // empty, there's no need to explain anything as Google Mock @@ -152,16 +157,16 @@ class ElementsAreMatcherImpl : public MatcherInterface { // The container has the right size but at least one element // doesn't match expectation. We need to find this element and // explain why it doesn't match. - typename RawContainer::const_iterator container_iter = container.begin(); - for (size_t i = 0; i != count(); ++container_iter, ++i) { - if (matchers_[i].Matches(*container_iter)) { + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + if (matchers_[i].Matches(*it)) { continue; } *os << "element " << i << " doesn't match"; ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + matchers_[i].ExplainMatchResultTo(*it, &ss); const string s = ss.str(); if (!s.empty()) { *os << " (" << s << ")"; @@ -190,7 +195,8 @@ class ElementsAreMatcher0 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher* const matchers = NULL; return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); @@ -206,7 +212,8 @@ class ElementsAreMatcher1 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -228,7 +235,8 @@ class ElementsAreMatcher2 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -253,7 +261,8 @@ class ElementsAreMatcher3 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -280,7 +289,8 @@ class ElementsAreMatcher4 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -309,7 +319,8 @@ class ElementsAreMatcher5 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -342,7 +353,8 @@ class ElementsAreMatcher6 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -377,7 +389,8 @@ class ElementsAreMatcher7 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -414,7 +427,8 @@ class ElementsAreMatcher8 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -454,7 +468,8 @@ class ElementsAreMatcher9 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -496,7 +511,8 @@ class ElementsAreMatcher10 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { MatcherCast(e1_), @@ -538,7 +554,8 @@ class ElementsAreArrayMatcher { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); } @@ -1573,45 +1590,4 @@ string FormatMatcherDescription( p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>::\ gmock_Impl::Matches(arg_type arg) const -namespace testing { -namespace internal { - -// Returns true iff element is in the STL-style container. -template -inline bool Contains(const Container& container, const Element& element) { - return ::std::find(container.begin(), container.end(), element) != - container.end(); -} - -// Returns true iff element is in the C-style array. -template -inline bool Contains(const ArrayElement (&array)[N], const Element& element) { - return ::std::find(array, array + N, element) != array + N; -} - -} // namespace internal - -// Matches an STL-style container or a C-style array that contains the given -// element. -// -// Examples: -// ::std::set page_ids; -// page_ids.insert(3); -// page_ids.insert(1); -// EXPECT_THAT(page_ids, Contains(1)); -// EXPECT_THAT(page_ids, Contains(3.0)); -// EXPECT_THAT(page_ids, Not(Contains(4))); -// -// ::std::map page_lengths; -// page_lengths[1] = 100; -// EXPECT_THAT(map_int, Contains(::std::pair(1, 100))); -// -// const char* user_ids[] = { "joe", "mike", "tom" }; -// EXPECT_THAT(user_ids, Contains(::std::string("tom"))); -MATCHER_P(Contains, element, "") { - return internal::Contains(arg, element); -} - -} // namespace testing - #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 09dfedfc..4495547d 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -53,7 +53,10 @@ template class ElementsAreMatcherImpl : public MatcherInterface { public: typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef internal::StlContainerView View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + typedef typename StlContainer::value_type Element; // Constructs the matcher from a sequence of element values or // element matchers. @@ -68,12 +71,13 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Returns true iff 'container' matches. virtual bool Matches(Container container) const { - if (container.size() != count()) + StlContainerReference stl_container = View::ConstReference(container); + if (stl_container.size() != count()) return false; - typename RawContainer::const_iterator container_iter = container.begin(); - for (size_t i = 0; i != count(); ++container_iter, ++i) { - if (!matchers_[i].Matches(*container_iter)) + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + if (!matchers_[i].Matches(*it)) return false; } @@ -119,15 +123,16 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Explains why 'container' matches, or doesn't match, this matcher. virtual void ExplainMatchResultTo(Container container, ::std::ostream* os) const { + StlContainerReference stl_container = View::ConstReference(container); if (Matches(container)) { // We need to explain why *each* element matches (the obvious // ones can be skipped). bool reason_printed = false; - typename RawContainer::const_iterator container_iter = container.begin(); - for (size_t i = 0; i != count(); ++container_iter, ++i) { + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + matchers_[i].ExplainMatchResultTo(*it, &ss); const string s = ss.str(); if (!s.empty()) { @@ -140,7 +145,7 @@ class ElementsAreMatcherImpl : public MatcherInterface { } } else { // We need to explain why the container doesn't match. - const size_t actual_count = container.size(); + const size_t actual_count = stl_container.size(); if (actual_count != count()) { // The element count doesn't match. If the container is // empty, there's no need to explain anything as Google Mock @@ -155,16 +160,16 @@ class ElementsAreMatcherImpl : public MatcherInterface { // The container has the right size but at least one element // doesn't match expectation. We need to find this element and // explain why it doesn't match. - typename RawContainer::const_iterator container_iter = container.begin(); - for (size_t i = 0; i != count(); ++container_iter, ++i) { - if (matchers_[i].Matches(*container_iter)) { + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + if (matchers_[i].Matches(*it)) { continue; } *os << "element " << i << " doesn't match"; ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*container_iter, &ss); + matchers_[i].ExplainMatchResultTo(*it, &ss); const string s = ss.str(); if (!s.empty()) { *os << " (" << s << ")"; @@ -193,7 +198,8 @@ class ElementsAreMatcher0 { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher* const matchers = NULL; return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); @@ -214,7 +220,8 @@ class ElementsAreMatcher$i { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; const Matcher matchers[] = { @@ -248,7 +255,8 @@ class ElementsAreArrayMatcher { operator Matcher() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView::type::value_type + Element; return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); } @@ -590,45 +598,4 @@ $var param_field_decls2 = [[$for j ]] -namespace testing { -namespace internal { - -// Returns true iff element is in the STL-style container. -template -inline bool Contains(const Container& container, const Element& element) { - return ::std::find(container.begin(), container.end(), element) != - container.end(); -} - -// Returns true iff element is in the C-style array. -template -inline bool Contains(const ArrayElement (&array)[N], const Element& element) { - return ::std::find(array, array + N, element) != array + N; -} - -} // namespace internal - -// Matches an STL-style container or a C-style array that contains the given -// element. -// -// Examples: -// ::std::set page_ids; -// page_ids.insert(3); -// page_ids.insert(1); -// EXPECT_THAT(page_ids, Contains(1)); -// EXPECT_THAT(page_ids, Contains(3.0)); -// EXPECT_THAT(page_ids, Not(Contains(4))); -// -// ::std::map page_lengths; -// page_lengths[1] = 100; -// EXPECT_THAT(map_int, Contains(::std::pair(1, 100))); -// -// const char* user_ids[] = { "joe", "mike", "tom" }; -// EXPECT_THAT(user_ids, Contains(::std::string("tom"))); -MATCHER_P(Contains, element, "") { - return internal::Contains(arg, element); -} - -} // namespace testing - #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 0497be27..ce7a2fe9 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1709,60 +1709,164 @@ void ExplainMatchResultTo(const ResultOfMatcher& matcher, template class ContainerEqMatcher { public: - explicit ContainerEqMatcher(const Container& rhs) : rhs_(rhs) {} - bool Matches(const Container& lhs) const { return lhs == rhs_; } + typedef internal::StlContainerView View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + + // We make a copy of rhs in case the elements in it are modified + // after this matcher is created. + explicit ContainerEqMatcher(const Container& rhs) : rhs_(View::Copy(rhs)) { + // Makes sure the user doesn't instantiate this class template + // with a const or reference type. + testing::StaticAssertTypeEq(); + } + + template + bool Matches(const LhsContainer& lhs) const { + // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug + // that causes LhsContainer to be a const type sometimes. + typedef internal::StlContainerView + LhsView; + StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + return lhs_stl_container == rhs_; + } void DescribeTo(::std::ostream* os) const { *os << "equals "; - UniversalPrinter::Print(rhs_, os); + UniversalPrinter::Print(rhs_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "does not equal "; - UniversalPrinter::Print(rhs_, os); + UniversalPrinter::Print(rhs_, os); } - void ExplainMatchResultTo(const Container& lhs, + template + void ExplainMatchResultTo(const LhsContainer& lhs, ::std::ostream* os) const { + // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug + // that causes LhsContainer to be a const type sometimes. + typedef internal::StlContainerView + LhsView; + typedef typename LhsView::type LhsStlContainer; + StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + // Something is different. Check for missing values first. bool printed_header = false; - for (typename Container::const_iterator it = lhs.begin(); - it != lhs.end(); ++it) { - if (std::find(rhs_.begin(), rhs_.end(), *it) == rhs_.end()) { + for (typename LhsStlContainer::const_iterator it = + lhs_stl_container.begin(); + it != lhs_stl_container.end(); ++it) { + if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) == + rhs_.end()) { if (printed_header) { *os << ", "; } else { *os << "Only in actual: "; printed_header = true; } - UniversalPrinter::Print(*it, os); + UniversalPrinter::Print(*it, os); } } // Now check for extra values. bool printed_header2 = false; - for (typename Container::const_iterator it = rhs_.begin(); + for (typename StlContainer::const_iterator it = rhs_.begin(); it != rhs_.end(); ++it) { - if (std::find(lhs.begin(), lhs.end(), *it) == lhs.end()) { + if (internal::ArrayAwareFind( + lhs_stl_container.begin(), lhs_stl_container.end(), *it) == + lhs_stl_container.end()) { if (printed_header2) { *os << ", "; } else { *os << (printed_header ? "; not" : "Not") << " in actual: "; printed_header2 = true; } - UniversalPrinter::Print(*it, os); + UniversalPrinter::Print(*it, os); } } } private: - const Container rhs_; + const StlContainer rhs_; }; -template +template void ExplainMatchResultTo(const ContainerEqMatcher& matcher, - const Container& lhs, + const LhsContainer& lhs, ::std::ostream* os) { matcher.ExplainMatchResultTo(lhs, os); } +// Implements Contains(element_matcher) for the given argument type Container. +template +class ContainsMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; + typedef StlContainerView View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + typedef typename StlContainer::value_type Element; + + template + explicit ContainsMatcherImpl(InnerMatcher inner_matcher) + : inner_matcher_( + testing::SafeMatcherCast(inner_matcher)) {} + + // Returns true iff 'container' matches. + virtual bool Matches(Container container) const { + StlContainerReference stl_container = View::ConstReference(container); + for (typename StlContainer::const_iterator it = stl_container.begin(); + it != stl_container.end(); ++it) { + if (inner_matcher_.Matches(*it)) + return true; + } + return false; + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "contains at least one element that "; + inner_matcher_.DescribeTo(os); + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't contain any element that "; + inner_matcher_.DescribeTo(os); + } + + // Explains why 'container' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(Container container, + ::std::ostream* os) const { + StlContainerReference stl_container = View::ConstReference(container); + + // We need to explain which (if any) element matches inner_matcher_. + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; it != stl_container.end(); ++it, ++i) { + if (inner_matcher_.Matches(*it)) { + *os << "element " << i << " matches"; + return; + } + } + } + + private: + const Matcher inner_matcher_; +}; + +// Implements polymorphic Contains(element_matcher). +template +class ContainsMatcher { + public: + explicit ContainsMatcher(M m) : inner_matcher_(m) {} + + template + operator Matcher() const { + return MakeMatcher(new ContainsMatcherImpl(inner_matcher_)); + } + + private: + const M inner_matcher_; +}; + } // namespace internal // Implements MatcherCast(). @@ -2206,9 +2310,35 @@ Truly(Predicate pred) { // values that are included in one container but not the other. (Duplicate // values and order differences are not explained.) template -inline PolymorphicMatcher > +inline PolymorphicMatcher > ContainerEq(const Container& rhs) { - return MakePolymorphicMatcher(internal::ContainerEqMatcher(rhs)); + // This following line is for working around a bug in MSVC 8.0, + // which causes Container to be a const type sometimes. + typedef GMOCK_REMOVE_CONST_(Container) RawContainer; + return MakePolymorphicMatcher(internal::ContainerEqMatcher(rhs)); +} + +// Matches an STL-style container or a native array that contains at +// least one element matching the given value or matcher. +// +// Examples: +// ::std::set page_ids; +// page_ids.insert(3); +// page_ids.insert(1); +// EXPECT_THAT(page_ids, Contains(1)); +// EXPECT_THAT(page_ids, Contains(Gt(2))); +// EXPECT_THAT(page_ids, Not(Contains(4))); +// +// ::std::map page_lengths; +// page_lengths[1] = 100; +// EXPECT_THAT(map_int, Contains(::std::pair(1, 100))); +// +// const char* user_ids[] = { "joe", "mike", "tom" }; +// EXPECT_THAT(user_ids, Contains(Eq(::std::string("tom")))); +template +inline internal::ContainsMatcher Contains(M matcher) { + return internal::ContainsMatcher(matcher); } // Returns a predicate that is satisfied by anything that matches the @@ -2218,6 +2348,12 @@ inline internal::MatcherAsPredicate Matches(M matcher) { return internal::MatcherAsPredicate(matcher); } +// Returns true iff the value matches the matcher. +template +inline bool Value(const T& value, M matcher) { + return testing::Matches(matcher)(value); +} + // These macros allow using matchers to check values in Google Test // tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher) // succeed iff the value matches the matcher. If the assertion fails, diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index e233ef3e..561de3d9 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -66,10 +66,28 @@ // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// // // Prints the fields of a tuple tersely to a string vector, one // // element for each field. // std::vector UniversalTersePrintTupleFieldsToStrings( // const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ @@ -208,6 +226,9 @@ namespace internal { template class UniversalPrinter; +template +void UniversalPrint(const T& value, ::std::ostream* os); + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template @@ -227,7 +248,9 @@ void DefaultPrintTo(IsContainer /* dummy */, } } *os << ' '; - PrintTo(*it, os); + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); } if (count > 0) { @@ -683,6 +706,15 @@ inline void UniversalTersePrint(char* str, ::std::ostream* os) { UniversalTersePrint(static_cast(str), os); } +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter::Print(value, os); +} + // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index b5e38db3..ee6aa1e2 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -99,6 +99,17 @@ struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { typedef T type; }; // NOLINT +// MSVC 8.0 has a bug which causes the above definition to fail to +// remove the const in 'const int[3]'. The following specialization +// works around the bug. However, it causes trouble with gcc and thus +// needs to be conditionally compiled. +#ifdef _MSC_VER +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; +#endif // _MSC_VER + // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GMOCK_REMOVE_CONST_(T) \ @@ -451,10 +462,6 @@ bool LogIsVisible(LogSeverity severity); // conservative. void Log(LogSeverity severity, const string& message, int stack_frames_to_skip); -// The universal value printer (public/gmock-printers.h) needs this -// to declare an unused << operator in the global namespace. -struct Unused {}; - // TODO(wan@google.com): group all type utilities together. // Type traits. @@ -482,6 +489,238 @@ inline T Invalid() { template <> inline void Invalid() {} +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef const Element* const_iterator; + + // Constructs from a native array passed by reference. + template + NativeArray(const Element (&array)[N], RelationToSource relation) { + Init(array, N, relation); + } + + // Constructs from a native array passed by a pointer and a size. + // For generality we don't artificially restrict the types of the + // pointer and the size. + template + NativeArray(const ::std::tr1::tuple& array, + RelationToSource relation) { + Init(internal::GetRawPointer(::std::tr1::get<0>(array)), + ::std::tr1::get<1>(array), + relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + testing::StaticAssertTypeEq(); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Not implemented as we don't want to support assignment. + void operator=(const NativeArray& rhs); + + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[size]; + CopyArray(array, size, copy); + array_ = copy; + } + size_ = size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; +}; + +// Given a raw type (i.e. having no top-level reference or const +// modifier) RawContainer that's either an STL-style container or a +// native array, class StlContainerView has the +// following members: +// +// - type is a type that provides an STL-style container view to +// (i.e. implements the STL container concept for) RawContainer; +// - const_reference is a type that provides a reference to a const +// RawContainer; +// - ConstReference(raw_container) returns a const reference to an STL-style +// container view to raw_container, which is a RawContainer. +// - Copy(raw_container) returns an STL-style container view of a +// copy of raw_container, which is a RawContainer. +// +// This generic version is used when RawContainer itself is already an +// STL-style container. +template +class StlContainerView { + public: + typedef RawContainer type; + typedef const type& const_reference; + + static const_reference ConstReference(const RawContainer& container) { + // Ensures that RawContainer is not a const type. + testing::StaticAssertTypeEq(); + return container; + } + static type Copy(const RawContainer& container) { return container; } +}; + +// This specialization is used when RawContainer is a native array type. +template +class StlContainerView { + public: + typedef GMOCK_REMOVE_CONST_(Element) RawElement; + typedef internal::NativeArray type; + // NativeArray can represent a native array either by value or by + // reference (selected by a constructor argument), so 'const type' + // can be used to reference a const native array. We cannot + // 'typedef const type& const_reference' here, as that would mean + // ConstReference() has to return a reference to a local variable. + typedef const type const_reference; + + static const_reference ConstReference(const Element (&array)[N]) { + // Ensures that Element is not a const type. + testing::StaticAssertTypeEq(); + return type(array, kReference); + } + static type Copy(const Element (&array)[N]) { + return type(array, kCopy); + } +}; + +// This specialization is used when RawContainer is a native array +// represented as a (pointer, size) tuple. +template +class StlContainerView< ::std::tr1::tuple > { + public: + typedef GMOCK_REMOVE_CONST_( + typename internal::PointeeOf::type) RawElement; + typedef internal::NativeArray type; + typedef const type const_reference; + + static const_reference ConstReference( + const ::std::tr1::tuple& array) { + return type(array, kReference); + } + static type Copy(const ::std::tr1::tuple& array) { + return type(array, kCopy); + } +}; + +// The following specialization prevents the user from instantiating +// StlContainer with a reference type. +template class StlContainerView; + } // namespace internal } // namespace testing diff --git a/scripts/generator/README b/scripts/generator/README index 071bf0fb..d6f95974 100644 --- a/scripts/generator/README +++ b/scripts/generator/README @@ -23,7 +23,7 @@ the environment. For example to use an indent of 4 spaces: INDENT=4 gmock_gen.py header-file.h ClassName -This version was made from SVN revision 279 in the cppclean repository. +This version was made from SVN revision 281 in the cppclean repository. Known Limitations ----------------- diff --git a/scripts/generator/cpp/gmock_class_test.py b/scripts/generator/cpp/gmock_class_test.py index 0132eef4..ae00800f 100755 --- a/scripts/generator/cpp/gmock_class_test.py +++ b/scripts/generator/cpp/gmock_class_test.py @@ -25,7 +25,7 @@ import sys import unittest # Allow the cpp imports below to work when run as a standalone script. -sys.path.append(os.path.dirname(os.path.dirname(__file__))) +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from cpp import ast from cpp import gmock_class diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 1980977c..05e42585 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import re import sys -_VERSION = '1.0.1' +_VERSION = '1.0.3' _COMMON_GMOCK_SYMBOLS = [ # Matchers @@ -63,6 +63,7 @@ _COMMON_GMOCK_SYMBOLS = [ 'Le', 'Lt', 'MatcherCast', + 'Matches', 'MatchesRegex', 'NanSensitiveDoubleEq', 'NanSensitiveFloatEq', @@ -82,6 +83,7 @@ _COMMON_GMOCK_SYMBOLS = [ 'StrNe', 'Truly', 'TypedEq', + 'Value', # Actions 'Assign', @@ -171,7 +173,7 @@ def _NeedToReturnSomethingDiagnoser(msg): regex = (_FILE_LINE_RE + r'(instantiated from here\n.' - r'*gmock-actions\.h.*error: void value not ignored)' + r'*gmock.*actions\.h.*error: void value not ignored)' r'|(error: control reaches end of non-void function)') diagnosis = """ You are using an action that returns void, but it needs to return @@ -346,6 +348,60 @@ Note: the line number may be off; please fix all instances of Return(NULL).""" regex, diagnosis, msg) +_TTB_DIAGNOSIS = """ +In a mock class template, types or typedefs defined in the base class +template are *not* automatically visible. This is how C++ works. Before +you can use a type or typedef named %(type)s defined in base class Base, you +need to make it visible. One way to do it is: + + typedef typename Base::%(type)s %(type)s;""" + + +def _TypeInTemplatedBaseDiagnoser1(msg): + """Diagnoses the TTB disease, given the error messages by gcc. + + This version works when the type is used as the mock function's return + type. + """ + + regex = (r'In member function \'int .*\n' + _FILE_LINE_RE + + r'error: a function call cannot appear in a constant-expression') + diagnosis = _TTB_DIAGNOSIS % {'type': 'Foo'} + return _GenericDiagnoser('TTB', 'Type in Template Base', + regex, diagnosis, msg) + + +def _TypeInTemplatedBaseDiagnoser2(msg): + """Diagnoses the TTB disease, given the error messages by gcc. + + This version works when the type is used as the mock function's sole + parameter type. + """ + + regex = (r'In member function \'int .*\n' + + _FILE_LINE_RE + + r'error: \'(?P.+)\' was not declared in this scope\n' + r'.*error: template argument 1 is invalid\n') + return _GenericDiagnoser('TTB', 'Type in Template Base', + regex, _TTB_DIAGNOSIS, msg) + + +def _TypeInTemplatedBaseDiagnoser3(msg): + """Diagnoses the TTB disease, given the error messages by gcc. + + This version works when the type is used as a parameter of a mock + function that has multiple parameters. + """ + + regex = (r'error: expected `;\' before \'::\' token\n' + + _FILE_LINE_RE + + r'error: \'(?P.+)\' was not declared in this scope\n' + r'.*error: template argument 1 is invalid\n' + r'.*error: \'.+\' was not declared in this scope') + return _GenericDiagnoser('TTB', 'Type in Template Base', + regex, _TTB_DIAGNOSIS, msg) + + def _WrongMockMethodMacroDiagnoser(msg): """Diagnoses the WMM disease, given the error messages by gcc.""" @@ -357,7 +413,7 @@ def _WrongMockMethodMacroDiagnoser(msg): You are using MOCK_METHOD%(wrong_args)s to define a mock method that has %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" - return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn macro', + return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro', regex, diagnosis, msg) @@ -373,7 +429,7 @@ The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* EXPECT_CALL(my_mock, Foo(_)).%(method)s(...); instead of: EXPECT_CALL(my_mock, Foo(_).%(method)s(...));""" - return _GenericDiagnoser('WPP', 'Wrong parenthesis position', + return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position', regex, diagnosis, msg) @@ -389,6 +445,9 @@ _DIAGNOSERS = [ _OverloadedFunctionMatcherDiagnoser, _OverloadedMethodActionDiagnoser1, _OverloadedMethodActionDiagnoser2, + _TypeInTemplatedBaseDiagnoser1, + _TypeInTemplatedBaseDiagnoser2, + _TypeInTemplatedBaseDiagnoser3, _WrongMockMethodMacroDiagnoser, _WrongParenPositionDiagnoser, ] diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 669652b9..26814463 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -53,6 +53,7 @@ using std::pair; using std::set; using std::stringstream; using std::vector; +using std::tr1::make_tuple; using testing::_; using testing::Contains; using testing::ElementsAre; @@ -60,6 +61,7 @@ using testing::ElementsAreArray; using testing::Eq; using testing::Ge; using testing::Gt; +using testing::Lt; using testing::MakeMatcher; using testing::Matcher; using testing::MatcherInterface; @@ -69,6 +71,7 @@ using testing::Pointee; using testing::Ref; using testing::StaticAssertTypeEq; using testing::StrEq; +using testing::Value; using testing::internal::string; // Returns the description of the given matcher. @@ -330,6 +333,39 @@ TEST(ElementsAreTest, WorksWithContainerPointerUsingPointee) { EXPECT_THAT(&v, Not(Pointee(ElementsAre(0, _, 3)))); } +TEST(ElementsAreTest, WorksWithNativeArrayPassedByReference) { + int array[] = { 0, 1, 2 }; + EXPECT_THAT(array, ElementsAre(0, 1, _)); + EXPECT_THAT(array, Not(ElementsAre(1, _, _))); + EXPECT_THAT(array, Not(ElementsAre(0, _))); +} + +class NativeArrayPassedAsPointerAndSize { + public: + MOCK_METHOD2(Helper, void(int* array, int size)); +}; + +TEST(ElementsAreTest, WorksWithNativeArrayPassedAsPointerAndSize) { + int array[] = { 0, 1 }; + ::std::tr1::tuple array_as_tuple(array, 2); + EXPECT_THAT(array_as_tuple, ElementsAre(0, 1)); + EXPECT_THAT(array_as_tuple, Not(ElementsAre(0))); + + NativeArrayPassedAsPointerAndSize helper; + EXPECT_CALL(helper, Helper(_, _)) + .WithArguments(ElementsAre(0, 1)); + helper.Helper(array, 2); +} + +TEST(ElementsAreTest, WorksWithTwoDimensionalNativeArray) { + const char a2[][3] = { "hi", "lo" }; + EXPECT_THAT(a2, ElementsAre(ElementsAre('h', 'i', '\0'), + ElementsAre('l', 'o', '\0'))); + EXPECT_THAT(a2, ElementsAre(StrEq("hi"), StrEq("lo"))); + EXPECT_THAT(a2, ElementsAre(Not(ElementsAre('h', 'o', '\0')), + ElementsAre('l', 'o', '\0'))); +} + // Tests for ElementsAreArray(). Since ElementsAreArray() shares most // of the implementation with ElementsAre(), we don't test it as // thoroughly here. @@ -379,6 +415,17 @@ TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); } +// Since ElementsAre() and ElementsAreArray() share much of the +// implementation, we only do a sanity test for native arrays here. +TEST(ElementsAreArrayTest, WorksWithNativeArray) { + ::std::string a[] = { "hi", "ho" }; + ::std::string b[] = { "hi", "ho" }; + + EXPECT_THAT(a, ElementsAreArray(b)); + EXPECT_THAT(a, ElementsAreArray(b, 2)); + EXPECT_THAT(a, Not(ElementsAreArray(b, 1))); +} + // Tests for the MATCHER*() macro family. // Tests that a simple MATCHER() definition works. @@ -443,12 +490,23 @@ namespace matcher_test { MATCHER(IsOdd, "") { return (arg % 2) != 0; } } // namespace matcher_test -TEST(MatcherTest, WorksInNamespace) { +TEST(MatcherMacroTest, WorksInNamespace) { Matcher m = matcher_test::IsOdd(); EXPECT_FALSE(m.Matches(4)); EXPECT_TRUE(m.Matches(5)); } +// Tests that Value() can be used to compose matchers. +MATCHER(IsPositiveOdd, "") { + return Value(arg, matcher_test::IsOdd()) && arg > 0; +} + +TEST(MatcherMacroTest, CanBeComposedUsingValue) { + EXPECT_THAT(3, IsPositiveOdd()); + EXPECT_THAT(4, Not(IsPositiveOdd())); + EXPECT_THAT(-1, Not(IsPositiveOdd())); +} + // Tests that a simple MATCHER_P() definition works. MATCHER_P(IsGreaterThan32And, n, "") { return arg > 32 && arg > n; } @@ -742,14 +800,31 @@ TEST(MatcherPnMacroTest, TypesAreCorrect) { EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); } +// Tests that matcher-typed parameters can be used in Value() inside a +// MATCHER_Pn definition. + +// Succeeds if arg matches exactly 2 of the 3 matchers. +MATCHER_P3(TwoOf, m1, m2, m3, "") { + const int count = static_cast(Value(arg, m1)) + + static_cast(Value(arg, m2)) + static_cast(Value(arg, m3)); + return count == 2; +} + +TEST(MatcherPnMacroTest, CanUseMatcherTypedParameterInValue) { + EXPECT_THAT(42, TwoOf(Gt(0), Lt(50), Eq(10))); + EXPECT_THAT(0, Not(TwoOf(Gt(-1), Lt(1), Eq(0)))); +} + +// Tests Contains(). + TEST(ContainsTest, ListMatchesWhenElementIsInContainer) { list some_list; some_list.push_back(3); some_list.push_back(1); some_list.push_back(2); EXPECT_THAT(some_list, Contains(1)); - EXPECT_THAT(some_list, Contains(3.0)); - EXPECT_THAT(some_list, Contains(2.0f)); + EXPECT_THAT(some_list, Contains(Gt(2.5))); + EXPECT_THAT(some_list, Contains(Eq(2.0f))); list another_list; another_list.push_back("fee"); @@ -771,8 +846,8 @@ TEST(ContainsTest, SetMatchesWhenElementIsInContainer) { some_set.insert(3); some_set.insert(1); some_set.insert(2); - EXPECT_THAT(some_set, Contains(1.0)); - EXPECT_THAT(some_set, Contains(3.0f)); + EXPECT_THAT(some_set, Contains(Eq(1.0))); + EXPECT_THAT(some_set, Contains(Eq(3.0f))); EXPECT_THAT(some_set, Contains(2)); set another_set; @@ -780,7 +855,7 @@ TEST(ContainsTest, SetMatchesWhenElementIsInContainer) { another_set.insert("fie"); another_set.insert("foe"); another_set.insert("fum"); - EXPECT_THAT(another_set, Contains(string("fum"))); + EXPECT_THAT(another_set, Contains(Eq(string("fum")))); } TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { @@ -795,8 +870,20 @@ TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { } TEST(ContainsTest, DescribesItselfCorrectly) { + const int a[2] = { 1, 2 }; + Matcher m = Contains(2); + EXPECT_EQ("element 1 matches", Explain(m, a)); + + m = Contains(3); + EXPECT_EQ("", Explain(m, a)); +} + +TEST(ContainsTest, ExplainsMatchResultCorrectly) { Matcher > m = Contains(1); - EXPECT_EQ("contains 1", Describe(m)); + EXPECT_EQ("contains at least one element that is equal to 1", Describe(m)); + + Matcher > m2 = Not(m); + EXPECT_EQ("doesn't contain any element that is equal to 1", Describe(m2)); } TEST(ContainsTest, MapMatchesWhenElementIsInContainer) { @@ -823,7 +910,7 @@ TEST(ContainsTest, MapDoesNotMatchWhenElementIsNotInContainer) { TEST(ContainsTest, ArrayMatchesWhenElementIsInContainer) { const char* string_array[] = { "fee", "fie", "foe", "fum" }; - EXPECT_THAT(string_array, Contains(string("fum"))); + EXPECT_THAT(string_array, Contains(Eq(string("fum")))); } TEST(ContainsTest, ArrayDoesNotMatchWhenElementIsNotInContainer) { @@ -831,4 +918,24 @@ TEST(ContainsTest, ArrayDoesNotMatchWhenElementIsNotInContainer) { EXPECT_THAT(int_array, Not(Contains(5))); } +TEST(ContainsTest, AcceptsMatcher) { + const int a[] = { 1, 2, 3 }; + EXPECT_THAT(a, Contains(Gt(2))); + EXPECT_THAT(a, Not(Contains(Gt(4)))); +} + +TEST(ContainsTest, WorksForNativeArrayAsTuple) { + const int a[] = { 1, 2 }; + EXPECT_THAT(make_tuple(a, 2), Contains(1)); + EXPECT_THAT(make_tuple(a, 2), Not(Contains(Gt(3)))); +} + +TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { + int a[][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + EXPECT_THAT(a, Contains(ElementsAre(4, 5, 6))); + EXPECT_THAT(a, Contains(Contains(5))); + EXPECT_THAT(a, Not(Contains(ElementsAre(3, 4, 5)))); + EXPECT_THAT(a, Contains(Not(Contains(5)))); +} + } // namespace diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 7886f6d3..73960df5 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -53,6 +53,7 @@ namespace internal { namespace { +using ::std::tr1::make_tuple; using ::std::tr1::tuple; TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsNoWord) { @@ -130,6 +131,8 @@ TEST(RemoveConstTest, DoesNotAffectNonConstType) { // Tests that RemoveConst removes const from const types. TEST(RemoveConstTest, RemovesConst) { CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); } // Tests GMOCK_REMOVE_CONST_. @@ -721,6 +724,234 @@ TEST(OnCallTest, LogsAnythingArgument) { #endif // 0 +// Tests ArrayEq(). + +TEST(ArrayEqTest, WorksForDegeneratedArrays) { + EXPECT_TRUE(ArrayEq(5, 5L)); + EXPECT_FALSE(ArrayEq('a', 0)); +} + +TEST(ArrayEqTest, WorksForOneDimensionalArrays) { + const int a[] = { 0, 1 }; + long b[] = { 0, 1 }; + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + b[0] = 2; + EXPECT_FALSE(ArrayEq(a, b)); + EXPECT_FALSE(ArrayEq(a, 1, b)); +} + +TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { + const char a[][3] = { "hi", "lo" }; + const char b[][3] = { "hi", "lo" }; + const char c[][3] = { "hi", "li" }; + + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + EXPECT_FALSE(ArrayEq(a, c)); + EXPECT_FALSE(ArrayEq(a, 2, c)); +} + +// Tests ArrayAwareFind(). + +TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { + const char a[] = "hello"; + EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); + EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); +} + +TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { + int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; + const int b[2] = { 2, 3 }; + EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); + + const int c[2] = { 6, 7 }; + EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); +} + +// Tests CopyArray(). + +TEST(CopyArrayTest, WorksForDegeneratedArrays) { + int n = 0; + CopyArray('a', &n); + EXPECT_EQ('a', n); +} + +TEST(CopyArrayTest, WorksForOneDimensionalArrays) { + const char a[3] = "hi"; + int b[3]; + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); + + int c[3]; + CopyArray(a, 3, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { + const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; + int b[2][3]; + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); + + int c[2][3]; + CopyArray(a, 2, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +// Tests NativeArray. + +TEST(NativeArrayTest, ConstructorFromArrayReferenceWorks) { + const int a[3] = { 0, 1, 2 }; + NativeArray na(a, kReference); + EXPECT_EQ(3, na.size()); + EXPECT_EQ(a, na.begin()); +} + +TEST(NativeArrayTest, ConstructorFromTupleWorks) { + int a[3] = { 0, 1, 2 }; + // Tests with a plain pointer. + NativeArray na(make_tuple(a, 3U), kReference); + EXPECT_EQ(a, na.begin()); + + const linked_ptr b(new char); + *b = 'a'; + // Tests with a smart pointer. + NativeArray nb(make_tuple(b, 1), kCopy); + EXPECT_NE(b.get(), nb.begin()); + EXPECT_EQ('a', nb.begin()[0]); +} + +TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { + typedef int Array[2]; + Array* a = new Array[1]; + (*a)[0] = 0; + (*a)[1] = 1; + NativeArray na(*a, kCopy); + EXPECT_NE(*a, na.begin()); + delete[] a; + EXPECT_EQ(0, na.begin()[0]); + EXPECT_EQ(1, na.begin()[1]); + + // We rely on the heap checker to verify that na deletes the copy of + // array. +} + +TEST(NativeArrayTest, TypeMembersAreCorrect) { + StaticAssertTypeEq::value_type>(); + StaticAssertTypeEq::value_type>(); + + StaticAssertTypeEq::const_iterator>(); + StaticAssertTypeEq::const_iterator>(); +} + +TEST(NativeArrayTest, MethodsWork) { + const int a[] = { 0, 1, 2 }; + NativeArray na(a, kCopy); + ASSERT_EQ(3, na.size()); + EXPECT_EQ(3, na.end() - na.begin()); + + NativeArray::const_iterator it = na.begin(); + EXPECT_EQ(0, *it); + ++it; + EXPECT_EQ(1, *it); + it++; + EXPECT_EQ(2, *it); + ++it; + EXPECT_EQ(na.end(), it); + + EXPECT_THAT(na, Eq(na)); + + NativeArray na2(a, kReference); + EXPECT_THAT(na, Eq(na2)); + + const int b1[] = { 0, 1, 1 }; + const int b2[] = { 0, 1, 2, 3 }; + EXPECT_THAT(na, Not(Eq(NativeArray(b1, kReference)))); + EXPECT_THAT(na, Not(Eq(NativeArray(b2, kCopy)))); +} + +TEST(NativeArrayTest, WorksForTwoDimensionalArray) { + const char a[2][3] = { "hi", "lo" }; + NativeArray na(a, kReference); + ASSERT_EQ(2, na.size()); + EXPECT_EQ(a, na.begin()); +} + +// Tests StlContainerView. + +TEST(StlContainerViewTest, WorksForStlContainer) { + StaticAssertTypeEq, + StlContainerView >::type>(); + StaticAssertTypeEq&, + StlContainerView >::const_reference>(); + + typedef std::vector Chars; + Chars v1; + const Chars& v2(StlContainerView::ConstReference(v1)); + EXPECT_EQ(&v1, &v2); + + v1.push_back('a'); + Chars v3 = StlContainerView::Copy(v1); + EXPECT_THAT(v3, Eq(v3)); +} + +TEST(StlContainerViewTest, WorksForStaticNativeArray) { + StaticAssertTypeEq, + StlContainerView::type>(); + StaticAssertTypeEq, + StlContainerView::type>(); + StaticAssertTypeEq, + StlContainerView::type>(); + + StaticAssertTypeEq, + StlContainerView::const_reference>(); + + int a1[3] = { 0, 1, 2 }; + NativeArray a2 = StlContainerView::ConstReference(a1); + EXPECT_EQ(3, a2.size()); + EXPECT_EQ(a1, a2.begin()); + + const NativeArray a3 = StlContainerView::Copy(a1); + ASSERT_EQ(3, a3.size()); + EXPECT_EQ(0, a3.begin()[0]); + EXPECT_EQ(1, a3.begin()[1]); + EXPECT_EQ(2, a3.begin()[2]); + + // Makes sure a1 and a3 aren't aliases. + a1[0] = 3; + EXPECT_EQ(0, a3.begin()[0]); +} + +TEST(StlContainerViewTest, WorksForDynamicNativeArray) { + StaticAssertTypeEq, + StlContainerView >::type>(); + StaticAssertTypeEq, + StlContainerView, int> >::type>(); + + StaticAssertTypeEq, + StlContainerView >::const_reference>(); + + int a1[3] = { 0, 1, 2 }; + NativeArray a2 = StlContainerView >:: + ConstReference(make_tuple(a1, 3)); + EXPECT_EQ(3, a2.size()); + EXPECT_EQ(a1, a2.begin()); + + const NativeArray a3 = StlContainerView >:: + Copy(make_tuple(a1, 3)); + ASSERT_EQ(3, a3.size()); + EXPECT_EQ(0, a3.begin()[0]); + EXPECT_EQ(1, a3.begin()[1]); + EXPECT_EQ(2, a3.begin()[2]); + + // Makes sure a1 and a3 aren't aliases. + a1[0] = 3; + EXPECT_EQ(0, a3.begin()[0]); +} + } // namespace } // namespace internal } // namespace testing diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index e7709018..1226a1d1 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -60,6 +60,7 @@ bool SkipPrefix(const char* prefix, const char** pstr); namespace gmock_matchers_test { using std::stringstream; +using std::tr1::make_tuple; using testing::A; using testing::AllOf; using testing::An; @@ -98,6 +99,7 @@ using testing::StrEq; using testing::StrNe; using testing::Truly; using testing::TypedEq; +using testing::Value; using testing::_; using testing::internal::FloatingEqMatcher; using testing::internal::FormatMatcherDescriptionSyntaxError; @@ -1670,6 +1672,25 @@ TEST(MatchesTest, WorksWithMatcherOnNonRefType) { EXPECT_FALSE(Matches(eq5)(2)); } +// Tests Value(value, matcher). Since Value() is a simple wrapper for +// Matches(), which has been tested already, we don't spend a lot of +// effort on testing Value(). +TEST(ValueTest, WorksWithPolymorphicMatcher) { + EXPECT_TRUE(Value("hi", StartsWith("h"))); + EXPECT_FALSE(Value(5, Gt(10))); +} + +TEST(ValueTest, WorksWithMonomorphicMatcher) { + const Matcher is_zero = Eq(0); + EXPECT_TRUE(Value(0, is_zero)); + EXPECT_FALSE(Value('a', is_zero)); + + int n = 0; + const Matcher ref_n = Ref(n); + EXPECT_TRUE(Value(n, ref_n)); + EXPECT_FALSE(Value(1, ref_n)); +} + // Tests that ASSERT_THAT() and EXPECT_THAT() work when the value // matches the matcher. TEST(MatcherAssertionTest, WorksWhenMatcherIsSatisfied) { @@ -2765,9 +2786,7 @@ TEST(ByRefTest, AllowsNotCopyableValueInMatchers) { // different element types. template -class ContainerEqTest : public testing::Test { - public: -}; +class ContainerEqTest : public testing::Test {}; typedef testing::Types< std::set, @@ -2901,6 +2920,59 @@ TEST(ContainerEqExtraTest, WorksForMaps) { Explain(m, test_map)); } +TEST(ContainerEqExtraTest, WorksForNativeArray) { + int a1[] = { 1, 2, 3 }; + int a2[] = { 1, 2, 3 }; + int b[] = { 1, 2, 4 }; + + EXPECT_THAT(a1, ContainerEq(a2)); + EXPECT_THAT(a1, Not(ContainerEq(b))); +} + +TEST(ContainerEqExtraTest, WorksForTwoDimensionalNativeArray) { + const char a1[][3] = { "hi", "lo" }; + const char a2[][3] = { "hi", "lo" }; + const char b[][3] = { "lo", "hi" }; + + // Tests using ContainerEq() in the first dimension. + EXPECT_THAT(a1, ContainerEq(a2)); + EXPECT_THAT(a1, Not(ContainerEq(b))); + + // Tests using ContainerEq() in the second dimension. + EXPECT_THAT(a1, ElementsAre(ContainerEq(a2[0]), ContainerEq(a2[1]))); + EXPECT_THAT(a1, ElementsAre(Not(ContainerEq(b[0])), ContainerEq(a2[1]))); +} + +TEST(ContainerEqExtraTest, WorksForNativeArrayAsTuple) { + const int a1[] = { 1, 2, 3 }; + const int a2[] = { 1, 2, 3 }; + const int b[] = { 1, 2, 3, 4 }; + + EXPECT_THAT(make_tuple(a1, 3), ContainerEq(a2)); + EXPECT_THAT(make_tuple(a1, 3), Not(ContainerEq(b))); + + const int c[] = { 1, 3, 2 }; + EXPECT_THAT(make_tuple(a1, 3), Not(ContainerEq(c))); +} + +TEST(ContainerEqExtraTest, CopiesNativeArrayParameter) { + std::string a1[][3] = { + { "hi", "hello", "ciao" }, + { "bye", "see you", "ciao" } + }; + + std::string a2[][3] = { + { "hi", "hello", "ciao" }, + { "bye", "see you", "ciao" } + }; + + const Matcher m = ContainerEq(a2); + EXPECT_THAT(a1, m); + + a2[0][0] = "ha"; + EXPECT_THAT(a1, m); +} + // Tests GetParamIndex(). TEST(GetParamIndexTest, WorksForEmptyParamList) { diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index f03be292..8c03ec46 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -154,10 +154,13 @@ using ::std::tr1::tuple; using ::std::vector; using ::testing::ElementsAre; using ::testing::StartsWith; +using ::testing::internal::NativeArray; using ::testing::internal::Strings; using ::testing::internal::UniversalTersePrint; +using ::testing::internal::UniversalPrint; using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; using ::testing::internal::UniversalPrinter; +using ::testing::internal::kReference; using ::testing::internal::string; #if GTEST_OS_WINDOWS @@ -786,6 +789,17 @@ TEST(PrintStlContainerTest, NestedContainer) { EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); } +TEST(PrintStlContainerTest, OneDimensionalNativeArray) { + const int a[] = { 1, 2, 3 }; + NativeArray b(a, kReference); + EXPECT_EQ("{ 1, 2, 3 }", Print(b)); +} + +TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { + const int a[][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + NativeArray b(a, kReference); + EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); +} // Tests printing tuples. @@ -1013,6 +1027,37 @@ TEST(UniversalTersePrintTest, WorksForCString) { EXPECT_EQ("NULL", ss3.str()); } +TEST(UniversalPrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalPrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalPrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalPrint(s1, &ss1); + EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str())); + + char* s2 = const_cast(s1); + ::std::stringstream ss2; + UniversalPrint(s2, &ss2); + EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str())); + + const char* s3 = NULL; + ::std::stringstream ss3; + UniversalPrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + + TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) { EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple()), ElementsAre()); -- cgit v1.2.3 From 240fe5a0cf84258c9baf288b78debd3a4b709913 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 5 Jun 2009 06:42:33 +0000 Subject: Fixes errors in the autotools scripts. --- configure.ac | 2 +- scripts/gmock-config.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c317979f..78ff30d8 100644 --- a/configure.ac +++ b/configure.ac @@ -80,7 +80,7 @@ AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" -GTEST_MIN_VERSION="1.2.1" +GTEST_MIN_VERSION="1.3.0" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. diff --git a/scripts/gmock-config.in b/scripts/gmock-config.in index 016ad611..9ce17a25 100755 --- a/scripts/gmock-config.in +++ b/scripts/gmock-config.in @@ -259,7 +259,7 @@ fi # Add the necessary Google Test bits into the various flag variables gmock_cppflags="${gmock_cppflags} `${gtest_config} --cppflags`" gmock_cxxflags="${gmock_cxxflags} `${gtest_config} --cxxflags`" -gmock_ldflags="${gmock_ldflags}`${gtest_config} --ldflags`" +gmock_ldflags="${gmock_ldflags} `${gtest_config} --ldflags`" gmock_libs="${gmock_libs} `${gtest_config} --libs`" # Do an installation query if requested. -- cgit v1.2.3 From 2661c6821a4d7964697e48747c4d739e1ac3a243 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 9 Jun 2009 05:42:12 +0000 Subject: Implements the Args(m) matcher. --- include/gmock/gmock-generated-matchers.h | 323 ++++++++++++++++++++++++++ include/gmock/gmock-generated-matchers.h.pump | 141 +++++++++++ include/gmock/gmock-matchers.h | 18 +- include/gmock/gmock-spec-builders.h | 4 +- test/gmock-generated-matchers_test.cc | 109 ++++++++- test/gmock-internal-utils_test.cc | 2 +- test/gmock-matchers_test.cc | 21 +- test/gmock_output_test_golden.txt | 8 +- 8 files changed, 597 insertions(+), 29 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index f3484cb4..1a3e60b3 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -45,6 +45,251 @@ namespace testing { namespace internal { +// The type of the i-th (0-based) field of Tuple. +#define GMOCK_FIELD_TYPE_(Tuple, i) \ + typename ::std::tr1::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 ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + 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 ::std::tr1::tuple<> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get(t), get(t), get(t), get(t), get(t), + get(t), get(t), get(t)); + } +}; + +template +class TupleFields { + public: + typedef ::std::tr1::tuple type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + 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 GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(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 Matches(ArgsTuple args) const { + return inner_matcher_.Matches(GetSelectedArgs(args)); + } + + virtual void DescribeTo(::std::ostream* os) const { + PrintIndices(os); + inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + PrintIndices(os); + inner_matcher_.DescribeNegationTo(os); + } + + virtual void ExplainMatchResultTo(ArgsTuple args, + ::std::ostream* os) const { + inner_matcher_.ExplainMatchResultTo(GetSelectedArgs(args), 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 << "are a tuple 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_; +}; + +template +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); + } + + const InnerMatcher inner_matcher_; +}; + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -567,6 +812,84 @@ class ElementsAreArrayMatcher { } // 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(e0, e1, ..., e_n) matches an STL-style container with // (n + 1) elements, where the i-th element in the container must // match the i-th argument in the list. Each argument of diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 4495547d..653a2e87 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -3,6 +3,7 @@ $$ This is a Pump source file. Please use Pump to convert it to $$ gmock-generated-variadic-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. // @@ -48,6 +49,130 @@ $var n = 10 $$ The maximum arity we support. 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 ::std::tr1::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 ::std::tr1::tuple<$for i, [[GMOCK_FIELD_TYPE_(Tuple, k$i)]]> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + 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 ::std::tr1::tuple<$for j, [[GMOCK_FIELD_TYPE_(Tuple, k$j)]]> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + 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 GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(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 Matches(ArgsTuple args) const { + return inner_matcher_.Matches(GetSelectedArgs(args)); + } + + virtual void DescribeTo(::std::ostream* os) const { + PrintIndices(os); + inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + PrintIndices(os); + inner_matcher_.DescribeNegationTo(os); + } + + virtual void ExplainMatchResultTo(ArgsTuple args, + ::std::ostream* os) const { + inner_matcher_.ExplainMatchResultTo(GetSelectedArgs(args), 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 << "are a tuple 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_; +}; + +template +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); + } + + const InnerMatcher inner_matcher_; +}; + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -268,6 +393,21 @@ class ElementsAreArrayMatcher { } // 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(e0, e1, ..., e_n) matches an STL-style container with // (n + 1) elements, where the i-th element in the container must // match the i-th argument in the list. Each argument of @@ -282,6 +422,7 @@ inline internal::ElementsAreMatcher0 ElementsAre() { return internal::ElementsAreMatcher0(); } +$range i 1..n $for i [[ $range j 1..i diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index ce7a2fe9..f4d5b0a6 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -938,7 +938,7 @@ class MatchesRegexMatcher { // // We define this as a macro in order to eliminate duplicated source // code. -#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \ +#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op) \ class name##2Matcher { \ public: \ template \ @@ -953,21 +953,21 @@ class MatchesRegexMatcher { return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ } \ virtual void DescribeTo(::std::ostream* os) const { \ - *os << "argument #0 is " relation " argument #1"; \ + *os << "are a pair (x, y) where x " #op " y"; \ } \ virtual void DescribeNegationTo(::std::ostream* os) const { \ - *os << "argument #0 is not " relation " argument #1"; \ + *os << "are a pair (x, y) where x " #op " y is false"; \ } \ }; \ } // Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==, "equal to"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ge, >=, "greater than or equal to"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Gt, >, "greater than"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Le, <=, "less than or equal to"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Lt, <, "less than"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "not equal to"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ge, >=); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Gt, >); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Le, <=); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Lt, <); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=); #undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index d4578ac7..c002ae7f 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -795,9 +795,9 @@ class Expectation : public ExpectationBase { DescribeMatchFailureTupleTo(matchers_, args, os); } if (!extra_matcher_.Matches(args)) { - *os << " Expected: "; + *os << " Expected args: "; extra_matcher_.DescribeTo(os); - *os << "\n Actual: false"; + *os << "\n Actual: don't match"; internal::ExplainMatchResultAsNeededTo( extra_matcher_, args, os); diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 26814463..7e716981 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -53,8 +53,11 @@ using std::pair; using std::set; using std::stringstream; using std::vector; +using std::tr1::get; using std::tr1::make_tuple; +using std::tr1::tuple; using testing::_; +using testing::Args; using testing::Contains; using testing::ElementsAre; using testing::ElementsAreArray; @@ -98,6 +101,107 @@ string Explain(const MatcherType& m, const Value& x) { return ss.str(); } +// Tests Args(m). + +TEST(ArgsTest, AcceptsZeroTemplateArg) { + const tuple t(5, true); + EXPECT_THAT(t, Args<>(Eq(tuple<>()))); + EXPECT_THAT(t, Not(Args<>(Ne(tuple<>())))); +} + +TEST(ArgsTest, AcceptsOneTemplateArg) { + const tuple t(5, true); + EXPECT_THAT(t, Args<0>(Eq(make_tuple(5)))); + EXPECT_THAT(t, Args<1>(Eq(make_tuple(true)))); + EXPECT_THAT(t, Not(Args<1>(Eq(make_tuple(false))))); +} + +TEST(ArgsTest, AcceptsTwoTemplateArgs) { + const tuple t(4, 5, 6L); // NOLINT + + EXPECT_THAT(t, (Args<0, 1>(Lt()))); + EXPECT_THAT(t, (Args<1, 2>(Lt()))); + EXPECT_THAT(t, Not(Args<0, 2>(Gt()))); +} + +TEST(ArgsTest, AcceptsRepeatedTemplateArgs) { + const tuple t(4, 5, 6L); // NOLINT + EXPECT_THAT(t, (Args<0, 0>(Eq()))); + EXPECT_THAT(t, Not(Args<1, 1>(Ne()))); +} + +TEST(ArgsTest, AcceptsDecreasingTemplateArgs) { + const tuple t(4, 5, 6L); // NOLINT + EXPECT_THAT(t, (Args<2, 0>(Gt()))); + EXPECT_THAT(t, Not(Args<2, 1>(Lt()))); +} + +MATCHER(SumIsZero, "") { + return get<0>(arg) + get<1>(arg) + get<2>(arg) == 0; +} + +TEST(ArgsTest, AcceptsMoreTemplateArgsThanArityOfOriginalTuple) { + EXPECT_THAT(make_tuple(-1, 2), (Args<0, 0, 1>(SumIsZero()))); + EXPECT_THAT(make_tuple(1, 2), Not(Args<0, 0, 1>(SumIsZero()))); +} + +TEST(ArgsTest, CanBeNested) { + const tuple t(4, 5, 6L, 6); // NOLINT + EXPECT_THAT(t, (Args<1, 2, 3>(Args<1, 2>(Eq())))); + EXPECT_THAT(t, (Args<0, 1, 3>(Args<0, 2>(Lt())))); +} + +TEST(ArgsTest, CanMatchTupleByValue) { + typedef tuple Tuple3; + const Matcher m = Args<1, 2>(Lt()); + EXPECT_TRUE(m.Matches(Tuple3('a', 1, 2))); + EXPECT_FALSE(m.Matches(Tuple3('b', 2, 2))); +} + +TEST(ArgsTest, CanMatchTupleByReference) { + typedef tuple Tuple3; + const Matcher m = Args<0, 1>(Lt()); + EXPECT_TRUE(m.Matches(Tuple3('a', 'b', 2))); + EXPECT_FALSE(m.Matches(Tuple3('b', 'b', 2))); +} + +// Validates that arg is printed as str. +MATCHER_P(PrintsAs, str, "") { + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(arg_type)) RawTuple; + return + testing::internal::UniversalPrinter::PrintToString(arg) == str; +} + +TEST(ArgsTest, AcceptsTenTemplateArgs) { + EXPECT_THAT(make_tuple(0, 1L, 2, 3L, 4, 5, 6, 7, 8, 9), + (Args<9, 8, 7, 6, 5, 4, 3, 2, 1, 0>( + PrintsAs("(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)")))); + EXPECT_THAT(make_tuple(0, 1L, 2, 3L, 4, 5, 6, 7, 8, 9), + Not(Args<9, 8, 7, 6, 5, 4, 3, 2, 1, 0>( + PrintsAs("(0, 8, 7, 6, 5, 4, 3, 2, 1, 0)")))); +} + +TEST(ArgsTest, DescirbesSelfCorrectly) { + const Matcher > m = Args<2, 0>(Lt()); + EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair (x, y) where x < y", + Describe(m)); +} + +TEST(ArgsTest, DescirbesNestedArgsCorrectly) { + const Matcher&> m = + Args<0, 2, 3>(Args<2, 0>(Lt())); + EXPECT_EQ("are a tuple whose fields (#0, #2, #3) are a tuple " + "whose fields (#2, #0) are a pair (x, y) where x < y", + Describe(m)); +} + +TEST(ArgsTest, DescribesNegationCorrectly) { + const Matcher > m = Args<1, 0>(Gt()); + EXPECT_EQ("are a tuple whose fields (#1, #0) are a pair (x, y) " + "where x > y is false", + DescribeNegation(m)); +} + // For testing ExplainMatchResultTo(). class GreaterThanMatcher : public MatcherInterface { public: @@ -926,8 +1030,9 @@ TEST(ContainsTest, AcceptsMatcher) { TEST(ContainsTest, WorksForNativeArrayAsTuple) { const int a[] = { 1, 2 }; - EXPECT_THAT(make_tuple(a, 2), Contains(1)); - EXPECT_THAT(make_tuple(a, 2), Not(Contains(Gt(3)))); + const int* const pointer = a; + EXPECT_THAT(make_tuple(pointer, 2), Contains(1)); + EXPECT_THAT(make_tuple(pointer, 2), Not(Contains(Gt(3)))); } TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 73960df5..912ee357 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -941,7 +941,7 @@ TEST(StlContainerViewTest, WorksForDynamicNativeArray) { EXPECT_EQ(a1, a2.begin()); const NativeArray a3 = StlContainerView >:: - Copy(make_tuple(a1, 3)); + Copy(make_tuple(static_cast(a1), 3)); ASSERT_EQ(3, a3.size()); EXPECT_EQ(0, a3.begin()[0]); EXPECT_EQ(1, a3.begin()[1]); diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 1226a1d1..4ee6ea81 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -1335,7 +1335,7 @@ TEST(Eq2Test, MatchesEqualArguments) { // Tests that Eq() describes itself properly. TEST(Eq2Test, CanDescribeSelf) { Matcher m = Eq(); - EXPECT_EQ("argument #0 is equal to argument #1", Describe(m)); + EXPECT_EQ("are a pair (x, y) where x == y", Describe(m)); } // Tests that Ge() matches a 2-tuple where the first field >= the @@ -1350,8 +1350,7 @@ TEST(Ge2Test, MatchesGreaterThanOrEqualArguments) { // Tests that Ge() describes itself properly. TEST(Ge2Test, CanDescribeSelf) { Matcher m = Ge(); - EXPECT_EQ("argument #0 is greater than or equal to argument #1", - Describe(m)); + EXPECT_EQ("are a pair (x, y) where x >= y", Describe(m)); } // Tests that Gt() matches a 2-tuple where the first field > the @@ -1366,7 +1365,7 @@ TEST(Gt2Test, MatchesGreaterThanArguments) { // Tests that Gt() describes itself properly. TEST(Gt2Test, CanDescribeSelf) { Matcher m = Gt(); - EXPECT_EQ("argument #0 is greater than argument #1", Describe(m)); + EXPECT_EQ("are a pair (x, y) where x > y", Describe(m)); } // Tests that Le() matches a 2-tuple where the first field <= the @@ -1381,8 +1380,7 @@ TEST(Le2Test, MatchesLessThanOrEqualArguments) { // Tests that Le() describes itself properly. TEST(Le2Test, CanDescribeSelf) { Matcher m = Le(); - EXPECT_EQ("argument #0 is less than or equal to argument #1", - Describe(m)); + EXPECT_EQ("are a pair (x, y) where x <= y", Describe(m)); } // Tests that Lt() matches a 2-tuple where the first field < the @@ -1397,7 +1395,7 @@ TEST(Lt2Test, MatchesLessThanArguments) { // Tests that Lt() describes itself properly. TEST(Lt2Test, CanDescribeSelf) { Matcher m = Lt(); - EXPECT_EQ("argument #0 is less than argument #1", Describe(m)); + EXPECT_EQ("are a pair (x, y) where x < y", Describe(m)); } // Tests that Ne() matches a 2-tuple where the first field != the @@ -1412,7 +1410,7 @@ TEST(Ne2Test, MatchesUnequalArguments) { // Tests that Ne() describes itself properly. TEST(Ne2Test, CanDescribeSelf) { Matcher m = Ne(); - EXPECT_EQ("argument #0 is not equal to argument #1", Describe(m)); + EXPECT_EQ("are a pair (x, y) where x != y", Describe(m)); } // Tests that Not(m) matches any value that doesn't match m. @@ -2948,11 +2946,12 @@ TEST(ContainerEqExtraTest, WorksForNativeArrayAsTuple) { const int a2[] = { 1, 2, 3 }; const int b[] = { 1, 2, 3, 4 }; - EXPECT_THAT(make_tuple(a1, 3), ContainerEq(a2)); - EXPECT_THAT(make_tuple(a1, 3), Not(ContainerEq(b))); + const int* const p1 = a1; + EXPECT_THAT(make_tuple(p1, 3), ContainerEq(a2)); + EXPECT_THAT(make_tuple(p1, 3), Not(ContainerEq(b))); const int c[] = { 1, 3, 2 }; - EXPECT_THAT(make_tuple(a1, 3), Not(ContainerEq(c))); + EXPECT_THAT(make_tuple(p1, 3), Not(ContainerEq(c))); } TEST(ContainerEqExtraTest, CopiesNativeArrayParameter) { diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index 887b7be7..b4d2ea06 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -183,8 +183,8 @@ Unexpected mock function call - returning default value. Google Mock tried the following 1 expectation, but it didn't match: FILE:#: - Expected: argument #0 is greater than or equal to argument #1 - Actual: false + Expected args: are a pair (x, y) where x >= y + Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.MismatchWithArguments @@ -199,8 +199,8 @@ Google Mock tried the following 1 expectation, but it didn't match: FILE:#: Expected arg #0: is greater than or equal to 2 Actual: 1 - Expected: argument #0 is greater than or equal to argument #1 - Actual: false + Expected args: are a pair (x, y) where x >= y + Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.MismatchArgumentsAndWithArguments -- cgit v1.2.3 From bf55085d456e3ee55eb234c98c435e54d0a2d5aa Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 9 Jun 2009 06:09:53 +0000 Subject: Implements .With() as a synonym of .WithArguments(); implements AllArgs(m) as a synonym of m; relies on gtest-port to #include tuple; fixes a compatibility with Symbian. --- include/gmock/gmock-matchers.h | 10 ++++ include/gmock/gmock-spec-builders.h | 104 +++++++++++++++++++--------------- include/gmock/gmock.h | 8 +-- include/gmock/internal/gmock-port.h | 14 +---- src/gmock-internal-utils.cc | 17 +++--- test/gmock-generated-matchers_test.cc | 2 +- test/gmock-matchers_test.cc | 30 ++++++++++ test/gmock-spec-builders_test.cc | 67 +++++++++++++++------- test/gmock_link_test.h | 1 + test/gmock_output_test_.cc | 12 ++-- test/gmock_output_test_golden.txt | 12 ++-- 11 files changed, 176 insertions(+), 101 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index f4d5b0a6..dc252e3e 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2354,6 +2354,16 @@ inline bool Value(const T& value, M matcher) { return testing::Matches(matcher)(value); } +// AllArgs(m) is a synonym of m. This is useful in +// +// EXPECT_CALL(foo, Bar(_, _)).With(AllArgs(Eq())); +// +// which is easier to read than +// +// EXPECT_CALL(foo, Bar(_, _)).With(Eq()); +template +inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; } + // These macros allow using matchers to check values in Google Test // tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher) // succeed iff the value matches the matcher. If the assertion fails, diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index c002ae7f..b570c00c 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -37,16 +37,16 @@ // a mock method. The syntax is: // // ON_CALL(mock_object, Method(argument-matchers)) -// .WithArguments(multi-argument-matcher) +// .With(multi-argument-matcher) // .WillByDefault(action); // -// where the .WithArguments() clause is optional. +// where the .With() clause is optional. // // A user can use the EXPECT_CALL() macro to specify an expectation on // a mock method. The syntax is: // // EXPECT_CALL(mock_object, Method(argument-matchers)) -// .WithArguments(multi-argument-matchers) +// .With(multi-argument-matchers) // .Times(cardinality) // .InSequence(sequences) // .WillOnce(action) @@ -144,31 +144,39 @@ class DefaultActionSpec { // bug in Symbian's C++ compiler (cannot decide between two // overloaded constructors of Matcher). extra_matcher_(A()), - last_clause_(NONE) { + last_clause_(kNone) { } // Where in the source file was the default action spec defined? const char* file() const { return file_; } int line() const { return line_; } - // Implements the .WithArguments() clause. - DefaultActionSpec& WithArguments(const Matcher& m) { + // Implements the .With() clause. + DefaultActionSpec& With(const Matcher& m) { // Makes sure this is called at most once. - ExpectSpecProperty(last_clause_ < WITH_ARGUMENTS, - ".WithArguments() cannot appear " + ExpectSpecProperty(last_clause_ < kWith, + ".With() cannot appear " "more than once in an ON_CALL()."); - last_clause_ = WITH_ARGUMENTS; + last_clause_ = kWith; extra_matcher_ = m; return *this; } + // Implements the .WithArguments() clause as a synonym of .With() + // for backward compatibility. WithArguments() is deprecated and + // new code should always use With(), as .With(Args<1, 2>(m)) is + // clearer than .WithArguments(Args<1, 2>(m)). + DefaultActionSpec& WithArguments(const Matcher& m) { + return With(m); + } + // Implements the .WillByDefault() clause. DefaultActionSpec& WillByDefault(const Action& action) { - ExpectSpecProperty(last_clause_ < WILL_BY_DEFAULT, + ExpectSpecProperty(last_clause_ < kWillByDefault, ".WillByDefault() must appear " "exactly once in an ON_CALL()."); - last_clause_ = WILL_BY_DEFAULT; + last_clause_ = kWillByDefault; ExpectSpecProperty(!action.IsDoDefault(), "DoDefault() cannot be used in ON_CALL()."); @@ -183,7 +191,7 @@ class DefaultActionSpec { // Returns the action specified by the user. const Action& GetAction() const { - AssertSpecProperty(last_clause_ == WILL_BY_DEFAULT, + AssertSpecProperty(last_clause_ == kWillByDefault, ".WillByDefault() must appear exactly " "once in an ON_CALL()."); return action_; @@ -193,9 +201,9 @@ class DefaultActionSpec { enum Clause { // Do not change the order of the enum members! The run-time // syntax checking relies on it. - NONE, - WITH_ARGUMENTS, - WILL_BY_DEFAULT, + kNone, + kWith, + kWillByDefault, }; // Asserts that the ON_CALL() statement has a certain property. @@ -211,7 +219,7 @@ class DefaultActionSpec { // The information in statement // // ON_CALL(mock_object, Method(matchers)) - // .WithArguments(multi-argument-matcher) + // .With(multi-argument-matcher) // .WillByDefault(action); // // is recorded in the data members like this: @@ -228,7 +236,7 @@ class DefaultActionSpec { Action action_; // The last clause in the ON_CALL() statement as seen so far. - // Initially NONE and changes as the statement is parsed. + // Initially kNone and changes as the statement is parsed. Clause last_clause_; }; // class DefaultActionSpec @@ -437,13 +445,13 @@ class ExpectationBase { enum Clause { // Don't change the order of the enum members! - NONE, - WITH_ARGUMENTS, - TIMES, - IN_SEQUENCE, - WILL_ONCE, - WILL_REPEATEDLY, - RETIRES_ON_SATURATION, + kNone, + kWith, + kTimes, + kInSequence, + kWillOnce, + kWillRepeatedly, + kRetiresOnSaturation, }; // Asserts that the EXPECT_CALL() statement has the given property. @@ -581,7 +589,7 @@ class Expectation : public ExpectationBase { repeated_action_specified_(false), repeated_action_(DoDefault()), retires_on_saturation_(false), - last_clause_(NONE), + last_clause_(kNone), action_count_checked_(false) {} virtual ~Expectation() { @@ -590,36 +598,42 @@ class Expectation : public ExpectationBase { CheckActionCountIfNotDone(); } - // Implements the .WithArguments() clause. - Expectation& WithArguments(const Matcher& m) { - if (last_clause_ == WITH_ARGUMENTS) { + // Implements the .With() clause. + Expectation& With(const Matcher& m) { + if (last_clause_ == kWith) { ExpectSpecProperty(false, - ".WithArguments() cannot appear " + ".With() cannot appear " "more than once in an EXPECT_CALL()."); } else { - ExpectSpecProperty(last_clause_ < WITH_ARGUMENTS, - ".WithArguments() must be the first " + ExpectSpecProperty(last_clause_ < kWith, + ".With() must be the first " "clause in an EXPECT_CALL()."); } - last_clause_ = WITH_ARGUMENTS; + last_clause_ = kWith; extra_matcher_ = m; return *this; } + // Implements the .WithArguments() clause as a synonym of .With(). + // This is deprecated and new code should always use With(). + Expectation& WithArguments(const Matcher& m) { + return With(m); + } + // Implements the .Times() clause. Expectation& Times(const Cardinality& cardinality) { - if (last_clause_ ==TIMES) { + if (last_clause_ ==kTimes) { ExpectSpecProperty(false, ".Times() cannot appear " "more than once in an EXPECT_CALL()."); } else { - ExpectSpecProperty(last_clause_ < TIMES, + ExpectSpecProperty(last_clause_ < kTimes, ".Times() cannot appear after " ".InSequence(), .WillOnce(), .WillRepeatedly(), " "or .RetiresOnSaturation()."); } - last_clause_ = TIMES; + last_clause_ = kTimes; ExpectationBase::SpecifyCardinality(cardinality); return *this; @@ -632,11 +646,11 @@ class Expectation : public ExpectationBase { // Implements the .InSequence() clause. Expectation& InSequence(const Sequence& s) { - ExpectSpecProperty(last_clause_ <= IN_SEQUENCE, + ExpectSpecProperty(last_clause_ <= kInSequence, ".InSequence() cannot appear after .WillOnce()," " .WillRepeatedly(), or " ".RetiresOnSaturation()."); - last_clause_ = IN_SEQUENCE; + last_clause_ = kInSequence; s.AddExpectation(owner_->GetLinkedExpectationBase(this)); return *this; @@ -660,10 +674,10 @@ class Expectation : public ExpectationBase { // Implements the .WillOnce() clause. Expectation& WillOnce(const Action& action) { - ExpectSpecProperty(last_clause_ <= WILL_ONCE, + ExpectSpecProperty(last_clause_ <= kWillOnce, ".WillOnce() cannot appear after " ".WillRepeatedly() or .RetiresOnSaturation()."); - last_clause_ = WILL_ONCE; + last_clause_ = kWillOnce; actions_.push_back(action); if (!cardinality_specified()) { @@ -674,16 +688,16 @@ class Expectation : public ExpectationBase { // Implements the .WillRepeatedly() clause. Expectation& WillRepeatedly(const Action& action) { - if (last_clause_ == WILL_REPEATEDLY) { + if (last_clause_ == kWillRepeatedly) { ExpectSpecProperty(false, ".WillRepeatedly() cannot appear " "more than once in an EXPECT_CALL()."); } else { - ExpectSpecProperty(last_clause_ < WILL_REPEATEDLY, + ExpectSpecProperty(last_clause_ < kWillRepeatedly, ".WillRepeatedly() cannot appear " "after .RetiresOnSaturation()."); } - last_clause_ = WILL_REPEATEDLY; + last_clause_ = kWillRepeatedly; repeated_action_specified_ = true; repeated_action_ = action; @@ -699,10 +713,10 @@ class Expectation : public ExpectationBase { // Implements the .RetiresOnSaturation() clause. Expectation& RetiresOnSaturation() { - ExpectSpecProperty(last_clause_ < RETIRES_ON_SATURATION, + ExpectSpecProperty(last_clause_ < kRetiresOnSaturation, ".RetiresOnSaturation() cannot appear " "more than once."); - last_clause_ = RETIRES_ON_SATURATION; + last_clause_ = kRetiresOnSaturation; retires_on_saturation_ = true; // Now that no more action clauses can be specified, we check @@ -717,7 +731,7 @@ class Expectation : public ExpectationBase { return matchers_; } - // Returns the matcher specified by the .WithArguments() clause. + // Returns the matcher specified by the .With() clause. const Matcher& extra_matcher() const { return extra_matcher_; } diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index 22e70287..29d9727c 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -39,14 +39,14 @@ // This file implements the following syntax: // // ON_CALL(mock_object.Method(...)) -// .WithArguments(...) ? +// .With(...) ? // .WillByDefault(...); // -// where WithArguments() is optional and WillByDefault() must appear -// exactly once. +// where With() is optional and WillByDefault() must appear exactly +// once. // // EXPECT_CALL(mock_object.Method(...)) -// .WithArguments(...) ? +// .With(...) ? // .Times(...) ? // .InSequence(...) * // .WillOnce(...) * diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 75be9edd..9ee8f728 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -47,18 +47,8 @@ // To avoid conditional compilation everywhere, we make it // gmock-port.h's responsibility to #include the header implementing -// tr1/tuple. -#if defined(__GNUC__) && GTEST_GCC_VER_ >= 40000 -// GTEST_GCC_VER_ is defined in gtest-port.h and 40000 corresponds to -// version 4.0.0. -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . -#include -#else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -#include -#endif // __GNUC__ +// tr1/tuple. gmock-port.h does this via gtest-port.h, which is +// guaranteed to pull in the tuple header. #if GTEST_OS_LINUX diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index ce17d715..0e693c70 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -131,16 +131,19 @@ void Log(LogSeverity severity, const string& message, // Ensures that logs from different threads don't interleave. MutexLock l(&g_log_mutex); - using ::std::cout; + + // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is a + // macro. + if (severity == WARNING) { // Prints a GMOCK WARNING marker to make the warnings easily searchable. - cout << "\nGMOCK WARNING:"; + std::cout << "\nGMOCK WARNING:"; } // Pre-pends a new-line to message if it doesn't start with one. if (message.empty() || message[0] != '\n') { - cout << "\n"; + std::cout << "\n"; } - cout << message; + std::cout << message; if (stack_frames_to_skip >= 0) { #ifdef NDEBUG // In opt mode, we have to be conservative and skip no stack frame. @@ -153,13 +156,13 @@ void Log(LogSeverity severity, const string& message, // Appends a new-line to message if it doesn't end with one. if (!message.empty() && *message.rbegin() != '\n') { - cout << "\n"; + std::cout << "\n"; } - cout << "Stack trace:\n" + std::cout << "Stack trace:\n" << ::testing::internal::GetCurrentOsStackTraceExceptTop( ::testing::UnitTest::GetInstance(), actual_to_skip); } - cout << ::std::flush; + std::cout << ::std::flush; } } // namespace internal diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 7e716981..19024d0d 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -457,7 +457,7 @@ TEST(ElementsAreTest, WorksWithNativeArrayPassedAsPointerAndSize) { NativeArrayPassedAsPointerAndSize helper; EXPECT_CALL(helper, Helper(_, _)) - .WithArguments(ElementsAre(0, 1)); + .With(ElementsAre(0, 1)); helper.Helper(array, 2); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 4ee6ea81..3541eef7 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -62,6 +62,7 @@ namespace gmock_matchers_test { using std::stringstream; using std::tr1::make_tuple; using testing::A; +using testing::AllArgs; using testing::AllOf; using testing::An; using testing::AnyOf; @@ -1689,6 +1690,35 @@ TEST(ValueTest, WorksWithMonomorphicMatcher) { EXPECT_FALSE(Value(1, ref_n)); } +TEST(AllArgsTest, WorksForTuple) { + EXPECT_THAT(make_tuple(1, 2L), AllArgs(Lt())); + EXPECT_THAT(make_tuple(2L, 1), Not(AllArgs(Lt()))); +} + +TEST(AllArgsTest, WorksForNonTuple) { + EXPECT_THAT(42, AllArgs(Gt(0))); + EXPECT_THAT('a', Not(AllArgs(Eq('b')))); +} + +class AllArgsHelper { + public: + MOCK_METHOD2(Helper, int(char x, int y)); +}; + +TEST(AllArgsTest, WorksInWithClause) { + AllArgsHelper helper; + ON_CALL(helper, Helper(_, _)) + .With(AllArgs(Lt())) + .WillByDefault(Return(1)); + EXPECT_CALL(helper, Helper(_, _)); + EXPECT_CALL(helper, Helper(_, _)) + .With(AllArgs(Gt())) + .WillOnce(Return(2)); + + EXPECT_EQ(1, helper.Helper('\1', 2)); + EXPECT_EQ(2, helper.Helper('a', 1)); +} + // Tests that ASSERT_THAT() and EXPECT_THAT() work when the value // matches the matcher. TEST(MatcherAssertionTest, WorksWhenMatcherIsSatisfied) { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 4711899d..24621371 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -72,6 +72,7 @@ using testing::Const; using testing::DoAll; using testing::DoDefault; using testing::GMOCK_FLAG(verbose); +using testing::Gt; using testing::InSequence; using testing::Invoke; using testing::InvokeWithoutArgs; @@ -96,6 +97,7 @@ class MockA { MOCK_METHOD1(DoA, void(int n)); // NOLINT MOCK_METHOD1(ReturnResult, Result(int n)); // NOLINT MOCK_METHOD2(Binary, bool(int x, int y)); // NOLINT + MOCK_METHOD2(ReturnInt, int(int x, int y)); // NOLINT }; class MockB { @@ -171,25 +173,40 @@ TEST(OnCallSyntaxTest, EvaluatesSecondArgumentOnce) { // Tests that the syntax of ON_CALL() is enforced at run time. -TEST(OnCallSyntaxTest, WithArgumentsIsOptional) { +TEST(OnCallSyntaxTest, WithIsOptional) { MockA a; ON_CALL(a, DoA(5)) .WillByDefault(Return()); ON_CALL(a, DoA(_)) - .WithArguments(_) + .With(_) .WillByDefault(Return()); } -TEST(OnCallSyntaxTest, WithArgumentsCanAppearAtMostOnce) { +TEST(OnCallSyntaxTest, WithCanAppearAtMostOnce) { MockA a; EXPECT_NONFATAL_FAILURE({ // NOLINT ON_CALL(a, ReturnResult(_)) - .WithArguments(_) - .WithArguments(_) + .With(_) + .With(_) .WillByDefault(Return(Result())); - }, ".WithArguments() cannot appear more than once in an ON_CALL()"); + }, ".With() cannot appear more than once in an ON_CALL()"); +} + +TEST(OnCallSyntaxTest, WithArgumentsIsSynonymOfWith) { + MockA a; + ON_CALL(a, ReturnInt(_, _)) + .WithArguments(Lt()) + .WillByDefault(Return(1)); + ON_CALL(a, ReturnInt(_, _)) + .WithArguments(Gt()) + .WillByDefault(Return(2)); + EXPECT_CALL(a, ReturnInt(_, _)) + .Times(AnyNumber()); + + EXPECT_EQ(1, a.ReturnInt(1, 2)); + EXPECT_EQ(2, a.ReturnInt(2, 1)); } #if GTEST_HAS_DEATH_TEST @@ -237,51 +254,61 @@ TEST(ExpectCallSyntaxTest, EvaluatesSecondArgumentOnce) { // Tests that the syntax of EXPECT_CALL() is enforced at run time. -TEST(ExpectCallSyntaxTest, WithArgumentsIsOptional) { +TEST(ExpectCallSyntaxTest, WithIsOptional) { MockA a; EXPECT_CALL(a, DoA(5)) .Times(0); EXPECT_CALL(a, DoA(6)) - .WithArguments(_) + .With(_) .Times(0); } -TEST(ExpectCallSyntaxTest, WithArgumentsCanAppearAtMostOnce) { +TEST(ExpectCallSyntaxTest, WithCanAppearAtMostOnce) { MockA a; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_CALL(a, DoA(6)) - .WithArguments(_) - .WithArguments(_); - }, ".WithArguments() cannot appear more than once in " - "an EXPECT_CALL()"); + .With(_) + .With(_); + }, ".With() cannot appear more than once in an EXPECT_CALL()"); a.DoA(6); } -TEST(ExpectCallSyntaxTest, WithArgumentsMustBeFirstClause) { +TEST(ExpectCallSyntaxTest, WithMustBeFirstClause) { MockA a; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_CALL(a, DoA(1)) .Times(1) - .WithArguments(_); - }, ".WithArguments() must be the first clause in an " - "EXPECT_CALL()"); + .With(_); + }, ".With() must be the first clause in an EXPECT_CALL()"); a.DoA(1); EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_CALL(a, DoA(2)) .WillOnce(Return()) - .WithArguments(_); - }, ".WithArguments() must be the first clause in an " - "EXPECT_CALL()"); + .With(_); + }, ".With() must be the first clause in an EXPECT_CALL()"); a.DoA(2); } +TEST(ExpectCallSyntaxTest, WithArgumentsIsSynonymOfWith) { + MockA a; + EXPECT_CALL(a, ReturnInt(_, _)) + .WithArguments(Lt()) + .WillOnce(Return(1)); + EXPECT_CALL(a, ReturnInt(_, _)) + .WithArguments(Gt()) + .WillOnce(Return(2)); + + EXPECT_EQ(1, a.ReturnInt(1, 2)); + EXPECT_EQ(2, a.ReturnInt(2, 1)); +} + TEST(ExpectCallSyntaxTest, TimesCanBeInferred) { MockA a; diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index 4e0adb71..b903f3cb 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -120,6 +120,7 @@ #include #endif +#include #include #include #include diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index 97619af1..8244f10b 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -177,19 +177,19 @@ TEST_F(GMockOutputTest, MismatchArguments) { foo_.Bar(s, 0, 0); } -TEST_F(GMockOutputTest, MismatchWithArguments) { +TEST_F(GMockOutputTest, MismatchWith) { EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1))) - .WithArguments(Ge()); + .With(Ge()); - foo_.Bar2(2, 3); // Mismatch WithArguments() + foo_.Bar2(2, 3); // Mismatch With() foo_.Bar2(2, 1); } -TEST_F(GMockOutputTest, MismatchArgumentsAndWithArguments) { +TEST_F(GMockOutputTest, MismatchArgumentsAndWith) { EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1))) - .WithArguments(Ge()); + .With(Ge()); - foo_.Bar2(1, 3); // Mismatch arguments and mismatch WithArguments() + foo_.Bar2(1, 3); // Mismatch arguments and mismatch With() foo_.Bar2(2, 1); } diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index b4d2ea06..aeec660f 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -174,7 +174,7 @@ FILE:#: Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.MismatchArguments -[ RUN ] GMockOutputTest.MismatchWithArguments +[ RUN ] GMockOutputTest.MismatchWith unknown file: Failure Unexpected mock function call - returning default value. @@ -187,8 +187,8 @@ FILE:#: Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active -[ FAILED ] GMockOutputTest.MismatchWithArguments -[ RUN ] GMockOutputTest.MismatchArgumentsAndWithArguments +[ FAILED ] GMockOutputTest.MismatchWith +[ RUN ] GMockOutputTest.MismatchArgumentsAndWith unknown file: Failure Unexpected mock function call - returning default value. @@ -203,7 +203,7 @@ FILE:#: Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active -[ FAILED ] GMockOutputTest.MismatchArgumentsAndWithArguments +[ FAILED ] GMockOutputTest.MismatchArgumentsAndWith [ RUN ] GMockOutputTest.UnexpectedCallWithDefaultAction unknown file: Failure @@ -290,8 +290,8 @@ Stack trace: [ FAILED ] GMockOutputTest.UnsatisfiedPrerequisites [ FAILED ] GMockOutputTest.UnsatisfiedExpectation [ FAILED ] GMockOutputTest.MismatchArguments -[ FAILED ] GMockOutputTest.MismatchWithArguments -[ FAILED ] GMockOutputTest.MismatchArgumentsAndWithArguments +[ FAILED ] GMockOutputTest.MismatchWith +[ FAILED ] GMockOutputTest.MismatchArgumentsAndWith [ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction [ FAILED ] GMockOutputTest.ExcessiveCallWithDefaultAction -- cgit v1.2.3 From 07587e9db4145baef2e1cf859bf2b9986326a237 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 11 Jun 2009 04:04:06 +0000 Subject: Works around a gcc bug that causes tr1/tuple to fail to compile when RTTI is disabled. --- Makefile.am | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile.am b/Makefile.am index 7a821a02..927c4982 100644 --- a/Makefile.am +++ b/Makefile.am @@ -135,6 +135,16 @@ check_PROGRAMS += test/gmock_test test_gmock_test_SOURCES = test/gmock_test.cc test_gmock_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la +# A sanity test for verifying that Google Mock works when RTTI is +# disabled. We pick gmock-spec-builders_test.cc as it exercises all +# components of Google Mock. +TESTS += test/gmock_no_rtti_test +check_PROGRAMS += test/gmock_no_rtti_test +test_gmock_no_rtti_test_SOURCES = test/gmock-spec-builders_test.cc \ + src/gmock-all.cc +test_gmock_no_rtti_test_CXXFLAGS = $(AM_CXXFLAGS) -fno-rtti -DGTEST_HAS_RTTI=0 +test_gmock_no_rtti_test_LDADD = $(GTEST_LIBS) + # The following tests depend on the presence of a Python installation and are # keyed off of it. We only add them to the TESTS variable when a Python # interpreter is available. TODO(chandlerc@google.com): While we currently only -- cgit v1.2.3 From 4cd148e588c7433d12a143108c15127aa283407a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 11 Jun 2009 20:07:00 +0000 Subject: Removes the .WithArguments() clause from ON_CALL and EXPECT_CALL. --- include/gmock/gmock-spec-builders.h | 14 -------------- test/gmock-spec-builders_test.cc | 28 ---------------------------- 2 files changed, 42 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index b570c00c..a22bcd11 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -163,14 +163,6 @@ class DefaultActionSpec { return *this; } - // Implements the .WithArguments() clause as a synonym of .With() - // for backward compatibility. WithArguments() is deprecated and - // new code should always use With(), as .With(Args<1, 2>(m)) is - // clearer than .WithArguments(Args<1, 2>(m)). - DefaultActionSpec& WithArguments(const Matcher& m) { - return With(m); - } - // Implements the .WillByDefault() clause. DefaultActionSpec& WillByDefault(const Action& action) { ExpectSpecProperty(last_clause_ < kWillByDefault, @@ -615,12 +607,6 @@ class Expectation : public ExpectationBase { return *this; } - // Implements the .WithArguments() clause as a synonym of .With(). - // This is deprecated and new code should always use With(). - Expectation& WithArguments(const Matcher& m) { - return With(m); - } - // Implements the .Times() clause. Expectation& Times(const Cardinality& cardinality) { if (last_clause_ ==kTimes) { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 24621371..058d343c 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -194,21 +194,6 @@ TEST(OnCallSyntaxTest, WithCanAppearAtMostOnce) { }, ".With() cannot appear more than once in an ON_CALL()"); } -TEST(OnCallSyntaxTest, WithArgumentsIsSynonymOfWith) { - MockA a; - ON_CALL(a, ReturnInt(_, _)) - .WithArguments(Lt()) - .WillByDefault(Return(1)); - ON_CALL(a, ReturnInt(_, _)) - .WithArguments(Gt()) - .WillByDefault(Return(2)); - EXPECT_CALL(a, ReturnInt(_, _)) - .Times(AnyNumber()); - - EXPECT_EQ(1, a.ReturnInt(1, 2)); - EXPECT_EQ(2, a.ReturnInt(2, 1)); -} - #if GTEST_HAS_DEATH_TEST TEST(OnCallSyntaxTest, WillByDefaultIsMandatory) { @@ -296,19 +281,6 @@ TEST(ExpectCallSyntaxTest, WithMustBeFirstClause) { a.DoA(2); } -TEST(ExpectCallSyntaxTest, WithArgumentsIsSynonymOfWith) { - MockA a; - EXPECT_CALL(a, ReturnInt(_, _)) - .WithArguments(Lt()) - .WillOnce(Return(1)); - EXPECT_CALL(a, ReturnInt(_, _)) - .WithArguments(Gt()) - .WillOnce(Return(2)); - - EXPECT_EQ(1, a.ReturnInt(1, 2)); - EXPECT_EQ(2, a.ReturnInt(2, 1)); -} - TEST(ExpectCallSyntaxTest, TimesCanBeInferred) { MockA a; -- cgit v1.2.3 From 90c90f9250f19c3f3a5c2c0887c1d9e414afe41b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 17 Jun 2009 22:11:04 +0000 Subject: Switches from Boost TR1 tuple to gtest's TR1 tuple. --- Makefile.am | 12 +++++ README | 81 ++++++++++++------------------ msvc/gmock_config.vsprops | 7 +-- test/gmock-generated-actions_test.cc | 96 ++++++++++++++++++++++++------------ test/gmock-internal-utils_test.cc | 6 ++- 5 files changed, 114 insertions(+), 88 deletions(-) diff --git a/Makefile.am b/Makefile.am index 927c4982..196b9271 100644 --- a/Makefile.am +++ b/Makefile.am @@ -145,6 +145,18 @@ test_gmock_no_rtti_test_SOURCES = test/gmock-spec-builders_test.cc \ test_gmock_no_rtti_test_CXXFLAGS = $(AM_CXXFLAGS) -fno-rtti -DGTEST_HAS_RTTI=0 test_gmock_no_rtti_test_LDADD = $(GTEST_LIBS) +# A sanity test for verifying that Google Mock works with Google +# Test's TR1 tuple implementation. We pick +# gmock-spec-builders_test.cc as it exercises all components of Google +# Mock. +TESTS += test/gmock_use_own_tuple_test +check_PROGRAMS += test/gmock_use_own_tuple_test +test_gmock_use_own_tuple_test_SOURCES = test/gmock-spec-builders_test.cc \ + src/gmock-all.cc +test_gmock_use_own_tuple_test_CXXFLAGS = \ + $(AM_CXXFLAGS) -DGTEST_USE_OWN_TR1_TUPLE=1 +test_gmock_use_own_tuple_test_LDADD = $(GTEST_LIBS) + # The following tests depend on the presence of a Python installation and are # keyed off of it. We only add them to the TESTS variable when a Python # interpreter is available. TODO(chandlerc@google.com): While we currently only diff --git a/README b/README index f14279ce..9cbda5d5 100644 --- a/README +++ b/README @@ -40,7 +40,7 @@ testing framework for writing tests. It works with Google Test (http://code.google.com/p/googletest/) out of the box. You can use either the copy of Google Test that comes with Google Mock, or a compatible version you already have. This version of Google Mock -requires Google Test 1.3.0. +requires Google Test 1.4.0. You can also easily configure Google Mock to work with another testing framework of your choice; although it will still need Google Test as @@ -57,8 +57,7 @@ package (as described below): * GNU-compatible Make or "gmake" * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) - * gcc 4.0 or newer, or gcc 3.4 or newer with the tr1 tuple library - (from Boost or other vendors). + * gcc 3.4 or newer. Furthermore, if you are building Google Mock from a VCS Checkout (also described below), there are further requirements: @@ -69,12 +68,6 @@ described below), there are further requirements: ### Windows Requirements ### * Microsoft Visual C++ 8.0 SP1 or newer - * An implementation of the tr1 tuple C++ library (You can get it for - free from http://www.boost.org/. We have verified that version - 1.36.0 works. One caveat is this implementation exposes a bug in - Visual C++'s header when exceptions are disabled. - Therefore your project must enable exceptions for this - configuration to work.) ### Mac OS X Requirements ### * Mac OS X 10.4 Tiger or newer @@ -141,6 +134,32 @@ which contains all of the source code. Here are some examples in Linux: tar -xvjf gmock-X.Y.Z.tar.bz2 unzip gmock-X.Y.Z.zip +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 (this requirement is new in +Google Test 1.4.0 and Google Mock 1.2.0, so you may need to take care +of it when upgrading from an earlier version), 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 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. + Building the Source ------------------- ### Linux and Mac OS X (without Xcode) ### @@ -236,46 +255,15 @@ separately. ### Windows ### The msvc/ directory contains VC++ 2005 projects for building Google -Mock and selected tests. In order to build Google Mock you must have -an implementation of TR1 tuple. One library that provides such -implementation is Boost. If you choose to use Boost, download it from -www.boost.org and install it on your system. Note that Boost TR1 tuple -is a header-only library, so the installation only involves unpacking -it to a suitable location - you don't need to compile it or download a -pre-compiled Boost binary. - -Since Boost is quite large, you may prefer to only install the files -actually needed by Google Mock. If so, you can download TR1 tuple -without other parts of Boost from -http://code.google.com/p/googlemock/downloads/list. - -After that you have two options: either set up Boost globally or -modify the Google Mock project to point to your copy of Boost. The -former will let all your tests use the same Boost library while the -latter will allow each of your projects use its own copy. You can also -use a hybrid solution: your project settings will override the -system-wide one. - -For example, if you unpacked boost v1.36.0 into C:\boost: -To set up Boost such that all projects can use it: - * Assuming you are using the Visual Studio 2005 IDE, select Tools | - Options | Projects And Solutions | VC++ Directories. - * In the "Show directories for" drop-down select Include Files. Add - C:\boost\boost_1_36_0\boost\tr1\tr1 and C:\boost\boost_1_36_0 to the - list of directories. - -To configure your project to point to that version of Boost, replace -the value of the BoostDir user macro with C:\boost\boost_1_36_0 in the -msvc/gmock_config.vsprops file. You can use any text editor to edit -that file. +Mock and selected tests. If you want to use a version of Google Test other then the one bundled with Google Mock, change the value of the GTestDir macro in gmock_config.vsprop to point to the new location. -After configuring Boost, just open msvc/gmock.sln and build the library and -tests. 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 msvc/gmock.sln and build the library and tests. 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 and select it. @@ -320,11 +308,6 @@ something like the following will do: g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ path/to/your_test.cc libgmock.a -o your_test -On Windows, you'll also need to add the include path for the boost -headers to the compiler command line. See -http://www.boost.org/doc/libs/1_36_0/doc/html/boost_tr1/usage.html for -how to do it. - Regenerating Source Files ------------------------- Some of Google Mock's source files are generated from templates (not diff --git a/msvc/gmock_config.vsprops b/msvc/gmock_config.vsprops index fa596ef9..a68c32e1 100644 --- a/msvc/gmock_config.vsprops +++ b/msvc/gmock_config.vsprops @@ -6,15 +6,10 @@ > - diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 84e5a413..d0b2ddc9 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -269,13 +269,19 @@ TEST(InvokeTest, FunctionThatTakes6Arguments) { EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); } +// A helper that turns the type of a C-string literal from const +// char[N] to const char*. +inline const char* CharPtr(const char* s) { return s; } + // Tests using Invoke() with a 7-argument function. TEST(InvokeTest, FunctionThatTakes7Arguments) { Action a = Invoke(Concat7); EXPECT_EQ("1234567", - a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7"))); + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7")))); } // Tests using Invoke() with a 8-argument function. @@ -284,7 +290,9 @@ TEST(InvokeTest, FunctionThatTakes8Arguments) { const char*, const char*, const char*, const char*)> a = Invoke(Concat8); EXPECT_EQ("12345678", - a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8"))); + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8")))); } // Tests using Invoke() with a 9-argument function. @@ -293,7 +301,9 @@ TEST(InvokeTest, FunctionThatTakes9Arguments) { const char*, const char*, const char*, const char*, const char*)> a = Invoke(Concat9); EXPECT_EQ("123456789", - a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8", "9"))); + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9")))); } // Tests using Invoke() with a 10-argument function. @@ -301,15 +311,18 @@ TEST(InvokeTest, FunctionThatTakes10Arguments) { Action a = Invoke(Concat10); - EXPECT_EQ("1234567890", a.Perform(make_tuple("1", "2", "3", "4", "5", "6", - "7", "8", "9", "0"))); + EXPECT_EQ("1234567890", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9"), + CharPtr("0")))); } // Tests using Invoke() with functions with parameters declared as Unused. TEST(InvokeTest, FunctionWithUnusedParameters) { Action a1 = Invoke(SumOfFirst2); - EXPECT_EQ(12, a1.Perform(make_tuple(10, 2, 5.6, "hi"))); + EXPECT_EQ(12, a1.Perform(make_tuple(10, 2, 5.6, CharPtr("hi")))); Action a2 = Invoke(SumOfFirst2); @@ -321,7 +334,7 @@ TEST(InvokeTest, MethodWithUnusedParameters) { Foo foo; Action a1 = Invoke(&foo, &Foo::SumOfLast2); - EXPECT_EQ(12, a1.Perform(make_tuple("hi", true, 10, 2))); + EXPECT_EQ(12, a1.Perform(make_tuple(CharPtr("hi"), true, 10, 2))); Action a2 = Invoke(&foo, &Foo::SumOfLast2); @@ -400,7 +413,9 @@ TEST(InvokeMethodTest, MethodThatTakes7Arguments) { const char*, const char*, const char*)> a = Invoke(&foo, &Foo::Concat7); EXPECT_EQ("1234567", - a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7"))); + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7")))); } // Tests using Invoke() with a 8-argument method. @@ -410,7 +425,9 @@ TEST(InvokeMethodTest, MethodThatTakes8Arguments) { const char*, const char*, const char*, const char*)> a = Invoke(&foo, &Foo::Concat8); EXPECT_EQ("12345678", - a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8"))); + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8")))); } // Tests using Invoke() with a 9-argument method. @@ -420,7 +437,9 @@ TEST(InvokeMethodTest, MethodThatTakes9Arguments) { const char*, const char*, const char*, const char*, const char*)> a = Invoke(&foo, &Foo::Concat9); EXPECT_EQ("123456789", - a.Perform(make_tuple("1", "2", "3", "4", "5", "6", "7", "8", "9"))); + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9")))); } // Tests using Invoke() with a 10-argument method. @@ -429,8 +448,11 @@ TEST(InvokeMethodTest, MethodThatTakes10Arguments) { Action a = Invoke(&foo, &Foo::Concat10); - EXPECT_EQ("1234567890", a.Perform(make_tuple("1", "2", "3", "4", "5", "6", - "7", "8", "9", "0"))); + EXPECT_EQ("1234567890", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9"), + CharPtr("0")))); } // Tests using Invoke(f) as an action of a compatible type. @@ -665,7 +687,7 @@ TEST(WithArgsTest, TwoArgs) { Action a = WithArgs<0, 2>(Invoke(Binary)); const char s[] = "Hello"; - EXPECT_EQ(s + 2, a.Perform(make_tuple(s, 0.5, 2))); + EXPECT_EQ(s + 2, a.Perform(make_tuple(CharPtr(s), 0.5, 2))); } // Tests using WithArgs with an action that takes 3 arguments. @@ -679,7 +701,8 @@ TEST(WithArgsTest, ThreeArgs) { TEST(WithArgsTest, FourArgs) { Action a = WithArgs<4, 3, 1, 0>(Invoke(Concat4)); - EXPECT_EQ("4310", a.Perform(make_tuple("0", "1", 2.5, "3", "4"))); + EXPECT_EQ("4310", a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), 2.5, + CharPtr("3"), CharPtr("4")))); } // Tests using WithArgs with an action that takes 5 arguments. @@ -687,42 +710,53 @@ TEST(WithArgsTest, FiveArgs) { Action a = WithArgs<4, 3, 2, 1, 0>(Invoke(Concat5)); - EXPECT_EQ("43210", a.Perform(make_tuple("0", "1", "2", "3", "4"))); + EXPECT_EQ("43210", + a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), CharPtr("2"), + CharPtr("3"), CharPtr("4")))); } // Tests using WithArgs with an action that takes 6 arguments. TEST(WithArgsTest, SixArgs) { Action a = WithArgs<0, 1, 2, 2, 1, 0>(Invoke(Concat6)); - EXPECT_EQ("012210", a.Perform(make_tuple("0", "1", "2"))); + EXPECT_EQ("012210", + a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), CharPtr("2")))); } // Tests using WithArgs with an action that takes 7 arguments. TEST(WithArgsTest, SevenArgs) { Action a = WithArgs<0, 1, 2, 3, 2, 1, 0>(Invoke(Concat7)); - EXPECT_EQ("0123210", a.Perform(make_tuple("0", "1", "2", "3"))); + EXPECT_EQ("0123210", + a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), CharPtr("2"), + CharPtr("3")))); } // Tests using WithArgs with an action that takes 8 arguments. TEST(WithArgsTest, EightArgs) { Action a = WithArgs<0, 1, 2, 3, 0, 1, 2, 3>(Invoke(Concat8)); - EXPECT_EQ("01230123", a.Perform(make_tuple("0", "1", "2", "3"))); + EXPECT_EQ("01230123", + a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), CharPtr("2"), + CharPtr("3")))); } // Tests using WithArgs with an action that takes 9 arguments. TEST(WithArgsTest, NineArgs) { Action a = WithArgs<0, 1, 2, 3, 1, 2, 3, 2, 3>(Invoke(Concat9)); - EXPECT_EQ("012312323", a.Perform(make_tuple("0", "1", "2", "3"))); + EXPECT_EQ("012312323", + a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), CharPtr("2"), + CharPtr("3")))); } // Tests using WithArgs with an action that takes 10 arguments. TEST(WithArgsTest, TenArgs) { Action a = WithArgs<0, 1, 2, 3, 2, 1, 0, 1, 2, 3>(Invoke(Concat10)); - EXPECT_EQ("0123210123", a.Perform(make_tuple("0", "1", "2", "3"))); + EXPECT_EQ("0123210123", + a.Perform(make_tuple(CharPtr("0"), CharPtr("1"), CharPtr("2"), + CharPtr("3")))); } // Tests using WithArgs with an action that is not Invoke(). @@ -736,7 +770,7 @@ class SubstractAction : public ActionInterface { // NOLINT TEST(WithArgsTest, NonInvokeAction) { Action a = // NOLINT WithArgs<2, 1>(MakeAction(new SubstractAction)); - EXPECT_EQ(8, a.Perform(make_tuple("hi", 2, 10))); + EXPECT_EQ(8, a.Perform(make_tuple(CharPtr("hi"), 2, 10))); } // Tests using WithArgs to pass all original arguments in the original order. @@ -758,7 +792,7 @@ TEST(WithArgsTest, ReversedArgumentOrder) { Action a = // NOLINT WithArgs<1, 0>(Invoke(Binary)); const char s[] = "Hello"; - EXPECT_EQ(s + 2, a.Perform(make_tuple(2, s))); + EXPECT_EQ(s + 2, a.Perform(make_tuple(2, CharPtr(s)))); } // Tests using WithArgs with compatible, but not identical, argument types. @@ -1123,16 +1157,16 @@ TEST(ActionMacroTest, CanDefineOverloadedActions) { typedef Action MyAction; const MyAction a1 = OverloadedAction(); - EXPECT_STREQ("hello", a1.Perform(make_tuple(false, "world"))); - EXPECT_STREQ("world", a1.Perform(make_tuple(true, "world"))); + EXPECT_STREQ("hello", a1.Perform(make_tuple(false, CharPtr("world")))); + EXPECT_STREQ("world", a1.Perform(make_tuple(true, CharPtr("world")))); const MyAction a2 = OverloadedAction("hi"); - EXPECT_STREQ("hi", a2.Perform(make_tuple(false, "world"))); - EXPECT_STREQ("world", a2.Perform(make_tuple(true, "world"))); + EXPECT_STREQ("hi", a2.Perform(make_tuple(false, CharPtr("world")))); + EXPECT_STREQ("world", a2.Perform(make_tuple(true, CharPtr("world")))); const MyAction a3 = OverloadedAction("hi", "you"); - EXPECT_STREQ("hi", a3.Perform(make_tuple(true, "world"))); - EXPECT_STREQ("you", a3.Perform(make_tuple(false, "world"))); + EXPECT_STREQ("hi", a3.Perform(make_tuple(true, CharPtr("world")))); + EXPECT_STREQ("you", a3.Perform(make_tuple(false, CharPtr("world")))); } // Tests ACTION_Pn where n >= 3. @@ -1224,8 +1258,8 @@ TEST(ActionPnMacroTest, SimpleTypePromotion) { PadArgument(std::string("foo"), 'r'); Action promo = PadArgument("foo", static_cast('r')); - EXPECT_EQ("foobar", no_promo.Perform(make_tuple("ba"))); - EXPECT_EQ("foobar", promo.Perform(make_tuple("ba"))); + EXPECT_EQ("foobar", no_promo.Perform(make_tuple(CharPtr("ba")))); + EXPECT_EQ("foobar", promo.Perform(make_tuple(CharPtr("ba")))); } // Tests that we can partially restrict parameter types using a @@ -1470,7 +1504,7 @@ TEST(DeleteArgActionTest, TenArgs) { const Action a1 = DeleteArg<9>(); EXPECT_FALSE(is_deleted); - a1.Perform(make_tuple(true, 5, 6, "hi", false, 7, 8, 9, 10, t)); + a1.Perform(make_tuple(true, 5, 6, CharPtr("hi"), false, 7, 8, 9, 10, t)); EXPECT_TRUE(is_deleted); } diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 912ee357..9ab15af2 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -812,8 +812,9 @@ TEST(NativeArrayTest, ConstructorFromArrayReferenceWorks) { TEST(NativeArrayTest, ConstructorFromTupleWorks) { int a[3] = { 0, 1, 2 }; + int* const p = a; // Tests with a plain pointer. - NativeArray na(make_tuple(a, 3U), kReference); + NativeArray na(make_tuple(p, 3U), kReference); EXPECT_EQ(a, na.begin()); const linked_ptr b(new char); @@ -935,8 +936,9 @@ TEST(StlContainerViewTest, WorksForDynamicNativeArray) { StlContainerView >::const_reference>(); int a1[3] = { 0, 1, 2 }; + const int* const p1 = a1; NativeArray a2 = StlContainerView >:: - ConstReference(make_tuple(a1, 3)); + ConstReference(make_tuple(p1, 3)); EXPECT_EQ(3, a2.size()); EXPECT_EQ(a1, a2.begin()); -- cgit v1.2.3 From 81476f2f9070186027e7337854bbcf693b85c6c6 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 22 Jun 2009 23:30:47 +0000 Subject: Makes gmock-spec-builders_test.cc and gmock-internal-utils_test.cc work where both ::string and ::std::string are defined. --- test/gmock-internal-utils_test.cc | 11 ++++++++++- test/gmock-spec-builders_test.cc | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 9ab15af2..20289288 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -501,7 +501,16 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) { class LogIsVisibleTest : public ::testing::Test { protected: - virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); } + virtual void SetUp() { + // The code needs to work when both ::string and ::std::string are + // defined and the flag is implemented as a + // testing::internal::String. In this case, without the call to + // c_str(), the compiler will complain that it cannot figure out + // whether the String flag should be converted to a ::string or an + // ::std::string before being assigned to original_verbose_. + original_verbose_ = GMOCK_FLAG(verbose).c_str(); + } + virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; } string original_verbose_; diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 058d343c..614e4ab5 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1628,7 +1628,16 @@ class LogTestHelper { class GMockLogTest : public ::testing::Test { protected: - virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); } + virtual void SetUp() { + // The code needs to work when both ::string and ::std::string are + // defined and the flag is implemented as a + // testing::internal::String. In this case, without the call to + // c_str(), the compiler will complain that it cannot figure out + // whether the String flag should be converted to a ::string or an + // ::std::string before being assigned to original_verbose_. + original_verbose_ = GMOCK_FLAG(verbose).c_str(); + } + virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; } LogTestHelper helper_; -- cgit v1.2.3 From 4019819dbb5369b1d638503523a04aaf7eb2a5ad Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 1 Jul 2009 05:03:39 +0000 Subject: A trivial comment fix. --- include/gmock/gmock-matchers.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index dc252e3e..4696f704 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2332,7 +2332,8 @@ inline PolymorphicMatcher page_lengths; // page_lengths[1] = 100; -// EXPECT_THAT(map_int, Contains(::std::pair(1, 100))); +// EXPECT_THAT(page_lengths, +// Contains(::std::pair(1, 100))); // // const char* user_ids[] = { "joe", "mike", "tom" }; // EXPECT_THAT(user_ids, Contains(Eq(::std::string("tom")))); -- cgit v1.2.3 From 41b9b0b5614588d252d565646ae43e9607d46502 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 1 Jul 2009 19:04:51 +0000 Subject: Implements Expectation, ExpectationSet, and After for specifying expectation orders. --- include/gmock/gmock-spec-builders.h | 350 +++++++++++++++++++++++++++--------- src/gmock-spec-builders.cc | 34 ++-- test/gmock-spec-builders_test.cc | 322 ++++++++++++++++++++++++++++++++- 3 files changed, 606 insertions(+), 100 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index a22bcd11..0748d9d4 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -49,13 +49,13 @@ // .With(multi-argument-matchers) // .Times(cardinality) // .InSequence(sequences) +// .After(expectations) // .WillOnce(action) // .WillRepeatedly(action) // .RetiresOnSaturation(); // -// where all clauses are optional, .InSequence() and .WillOnce() can -// appear any number of times, and .Times() can be omitted only if -// .WillOnce() or .WillRepeatedly() is present. +// where all clauses are optional, and .InSequence()/.After()/ +// .WillOnce() can appear any number of times. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ @@ -76,22 +76,30 @@ namespace testing { +// An abstract handle of an expectation. +class Expectation; + +// A set of expectation handles. +class ExpectationSet; + // Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION // and MUST NOT BE USED IN USER CODE!!! namespace internal { -template -class FunctionMocker; +// Implements a mock function. +template class FunctionMocker; // Base class for expectations. class ExpectationBase; +// Implements an expectation. +template class TypedExpectation; + // Helper class for testing the Expectation class template. class ExpectationTester; // Base class for function mockers. -template -class FunctionMockerBase; +template class FunctionMockerBase; // Protects the mock object registry (in class Mock), all function // mockers, and all expectations. @@ -232,7 +240,8 @@ class DefaultActionSpec { Clause last_clause_; }; // class DefaultActionSpec -// Possible reactions on uninteresting calls. +// Possible reactions on uninteresting calls. TODO(wan@google.com): +// rename the enum values to the kFoo style. enum CallReaction { ALLOW, WARN, @@ -327,31 +336,166 @@ class Mock { static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker); }; // class Mock +// An abstract handle of an expectation. Useful in the .After() +// clause of EXPECT_CALL() for setting the (partial) order of +// expectations. The syntax: +// +// Expectation e1 = EXPECT_CALL(...)...; +// EXPECT_CALL(...).After(e1)...; +// +// sets two expectations where the latter can only be matched after +// the former has been satisfied. +// +// Notes: +// - This class is copyable and has value semantics. +// - Constness is shallow: a const Expectation object itself cannot +// be modified, but the mutable methods of the ExpectationBase +// object it references can be called via expectation_base(). +class Expectation { + public: + // Constructs a null object that doesn't reference any expectation. + Expectation() {} + + // This single-argument ctor must not be explicit, in order to support the + // Expectation e = EXPECT_CALL(...); + // syntax. + // + // A TypedExpectation object stores its pre-requisites as + // Expectation objects, and needs to call the non-const Retire() + // method on the ExpectationBase objects they reference. Therefore + // Expectation must receive a *non-const* reference to the + // ExpectationBase object. + Expectation(internal::ExpectationBase& exp); // NOLINT + + // The compiler-generated copy ctor and operator= work exactly as + // intended, so we don't need to define our own. + + // Returns true iff rhs references the same expectation as this object does. + bool operator==(const Expectation& rhs) const { + return expectation_base_ == rhs.expectation_base_; + } + + bool operator!=(const Expectation& rhs) const { return !(*this == rhs); } + + private: + friend class ExpectationSet; + friend class Sequence; + friend class ::testing::internal::ExpectationBase; + + template + friend class ::testing::internal::FunctionMockerBase; + + template + friend class ::testing::internal::TypedExpectation; + + // This comparator is needed for putting Expectation objects into a set. + class Less { + public: + bool operator()(const Expectation& lhs, const Expectation& rhs) const { + return lhs.expectation_base_.get() < rhs.expectation_base_.get(); + } + }; + + typedef ::std::set Set; + + Expectation( + const internal::linked_ptr& expectation_base) : + expectation_base_(expectation_base) {} + + // Returns the expectation this object references. + const internal::linked_ptr& + expectation_base() const { + return expectation_base_; + } + + // A linked_ptr that co-owns the expectation this handle references. + internal::linked_ptr expectation_base_; +}; + +// A set of expectation handles. Useful in the .After() clause of +// EXPECT_CALL() for setting the (partial) order of expectations. The +// syntax: +// +// ExpectationSet es; +// es += EXPECT_CALL(...)...; +// es += EXPECT_CALL(...)...; +// EXPECT_CALL(...).After(es)...; +// +// sets three expectations where the last one can only be matched +// after the first two have both been satisfied. +// +// This class is copyable and has value semantics. +class ExpectationSet { + public: + // A bidirectional iterator that can read a const element in the set. + typedef Expectation::Set::const_iterator const_iterator; + + // An object stored in the set. This is an alias of Expectation. + typedef Expectation::Set::value_type value_type; + + // Constructs an empty set. + ExpectationSet() {} + + // This single-argument ctor must not be explicit, in order to support the + // ExpectationSet es = EXPECT_CALL(...); + // syntax. + ExpectationSet(internal::ExpectationBase& exp) { // NOLINT + *this += Expectation(exp); + } + + // This single-argument ctor implements implicit conversion from + // Expectation and thus must not be explicit. This allows either an + // Expectation or an ExpectationSet to be used in .After(). + ExpectationSet(const Expectation& e) { // NOLINT + *this += e; + } + + // The compiler-generator ctor and operator= works exactly as + // intended, so we don't need to define our own. + + // Returns true iff rhs contains the same set of Expectation objects + // as this does. + bool operator==(const ExpectationSet& rhs) const { + return expectations_ == rhs.expectations_; + } + + bool operator!=(const ExpectationSet& rhs) const { return !(*this == rhs); } + + // Implements the syntax + // expectation_set += EXPECT_CALL(...); + ExpectationSet& operator+=(const Expectation& e) { + expectations_.insert(e); + return *this; + } + + int size() const { return static_cast(expectations_.size()); } + + const_iterator begin() const { return expectations_.begin(); } + const_iterator end() const { return expectations_.end(); } + + private: + Expectation::Set expectations_; +}; + + // Sequence objects are used by a user to specify the relative order // in which the expectations should match. They are copyable (we rely // on the compiler-defined copy constructor and assignment operator). class Sequence { public: // Constructs an empty sequence. - Sequence() - : last_expectation_( - new internal::linked_ptr(NULL)) {} + Sequence() : last_expectation_(new Expectation) {} // Adds an expectation to this sequence. The caller must ensure // that no other thread is accessing this Sequence object. - void AddExpectation( - const internal::linked_ptr& expectation) const; + void AddExpectation(const Expectation& expectation) const; + private: - // The last expectation in this sequence. We use a nested - // linked_ptr here because: - // - Sequence objects are copyable, and we want the copies to act - // as aliases. The outer linked_ptr allows the copies to co-own - // and share the same state. - // - An Expectation object is co-owned (via linked_ptr) by its - // FunctionMocker and its successors (other Expectation objects). - // Hence the inner linked_ptr. - internal::linked_ptr > - last_expectation_; + // The last expectation in this sequence. We use a linked_ptr here + // because Sequence objects are copyable and we want the copies to + // be aliases. The linked_ptr allows the copies to co-own and share + // the same Expectation object. + internal::linked_ptr last_expectation_; }; // class Sequence // An object of this type causes all EXPECT_CALL() statements @@ -431,9 +575,7 @@ class ExpectationBase { // L >= g_gmock_mutex virtual void DescribeCallCountTo(::std::ostream* os) const = 0; protected: - typedef std::set, - LinkedPtrLessThan > - ExpectationBaseSet; + friend class ::testing::Expectation; enum Clause { // Don't change the order of the enum members! @@ -441,11 +583,16 @@ class ExpectationBase { kWith, kTimes, kInSequence, + kAfter, kWillOnce, kWillRepeatedly, kRetiresOnSaturation, }; + // Returns an Expectation object that references and co-owns this + // expectation. + virtual Expectation GetHandle() = 0; + // Asserts that the EXPECT_CALL() statement has the given property. void AssertSpecProperty(bool property, const string& failure_message) const { Assert(property, file_, line_, failure_message); @@ -518,7 +665,7 @@ class ExpectationBase { // Adds unsatisfied pre-requisites of this expectation to 'result'. // L >= g_gmock_mutex - void FindUnsatisfiedPrerequisites(ExpectationBaseSet* result) const; + void FindUnsatisfiedPrerequisites(ExpectationSet* result) const; // Returns the number this expectation has been invoked. // L >= g_gmock_mutex @@ -539,7 +686,7 @@ class ExpectationBase { friend class ::testing::internal::ExpectationTester; template - friend class Expectation; + friend class TypedExpectation; // This group of fields are part of the spec and won't change after // an EXPECT_CALL() statement finishes. @@ -548,11 +695,13 @@ class ExpectationBase { // True iff the cardinality is specified explicitly. bool cardinality_specified_; Cardinality cardinality_; // The cardinality of the expectation. - // The immediate pre-requisites of this expectation. We use - // linked_ptr in the set because we want an Expectation object to be - // co-owned by its FunctionMocker and its successors. This allows - // multiple mock objects to be deleted at different times. - ExpectationBaseSet immediate_prerequisites_; + // The immediate pre-requisites (i.e. expectations that must be + // satisfied before this expectation can be matched) of this + // expectation. We use linked_ptr in the set because we want an + // Expectation object to be co-owned by its FunctionMocker and its + // successors. This allows multiple mock objects to be deleted at + // different times. + ExpectationSet immediate_prerequisites_; // This group of fields are the current state of the expectation, // and can change as the mock function is called. @@ -562,14 +711,14 @@ class ExpectationBase { // Impements an expectation for the given function type. template -class Expectation : public ExpectationBase { +class TypedExpectation : public ExpectationBase { public: typedef typename Function::ArgumentTuple ArgumentTuple; typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; typedef typename Function::Result Result; - Expectation(FunctionMockerBase* owner, const char* file, int line, - const ArgumentMatcherTuple& m) + TypedExpectation(FunctionMockerBase* owner, const char* file, int line, + const ArgumentMatcherTuple& m) : ExpectationBase(file, line), owner_(owner), matchers_(m), @@ -584,14 +733,14 @@ class Expectation : public ExpectationBase { last_clause_(kNone), action_count_checked_(false) {} - virtual ~Expectation() { + virtual ~TypedExpectation() { // Check the validity of the action count if it hasn't been done // yet (for example, if the expectation was never used). CheckActionCountIfNotDone(); } // Implements the .With() clause. - Expectation& With(const Matcher& m) { + TypedExpectation& With(const Matcher& m) { if (last_clause_ == kWith) { ExpectSpecProperty(false, ".With() cannot appear " @@ -608,7 +757,7 @@ class Expectation : public ExpectationBase { } // Implements the .Times() clause. - Expectation& Times(const Cardinality& cardinality) { + TypedExpectation& Times(const Cardinality& cardinality) { if (last_clause_ ==kTimes) { ExpectSpecProperty(false, ".Times() cannot appear " @@ -626,40 +775,70 @@ class Expectation : public ExpectationBase { } // Implements the .Times() clause. - Expectation& Times(int n) { + TypedExpectation& Times(int n) { return Times(Exactly(n)); } // Implements the .InSequence() clause. - Expectation& InSequence(const Sequence& s) { + TypedExpectation& InSequence(const Sequence& s) { ExpectSpecProperty(last_clause_ <= kInSequence, - ".InSequence() cannot appear after .WillOnce()," - " .WillRepeatedly(), or " + ".InSequence() cannot appear after .After()," + " .WillOnce(), .WillRepeatedly(), or " ".RetiresOnSaturation()."); last_clause_ = kInSequence; - s.AddExpectation(owner_->GetLinkedExpectationBase(this)); + s.AddExpectation(GetHandle()); return *this; } - Expectation& InSequence(const Sequence& s1, const Sequence& s2) { + TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2) { return InSequence(s1).InSequence(s2); } - Expectation& InSequence(const Sequence& s1, const Sequence& s2, - const Sequence& s3) { + TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2, + const Sequence& s3) { return InSequence(s1, s2).InSequence(s3); } - Expectation& InSequence(const Sequence& s1, const Sequence& s2, - const Sequence& s3, const Sequence& s4) { + TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2, + const Sequence& s3, const Sequence& s4) { return InSequence(s1, s2, s3).InSequence(s4); } - Expectation& InSequence(const Sequence& s1, const Sequence& s2, - const Sequence& s3, const Sequence& s4, - const Sequence& s5) { + TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2, + const Sequence& s3, const Sequence& s4, + const Sequence& s5) { return InSequence(s1, s2, s3, s4).InSequence(s5); } + // Implements that .After() clause. + TypedExpectation& After(const ExpectationSet& s) { + ExpectSpecProperty(last_clause_ <= kAfter, + ".After() cannot appear after .WillOnce()," + " .WillRepeatedly(), or " + ".RetiresOnSaturation()."); + last_clause_ = kAfter; + + for (ExpectationSet::const_iterator it = s.begin(); it != s.end(); ++it) { + immediate_prerequisites_ += *it; + } + return *this; + } + TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2) { + return After(s1).After(s2); + } + TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2, + const ExpectationSet& s3) { + return After(s1, s2).After(s3); + } + TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2, + const ExpectationSet& s3, const ExpectationSet& s4) { + return After(s1, s2, s3).After(s4); + } + TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2, + const ExpectationSet& s3, const ExpectationSet& s4, + const ExpectationSet& s5) { + return After(s1, s2, s3, s4).After(s5); + } + // Implements the .WillOnce() clause. - Expectation& WillOnce(const Action& action) { + TypedExpectation& WillOnce(const Action& action) { ExpectSpecProperty(last_clause_ <= kWillOnce, ".WillOnce() cannot appear after " ".WillRepeatedly() or .RetiresOnSaturation()."); @@ -673,7 +852,7 @@ class Expectation : public ExpectationBase { } // Implements the .WillRepeatedly() clause. - Expectation& WillRepeatedly(const Action& action) { + TypedExpectation& WillRepeatedly(const Action& action) { if (last_clause_ == kWillRepeatedly) { ExpectSpecProperty(false, ".WillRepeatedly() cannot appear " @@ -698,7 +877,7 @@ class Expectation : public ExpectationBase { } // Implements the .RetiresOnSaturation() clause. - Expectation& RetiresOnSaturation() { + TypedExpectation& RetiresOnSaturation() { ExpectSpecProperty(last_clause_ < kRetiresOnSaturation, ".RetiresOnSaturation() cannot appear " "more than once."); @@ -756,6 +935,12 @@ class Expectation : public ExpectationBase { template friend class FunctionMockerBase; + // Returns an Expectation object that references and co-owns this + // expectation. + virtual Expectation GetHandle() { + return owner_->GetHandleOf(this); + } + // The following methods will be called only after the EXPECT_CALL() // statement finishes and when the current thread holds // g_gmock_mutex. @@ -807,12 +992,12 @@ class Expectation : public ExpectationBase { *os << " Expected: all pre-requisites are satisfied\n" << " Actual: the following immediate pre-requisites " << "are not satisfied:\n"; - ExpectationBaseSet unsatisfied_prereqs; + ExpectationSet unsatisfied_prereqs; FindUnsatisfiedPrerequisites(&unsatisfied_prereqs); int i = 0; - for (ExpectationBaseSet::const_iterator it = unsatisfied_prereqs.begin(); + for (ExpectationSet::const_iterator it = unsatisfied_prereqs.begin(); it != unsatisfied_prereqs.end(); ++it) { - (*it)->DescribeLocationTo(os); + it->expectation_base()->DescribeLocationTo(os); *os << "pre-requisite #" << i++ << "\n"; } *os << " (end of pre-requisites)\n"; @@ -957,7 +1142,7 @@ class Expectation : public ExpectationBase { Clause last_clause_; mutable bool action_count_checked_; // Under mutex_. mutable Mutex mutex_; // Protects action_count_checked_. -}; // class Expectation +}; // class TypedExpectation // A MockSpec object is used by ON_CALL() or EXPECT_CALL() for // specifying the default behavior of, or expectation on, a mock @@ -992,7 +1177,7 @@ class MockSpec { // Adds a new expectation spec to the function mocker and returns // the newly created spec. - internal::Expectation& InternalExpectedAt( + internal::TypedExpectation& InternalExpectedAt( const char* file, int line, const char* obj, const char* call) { LogWithLocation(internal::INFO, file, line, string("EXPECT_CALL(") + obj + ", " + call + ") invoked"); @@ -1247,18 +1432,18 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Adds and returns an expectation spec for this mock function. // L < g_gmock_mutex - Expectation& AddNewExpectation( + TypedExpectation& AddNewExpectation( const char* file, int line, const ArgumentMatcherTuple& m) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); - const linked_ptr > expectation( - new Expectation(this, file, line, m)); + const linked_ptr > expectation( + new TypedExpectation(this, file, line, m)); expectations_.push_back(expectation); // Adds this expectation into the implicit sequence if there is one. Sequence* const implicit_sequence = g_gmock_implicit_sequence.get(); if (implicit_sequence != NULL) { - implicit_sequence->AddExpectation(expectation); + implicit_sequence->AddExpectation(Expectation(expectation)); } return *expectation; @@ -1268,22 +1453,23 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // being described on this function mocker. MockSpec& current_spec() { return current_spec_; } private: - template friend class Expectation; + template friend class TypedExpectation; - typedef std::vector > > Expectations; + typedef std::vector > > + TypedExpectations; - // Gets the internal::linked_ptr object that co-owns 'exp'. - internal::linked_ptr GetLinkedExpectationBase( - Expectation* exp) { - for (typename Expectations::const_iterator it = expectations_.begin(); + // Returns an Expectation object that references and co-owns exp, + // which must be an expectation on this mock function. + Expectation GetHandleOf(TypedExpectation* exp) { + for (typename TypedExpectations::const_iterator it = expectations_.begin(); it != expectations_.end(); ++it) { if (it->get() == exp) { - return *it; + return Expectation(*it); } } Assert(false, __FILE__, __LINE__, "Cannot find expectation."); - return internal::linked_ptr(NULL); + return Expectation(); // The above statement is just to make the code compile, and will // never be executed. } @@ -1330,7 +1516,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // mock function) and excessive locking could cause a dead lock. // L < g_gmock_mutex bool FindMatchingExpectationAndAction( - const ArgumentTuple& args, Expectation** exp, Action* action, + const ArgumentTuple& args, TypedExpectation** exp, Action* action, bool* is_excessive, ::std::ostream* what, ::std::ostream* why) { MutexLock l(&g_gmock_mutex); *exp = this->FindMatchingExpectationLocked(args); @@ -1351,13 +1537,13 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Returns the expectation that matches the arguments, or NULL if no // expectation matches them. // L >= g_gmock_mutex - Expectation* FindMatchingExpectationLocked( + TypedExpectation* FindMatchingExpectationLocked( const ArgumentTuple& args) const { g_gmock_mutex.AssertHeld(); - for (typename Expectations::const_reverse_iterator it = + for (typename TypedExpectations::const_reverse_iterator it = expectations_.rbegin(); it != expectations_.rend(); ++it) { - Expectation* const exp = it->get(); + TypedExpectation* const exp = it->get(); if (exp->ShouldHandleArguments(args)) { return exp; } @@ -1415,7 +1601,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // All default action specs for this function mocker. std::vector > default_actions_; // All expectations for this function mocker. - Expectations expectations_; + TypedExpectations expectations_; // There is no generally useful and implementable semantics of // copying a mock object, so copying a mock is usually a user error. @@ -1446,9 +1632,9 @@ template bool FunctionMockerBase::VerifyAndClearExpectationsLocked() { g_gmock_mutex.AssertHeld(); bool expectations_met = true; - for (typename Expectations::const_iterator it = expectations_.begin(); + for (typename TypedExpectations::const_iterator it = expectations_.begin(); it != expectations_.end(); ++it) { - Expectation* const exp = it->get(); + TypedExpectation* const exp = it->get(); if (exp->IsOverSaturated()) { // There was an upper-bound violation. Since the error was @@ -1532,7 +1718,7 @@ typename Function::Result FunctionMockerBase::InvokeWith( ::std::stringstream why; ::std::stringstream loc; Action action; - Expectation* exp; + TypedExpectation* exp; // The FindMatchingExpectationAndAction() function acquires and // releases g_gmock_mutex. @@ -1605,6 +1791,10 @@ using internal::MockSpec; template inline const T& Const(const T& x) { return x; } +// Constructs an Expectation object that references and co-owns exp. +inline Expectation::Expectation(internal::ExpectationBase& exp) // NOLINT + : expectation_base_(exp.GetHandle().expectation_base()) {} + } // namespace testing // A separate macro is required to avoid compile errors when the name diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 465e4d63..00d16918 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -82,11 +82,9 @@ void ExpectationBase::RetireAllPreRequisites() { return; } - for (ExpectationBaseSet::const_iterator it = - immediate_prerequisites_.begin(); - it != immediate_prerequisites_.end(); - ++it) { - ExpectationBase* const prerequisite = (*it).get(); + for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin(); + it != immediate_prerequisites_.end(); ++it) { + ExpectationBase* const prerequisite = it->expectation_base().get(); if (!prerequisite->is_retired()) { prerequisite->RetireAllPreRequisites(); prerequisite->Retire(); @@ -99,10 +97,10 @@ void ExpectationBase::RetireAllPreRequisites() { // L >= g_gmock_mutex bool ExpectationBase::AllPrerequisitesAreSatisfied() const { g_gmock_mutex.AssertHeld(); - for (ExpectationBaseSet::const_iterator it = immediate_prerequisites_.begin(); + for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin(); it != immediate_prerequisites_.end(); ++it) { - if (!(*it)->IsSatisfied() || - !(*it)->AllPrerequisitesAreSatisfied()) + if (!(it->expectation_base()->IsSatisfied()) || + !(it->expectation_base()->AllPrerequisitesAreSatisfied())) return false; } return true; @@ -111,21 +109,21 @@ bool ExpectationBase::AllPrerequisitesAreSatisfied() const { // Adds unsatisfied pre-requisites of this expectation to 'result'. // L >= g_gmock_mutex void ExpectationBase::FindUnsatisfiedPrerequisites( - ExpectationBaseSet* result) const { + ExpectationSet* result) const { g_gmock_mutex.AssertHeld(); - for (ExpectationBaseSet::const_iterator it = immediate_prerequisites_.begin(); + for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin(); it != immediate_prerequisites_.end(); ++it) { - if ((*it)->IsSatisfied()) { + if (it->expectation_base()->IsSatisfied()) { // If *it is satisfied and has a call count of 0, some of its // pre-requisites may not be satisfied yet. - if ((*it)->call_count_ == 0) { - (*it)->FindUnsatisfiedPrerequisites(result); + if (it->expectation_base()->call_count_ == 0) { + it->expectation_base()->FindUnsatisfiedPrerequisites(result); } } else { // Now that we know *it is unsatisfied, we are not so interested // in whether its pre-requisites are satisfied. Therefore we // don't recursively call FindUnsatisfiedPrerequisites() here. - result->insert(*it); + *result += *it; } } } @@ -421,11 +419,11 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj) { } // Adds an expectation to a sequence. -void Sequence::AddExpectation( - const internal::linked_ptr& expectation) const { +void Sequence::AddExpectation(const Expectation& expectation) const { if (*last_expectation_ != expectation) { - if (*last_expectation_ != NULL) { - expectation->immediate_prerequisites_.insert(*last_expectation_); + if (last_expectation_->expectation_base() != NULL) { + expectation.expectation_base()->immediate_prerequisites_ + += *last_expectation_; } *last_expectation_ = expectation; } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 614e4ab5..f6c3141b 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -71,6 +71,9 @@ using testing::CardinalityInterface; using testing::Const; using testing::DoAll; using testing::DoDefault; +using testing::Eq; +using testing::Expectation; +using testing::ExpectationSet; using testing::GMOCK_FLAG(verbose); using testing::Gt; using testing::InSequence; @@ -80,13 +83,13 @@ using testing::IsSubstring; using testing::Lt; using testing::Message; using testing::Mock; +using testing::Ne; using testing::Return; using testing::Sequence; using testing::internal::g_gmock_mutex; using testing::internal::kErrorVerbosity; using testing::internal::kInfoVerbosity; using testing::internal::kWarningVerbosity; -using testing::internal::Expectation; using testing::internal::ExpectationTester; using testing::internal::string; @@ -345,7 +348,22 @@ TEST(ExpectCallSyntaxTest, InSequenceCanAppearMultipleTimes) { a.DoA(1); } -TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWill) { +TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeAfter) { + MockA a; + Sequence s; + + Expectation e = EXPECT_CALL(a, DoA(1)) + .Times(AnyNumber()); + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_CALL(a, DoA(2)) + .After(e) + .InSequence(s); + }, ".InSequence() cannot appear after "); + + a.DoA(2); +} + +TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWillOnce) { MockA a; Sequence s; @@ -358,6 +376,20 @@ TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWill) { a.DoA(1); } +TEST(ExpectCallSyntaxTest, AfterMustBeBeforeWillOnce) { + MockA a; + + Expectation e = EXPECT_CALL(a, DoA(1)); + EXPECT_NONFATAL_FAILURE({ + EXPECT_CALL(a, DoA(2)) + .WillOnce(Return()) + .After(e); + }, ".After() cannot appear after "); + + a.DoA(1); + a.DoA(2); +} + TEST(ExpectCallSyntaxTest, WillIsOptional) { MockA a; @@ -1248,6 +1280,292 @@ TEST(SequenceTest, Retirement) { a.DoA(1); } +// Tests Expectation. + +TEST(ExpectationTest, ConstrutorsWork) { + MockA a; + Expectation e1; // Default ctor. + Expectation e2 = EXPECT_CALL(a, DoA(1)); // Ctor from EXPECT_CALL. + Expectation e3 = e2; // Copy ctor. + + EXPECT_THAT(e1, Ne(e2)); + EXPECT_THAT(e2, Eq(e3)); + a.DoA(1); +} + +TEST(ExpectationTest, AssignmentWorks) { + MockA a; + Expectation e1; + Expectation e2 = EXPECT_CALL(a, DoA(1)); + + EXPECT_THAT(e1, Ne(e2)); + + e1 = e2; + EXPECT_THAT(e1, Eq(e2)); + + a.DoA(1); +} + +// Tests ExpectationSet. + +TEST(ExpectationSetTest, MemberTypesAreCorrect) { + ::testing::StaticAssertTypeEq(); +} + +TEST(ExpectationSetTest, ConstructorsWork) { + MockA a; + + Expectation e1; + const Expectation e2; + ExpectationSet es1; // Default ctor. + ExpectationSet es2 = EXPECT_CALL(a, DoA(1)); // Ctor from EXPECT_CALL. + ExpectationSet es3 = e1; // Ctor from Expectation. + ExpectationSet es4(e1); // Ctor from Expectation; alternative syntax. + ExpectationSet es5 = e2; // Ctor from const Expectation. + ExpectationSet es6(e2); // Ctor from const Expectation; alternative syntax. + ExpectationSet es7 = es2; // Copy ctor. + + EXPECT_EQ(0, es1.size()); + EXPECT_EQ(1, es2.size()); + EXPECT_EQ(1, es3.size()); + EXPECT_EQ(1, es4.size()); + EXPECT_EQ(1, es5.size()); + EXPECT_EQ(1, es6.size()); + EXPECT_EQ(1, es7.size()); + + EXPECT_THAT(es3, Ne(es2)); + EXPECT_THAT(es4, Eq(es3)); + EXPECT_THAT(es5, Eq(es4)); + EXPECT_THAT(es6, Eq(es5)); + EXPECT_THAT(es7, Eq(es2)); + a.DoA(1); +} + +TEST(ExpectationSetTest, AssignmentWorks) { + ExpectationSet es1; + ExpectationSet es2 = Expectation(); + + es1 = es2; + EXPECT_EQ(1, es1.size()); + EXPECT_THAT(*(es1.begin()), Eq(Expectation())); + EXPECT_THAT(es1, Eq(es2)); +} + +TEST(ExpectationSetTest, InsertionWorks) { + ExpectationSet es1; + Expectation e1; + es1 += e1; + EXPECT_EQ(1, es1.size()); + EXPECT_THAT(*(es1.begin()), Eq(e1)); + + MockA a; + Expectation e2 = EXPECT_CALL(a, DoA(1)); + es1 += e2; + EXPECT_EQ(2, es1.size()); + + ExpectationSet::const_iterator it1 = es1.begin(); + ExpectationSet::const_iterator it2 = it1; + ++it2; + EXPECT_TRUE(*it1 == e1 || *it2 == e1); // e1 must be in the set. + EXPECT_TRUE(*it1 == e2 || *it2 == e2); // e2 must be in the set too. + a.DoA(1); +} + +TEST(ExpectationSetTest, SizeWorks) { + ExpectationSet es; + EXPECT_EQ(0, es.size()); + + es += Expectation(); + EXPECT_EQ(1, es.size()); + + MockA a; + es += EXPECT_CALL(a, DoA(1)); + EXPECT_EQ(2, es.size()); + + a.DoA(1); +} + +TEST(ExpectationSetTest, IsEnumerable) { + ExpectationSet es; + EXPECT_THAT(es.begin(), Eq(es.end())); + + es += Expectation(); + ExpectationSet::const_iterator it = es.begin(); + EXPECT_THAT(it, Ne(es.end())); + EXPECT_THAT(*it, Eq(Expectation())); + ++it; + EXPECT_THAT(it, Eq(es.end())); +} + +// Tests the .After() clause. + +TEST(AfterTest, SucceedsWhenPartialOrderIsSatisfied) { + MockA a; + ExpectationSet es; + es += EXPECT_CALL(a, DoA(1)); + es += EXPECT_CALL(a, DoA(2)); + EXPECT_CALL(a, DoA(3)) + .After(es); + + a.DoA(1); + a.DoA(2); + a.DoA(3); +} + +TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) { + MockA a; + MockB b; + // The following also verifies that const Expectation objects work + // too. Do not remove the const modifiers. + const Expectation e1 = EXPECT_CALL(a, DoA(1)); + const Expectation e2 = EXPECT_CALL(b, DoB()) + .Times(2) + .After(e1); + EXPECT_CALL(a, DoA(2)).After(e2); + + a.DoA(1); + b.DoB(); + b.DoB(); + a.DoA(2); +} + +// Calls must be in strict order when specified so. +TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { + MockA a; + MockB b; + Expectation e1 = EXPECT_CALL(a, DoA(1)); + Expectation e2 = EXPECT_CALL(b, DoB()) + .Times(2) + .After(e1); + EXPECT_CALL(a, ReturnResult(2)) + .After(e2) + .WillOnce(Return(Result())); + + a.DoA(1); + // If a call to ReturnResult() violates the specified order, no + // matching expectation will be found, and thus the default action + // will be done. Since the return type of ReturnResult() is not a + // built-in type, gmock won't know what to return and will thus + // abort the program. Therefore a death test can tell us whether + // gmock catches the order violation correctly. + // + // gtest and gmock print messages to stdout, which isn't captured by + // death tests. Therefore we have to match with an empty regular + // expression in all the EXPECT_DEATH()s. + EXPECT_DEATH(a.ReturnResult(2), ""); + + b.DoB(); + EXPECT_DEATH(a.ReturnResult(2), ""); + + b.DoB(); + a.ReturnResult(2); +} + +// Calls must satisfy the partial order when specified so. +TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { + MockA a; + Expectation e = EXPECT_CALL(a, DoA(1)); + const ExpectationSet es = EXPECT_CALL(a, DoA(2)); + EXPECT_CALL(a, ReturnResult(3)) + .After(e, es) + .WillOnce(Return(Result())); + + EXPECT_DEATH(a.ReturnResult(3), ""); + + a.DoA(2); + EXPECT_DEATH(a.ReturnResult(3), ""); + + a.DoA(1); + a.ReturnResult(3); +} + +// .After() can be combined with .InSequence(). +TEST(AfterTest, CanBeUsedWithInSequence) { + MockA a; + Sequence s; + Expectation e = EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(2)).InSequence(s); + EXPECT_CALL(a, ReturnResult(3)) + .InSequence(s).After(e) + .WillOnce(Return(Result())); + + a.DoA(1); + EXPECT_DEATH(a.ReturnResult(3), ""); + + a.DoA(2); + a.ReturnResult(3); +} + +// .After() can be called multiple times. +TEST(AfterTest, CanBeCalledManyTimes) { + MockA a; + Expectation e1 = EXPECT_CALL(a, DoA(1)); + Expectation e2 = EXPECT_CALL(a, DoA(2)); + Expectation e3 = EXPECT_CALL(a, DoA(3)); + EXPECT_CALL(a, DoA(4)) + .After(e1) + .After(e2) + .After(e3); + + a.DoA(3); + a.DoA(1); + a.DoA(2); + a.DoA(4); +} + +// .After() accepts up to 5 arguments. +TEST(AfterTest, AcceptsUpToFiveArguments) { + MockA a; + Expectation e1 = EXPECT_CALL(a, DoA(1)); + Expectation e2 = EXPECT_CALL(a, DoA(2)); + Expectation e3 = EXPECT_CALL(a, DoA(3)); + ExpectationSet es1 = EXPECT_CALL(a, DoA(4)); + ExpectationSet es2 = EXPECT_CALL(a, DoA(5)); + EXPECT_CALL(a, DoA(6)) + .After(e1, e2, e3, es1, es2); + + a.DoA(5); + a.DoA(2); + a.DoA(4); + a.DoA(1); + a.DoA(3); + a.DoA(6); +} + +// .After() allows input to contain duplicated Expectations. +TEST(AfterTest, AcceptsDuplicatedInput) { + MockA a; + Expectation e1 = EXPECT_CALL(a, DoA(1)); + Expectation e2 = EXPECT_CALL(a, DoA(2)); + ExpectationSet es; + es += e1; + es += e2; + EXPECT_CALL(a, ReturnResult(3)) + .After(e1, e2, es, e1) + .WillOnce(Return(Result())); + + a.DoA(1); + EXPECT_DEATH(a.ReturnResult(3), ""); + + a.DoA(2); + a.ReturnResult(3); +} + +// An Expectation added to an ExpectationSet after it has been used in +// an .After() has no effect. +TEST(AfterTest, ChangesToExpectationSetHaveNoEffectAfterwards) { + MockA a; + ExpectationSet es1 = EXPECT_CALL(a, DoA(1)); + Expectation e2 = EXPECT_CALL(a, DoA(2)); + EXPECT_CALL(a, DoA(3)) + .After(es1); + es1 += e2; + + a.DoA(1); + a.DoA(3); + a.DoA(2); +} + // Tests that Google Mock correctly handles calls to mock functions // after a mock object owning one of their pre-requisites has died. -- cgit v1.2.3 From b5937dab6969ca4b1d8304cc8939ce16c1fb62e5 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 16 Jul 2009 20:26:41 +0000 Subject: Adds the Key() matcher, by Marcus Borger. --- include/gmock/gmock-matchers.h | 66 ++++++++++++++++++++++++++++++++++++++++++ test/gmock-matchers_test.cc | 49 +++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 4696f704..db23a1bd 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1867,6 +1867,64 @@ class ContainsMatcher { const M inner_matcher_; }; +// Implements Key(inner_matcher) for the given argument pair type. +// Key(inner_matcher) matches an std::pair whose 'first' field matches +// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an +// std::map that contains at least one element whose key is >= 5. +template +class KeyMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef typename RawPairType::first_type KeyType; + + template + explicit KeyMatcherImpl(InnerMatcher inner_matcher) + : inner_matcher_( + testing::SafeMatcherCast(inner_matcher)) { + } + + // Returns true iff 'key_value.first' (the key) matches the inner matcher. + virtual bool Matches(PairType key_value) const { + return inner_matcher_.Matches(key_value.first); + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "has a key that "; + inner_matcher_.DescribeTo(os); + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't have a key that "; + inner_matcher_.DescribeTo(os); + } + + // Explains why 'key_value' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(PairType key_value, + ::std::ostream* os) const { + inner_matcher_.ExplainMatchResultTo(key_value.first, os); + } + + private: + const Matcher inner_matcher_; +}; + +// Implements polymorphic Key(matcher_for_key). +template +class KeyMatcher { + public: + explicit KeyMatcher(M m) : matcher_for_key_(m) {} + + template + operator Matcher() const { + return MakeMatcher(new KeyMatcherImpl(matcher_for_key_)); + } + + private: + const M matcher_for_key_; +}; + } // namespace internal // Implements MatcherCast(). @@ -2342,6 +2400,14 @@ inline internal::ContainsMatcher Contains(M matcher) { return internal::ContainsMatcher(matcher); } +// Key(inner_matcher) matches an std::pair whose 'first' field matches +// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an +// std::map that contains at least one element whose key is >= 5. +template +inline internal::KeyMatcher Key(M inner_matcher) { + return internal::KeyMatcher(inner_matcher); +} + // Returns a predicate that is satisfied by anything that matches the // given matcher. template diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 3541eef7..052202d7 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -59,6 +59,8 @@ bool SkipPrefix(const char* prefix, const char** pstr); namespace gmock_matchers_test { +using std::map; +using std::multimap; using std::stringstream; using std::tr1::make_tuple; using testing::A; @@ -75,6 +77,7 @@ using testing::FloatEq; using testing::Ge; using testing::Gt; using testing::HasSubstr; +using testing::Key; using testing::Le; using testing::Lt; using testing::MakeMatcher; @@ -850,6 +853,52 @@ TEST(HasSubstrTest, CanDescribeSelf) { EXPECT_EQ("has substring \"foo\\n\\\"\"", Describe(m)); } +TEST(KeyTest, CanDescribeSelf) { + Matcher&> m = Key("foo"); + EXPECT_EQ("has a key that is equal to \"foo\"", Describe(m)); +} + +TEST(KeyTest, MatchesCorrectly) { + std::pair p(25, "foo"); + EXPECT_THAT(p, Key(25)); + EXPECT_THAT(p, Not(Key(42))); + EXPECT_THAT(p, Key(Ge(20))); + EXPECT_THAT(p, Not(Key(Lt(25)))); +} + +TEST(KeyTest, SafelyCastsInnerMatcher) { + Matcher is_positive = Gt(0); + Matcher is_negative = Lt(0); + std::pair p('a', true); + EXPECT_THAT(p, Key(is_positive)); + EXPECT_THAT(p, Not(Key(is_negative))); +} + +TEST(KeyTest, InsideContainsUsingMap) { + std::map container; + container.insert(std::make_pair(1, "foo")); + container.insert(std::make_pair(2, "bar")); + container.insert(std::make_pair(4, "baz")); + EXPECT_THAT(container, Contains(Key(1))); + EXPECT_THAT(container, Not(Contains(Key(3)))); +} + +TEST(KeyTest, InsideContainsUsingMultimap) { + std::multimap container; + container.insert(std::make_pair(1, "foo")); + container.insert(std::make_pair(2, "bar")); + container.insert(std::make_pair(4, "baz")); + + EXPECT_THAT(container, Not(Contains(Key(25)))); + container.insert(std::make_pair(25, "more foo")); + EXPECT_THAT(container, Contains(Key(25))); + container.insert(std::make_pair(25, "more bar")); + EXPECT_THAT(container, Contains(Key(25))); + + EXPECT_THAT(container, Contains(Key(1))); + EXPECT_THAT(container, Not(Contains(Key(3)))); +} + // Tests StartsWith(s). TEST(StartsWithTest, MatchesStringWithGivenPrefix) { -- cgit v1.2.3 From 387bdd551d4a88383246841ac3f70324b8d42772 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 20 Jul 2009 21:16:35 +0000 Subject: Makes ByRef(x) printable as a reference to x. --- include/gmock/gmock-generated-actions.h | 11 +++++++++++ include/gmock/gmock-generated-actions.h.pump | 11 +++++++++++ scripts/gmock_doctor.py | 1 - test/gmock-generated-actions_test.cc | 10 ++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index fa02faaa..c0097175 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -39,6 +39,7 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #include +#include #include namespace testing { @@ -321,6 +322,9 @@ class InvokeMethodAction { const MethodPtr method_ptr_; }; +// TODO(wan@google.com): ReferenceWrapper and ByRef() are neither +// action-specific nor variadic. Move them to a better place. + // 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, @@ -341,6 +345,13 @@ class ReferenceWrapper { 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); +} + // CallableHelper has static methods for invoking "callables", // i.e. function pointers and functors. It uses overloading to // provide a uniform interface for invoking different kinds of diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index b5223a34..2a7e4ffd 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -43,6 +43,7 @@ $$}} This meta comment fixes auto-indentation in editors. #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #include +#include #include namespace testing { @@ -123,6 +124,9 @@ class InvokeMethodAction { const MethodPtr method_ptr_; }; +// TODO(wan@google.com): ReferenceWrapper and ByRef() are neither +// action-specific nor variadic. Move them to a better place. + // 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, @@ -143,6 +147,13 @@ class ReferenceWrapper { 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); +} + // CallableHelper has static methods for invoking "callables", // i.e. function pointers and functors. It uses overloading to // provide a uniform interface for invoking different kinds of diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 05e42585..7b45fa17 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -71,7 +71,6 @@ _COMMON_GMOCK_SYMBOLS = [ 'Not', 'NotNull', 'Pointee', - 'PointeeIsInitializedProto', 'Property', 'Ref', 'ResultOf', diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index d0b2ddc9..cf3c7891 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -546,6 +547,15 @@ TEST(ByRefTest, ExplicitType) { // ByRef(b); } +// Tests that Google Mock prints expression ByRef(x) as a reference to x. +TEST(ByRefTest, PrintsCorrectly) { + int n = 42; + ::std::stringstream expected, actual; + testing::internal::UniversalPrinter::Print(n, &expected); + testing::internal::UniversalPrint(ByRef(n), &actual); + EXPECT_EQ(expected.str(), actual.str()); +} + // Tests InvokeArgument(...). // Tests using InvokeArgument with a nullary function. -- cgit v1.2.3 From 1afe1c7971e649ae8b85a39fc1ab6ac595e1dd58 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 21 Jul 2009 23:26:31 +0000 Subject: Adds the ReturnArg() action (by Tim Hockin); refactors gmock-matchers.h (by Zhanyong Wan). --- include/gmock/gmock-generated-actions.h | 7 + include/gmock/gmock-generated-actions.h.pump | 9 +- include/gmock/gmock-generated-matchers.h | 222 +------------------------ include/gmock/gmock-generated-matchers.h.pump | 224 +------------------------- include/gmock/gmock-matchers.h | 215 ++++++++++++++++++++++++ test/gmock-generated-actions_test.cc | 16 ++ 6 files changed, 249 insertions(+), 444 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index c0097175..06d9449e 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -2441,6 +2441,13 @@ ACTION_TEMPLATE(InvokeArgument, ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +// Action ReturnArg() returns the k-th argument of the mock function. +ACTION_TEMPLATE(ReturnArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + return std::tr1::get(args); +} + // Action SaveArg(pointer) saves the k-th (0-based) argument of the // mock function to *pointer. ACTION_TEMPLATE(SaveArg, diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 2a7e4ffd..cc11769b 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -1,6 +1,6 @@ $$ -*- mode: c++; -*- $$ This is a Pump source file. Please use Pump to convert it to -$$ gmock-generated-variadic-actions.h. +$$ gmock-generated-actions.h. $$ $var n = 10 $$ The maximum arity we support. $$}} This meta comment fixes auto-indentation in editors. @@ -940,6 +940,13 @@ ACTION_TEMPLATE(InvokeArgument, ]] +// Action ReturnArg() returns the k-th argument of the mock function. +ACTION_TEMPLATE(ReturnArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + return std::tr1::get(args); +} + // Action SaveArg(pointer) saves the k-th (0-based) argument of the // mock function to *pointer. ACTION_TEMPLATE(SaveArg, diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 1a3e60b3..b2d55768 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -290,163 +290,7 @@ class ArgsMatcher { const InnerMatcher inner_matcher_; }; -// Implements ElementsAre() and ElementsAreArray(). -template -class ElementsAreMatcherImpl : public MatcherInterface { - public: - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef internal::StlContainerView View; - typedef typename View::type StlContainer; - typedef typename View::const_reference StlContainerReference; - typedef typename StlContainer::value_type Element; - - // Constructs the matcher from a sequence of element values or - // element matchers. - template - ElementsAreMatcherImpl(InputIter first, size_t count) { - matchers_.reserve(count); - InputIter it = first; - for (size_t i = 0; i != count; ++i, ++it) { - matchers_.push_back(MatcherCast(*it)); - } - } - - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - if (stl_container.size() != count()) - return false; - - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (!matchers_[i].Matches(*it)) - return false; - } - - return true; - } - - // Describes what this matcher does. - virtual void DescribeTo(::std::ostream* os) const { - if (count() == 0) { - *os << "is empty"; - } else if (count() == 1) { - *os << "has 1 element that "; - matchers_[0].DescribeTo(os); - } else { - *os << "has " << Elements(count()) << " where\n"; - for (size_t i = 0; i != count(); ++i) { - *os << "element " << i << " "; - matchers_[i].DescribeTo(os); - if (i + 1 < count()) { - *os << ",\n"; - } - } - } - } - - // Describes what the negation of this matcher does. - virtual void DescribeNegationTo(::std::ostream* os) const { - if (count() == 0) { - *os << "is not empty"; - return; - } - - *os << "does not have " << Elements(count()) << ", or\n"; - for (size_t i = 0; i != count(); ++i) { - *os << "element " << i << " "; - matchers_[i].DescribeNegationTo(os); - if (i + 1 < count()) { - *os << ", or\n"; - } - } - } - - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { - StlContainerReference stl_container = View::ConstReference(container); - if (Matches(container)) { - // We need to explain why *each* element matches (the obvious - // ones can be skipped). - - bool reason_printed = false; - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - - const string s = ss.str(); - if (!s.empty()) { - if (reason_printed) { - *os << ",\n"; - } - *os << "element " << i << " " << s; - reason_printed = true; - } - } - } else { - // We need to explain why the container doesn't match. - const size_t actual_count = stl_container.size(); - if (actual_count != count()) { - // The element count doesn't match. If the container is - // empty, there's no need to explain anything as Google Mock - // already prints the empty container. Otherwise we just need - // to show how many elements there actually are. - if (actual_count != 0) { - *os << "has " << Elements(actual_count); - } - return; - } - - // The container has the right size but at least one element - // doesn't match expectation. We need to find this element and - // explain why it doesn't match. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (matchers_[i].Matches(*it)) { - continue; - } - - *os << "element " << i << " doesn't match"; - - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - const string s = ss.str(); - if (!s.empty()) { - *os << " (" << s << ")"; - } - return; - } - } - } - - private: - static Message Elements(size_t count) { - return Message() << count << (count == 1 ? " element" : " elements"); - } - - size_t count() const { return matchers_.size(); } - std::vector > matchers_; -}; - -// Implements ElementsAre() of 0-10 arguments. - -class ElementsAreMatcher0 { - public: - ElementsAreMatcher0() {} - - template - operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) - RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher* const matchers = NULL; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); - } -}; +// Implements ElementsAre() of 1-10 arguments. template class ElementsAreMatcher1 { @@ -788,28 +632,6 @@ class ElementsAreMatcher10 { const T10& e10_; }; -// Implements ElementsAreArray(). -template -class ElementsAreArrayMatcher { - public: - ElementsAreArrayMatcher(const T* first, size_t count) : - first_(first), count_(count) {} - - template - operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) - RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); - } - - private: - const T* const first_; - const size_t count_; -}; - } // namespace internal // Args(a_matcher) matches a tuple if the selected @@ -1169,48 +991,6 @@ ElementsAreArray(const T (&array)[N]) { // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. -namespace testing { -namespace internal { - -// Constants denoting interpolations in a matcher description string. -const int kTupleInterpolation = -1; // "%(*)s" -const int kPercentInterpolation = -2; // "%%" -const int kInvalidInterpolation = -3; // "%" followed by invalid text - -// Records the location and content of an interpolation. -struct Interpolation { - Interpolation(const char* start, const char* end, int param) - : start_pos(start), end_pos(end), param_index(param) {} - - // Points to the start of the interpolation (the '%' character). - const char* start_pos; - // Points to the first character after the interpolation. - const char* end_pos; - // 0-based index of the interpolated matcher parameter; - // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%". - int param_index; -}; - -typedef ::std::vector Interpolations; - -// Parses a matcher description string and returns a vector of -// interpolations that appear in the string; generates non-fatal -// failures iff 'description' is an invalid matcher description. -// 'param_names' is a NULL-terminated array of parameter names in the -// order they appear in the MATCHER_P*() parameter list. -Interpolations ValidateMatcherDescription( - const char* param_names[], const char* description); - -// Returns the actual matcher description, given the matcher name, -// user-supplied description template string, interpolations in the -// string, and the printed values of the matcher parameters. -string FormatMatcherDescription( - const char* matcher_name, const char* description, - const Interpolations& interp, const Strings& param_values); - -} // namespace internal -} // namespace testing - #define MATCHER(name, description)\ class name##Matcher {\ public:\ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 653a2e87..41294b7a 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -1,6 +1,6 @@ $$ -*- mode: c++; -*- $$ This is a Pump source file. Please use Pump to convert it to -$$ gmock-generated-variadic-actions.h. +$$ gmock-generated-actions.h. $$ $var n = 10 $$ The maximum arity we support. $$ }} This line fixes auto-indentation of the following code in Emacs. @@ -173,163 +173,7 @@ class ArgsMatcher { const InnerMatcher inner_matcher_; }; -// Implements ElementsAre() and ElementsAreArray(). -template -class ElementsAreMatcherImpl : public MatcherInterface { - public: - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef internal::StlContainerView View; - typedef typename View::type StlContainer; - typedef typename View::const_reference StlContainerReference; - typedef typename StlContainer::value_type Element; - - // Constructs the matcher from a sequence of element values or - // element matchers. - template - ElementsAreMatcherImpl(InputIter first, size_t count) { - matchers_.reserve(count); - InputIter it = first; - for (size_t i = 0; i != count; ++i, ++it) { - matchers_.push_back(MatcherCast(*it)); - } - } - - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - if (stl_container.size() != count()) - return false; - - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (!matchers_[i].Matches(*it)) - return false; - } - - return true; - } - - // Describes what this matcher does. - virtual void DescribeTo(::std::ostream* os) const { - if (count() == 0) { - *os << "is empty"; - } else if (count() == 1) { - *os << "has 1 element that "; - matchers_[0].DescribeTo(os); - } else { - *os << "has " << Elements(count()) << " where\n"; - for (size_t i = 0; i != count(); ++i) { - *os << "element " << i << " "; - matchers_[i].DescribeTo(os); - if (i + 1 < count()) { - *os << ",\n"; - } - } - } - } - - // Describes what the negation of this matcher does. - virtual void DescribeNegationTo(::std::ostream* os) const { - if (count() == 0) { - *os << "is not empty"; - return; - } - - *os << "does not have " << Elements(count()) << ", or\n"; - for (size_t i = 0; i != count(); ++i) { - *os << "element " << i << " "; - matchers_[i].DescribeNegationTo(os); - if (i + 1 < count()) { - *os << ", or\n"; - } - } - } - - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { - StlContainerReference stl_container = View::ConstReference(container); - if (Matches(container)) { - // We need to explain why *each* element matches (the obvious - // ones can be skipped). - - bool reason_printed = false; - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - - const string s = ss.str(); - if (!s.empty()) { - if (reason_printed) { - *os << ",\n"; - } - *os << "element " << i << " " << s; - reason_printed = true; - } - } - } else { - // We need to explain why the container doesn't match. - const size_t actual_count = stl_container.size(); - if (actual_count != count()) { - // The element count doesn't match. If the container is - // empty, there's no need to explain anything as Google Mock - // already prints the empty container. Otherwise we just need - // to show how many elements there actually are. - if (actual_count != 0) { - *os << "has " << Elements(actual_count); - } - return; - } - - // The container has the right size but at least one element - // doesn't match expectation. We need to find this element and - // explain why it doesn't match. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (matchers_[i].Matches(*it)) { - continue; - } - - *os << "element " << i << " doesn't match"; - - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - const string s = ss.str(); - if (!s.empty()) { - *os << " (" << s << ")"; - } - return; - } - } - } - - private: - static Message Elements(size_t count) { - return Message() << count << (count == 1 ? " element" : " elements"); - } - - size_t count() const { return matchers_.size(); } - std::vector > matchers_; -}; - -// Implements ElementsAre() of 0-10 arguments. - -class ElementsAreMatcher0 { - public: - ElementsAreMatcher0() {} - - template - operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) - RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher* const matchers = NULL; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); - } -}; +// Implements ElementsAre() of 1-$n arguments. $range i 1..n @@ -369,28 +213,6 @@ $for j [[ ]] -// Implements ElementsAreArray(). -template -class ElementsAreArrayMatcher { - public: - ElementsAreArrayMatcher(const T* first, size_t count) : - first_(first), count_(count) {} - - template - operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) - RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); - } - - private: - const T* const first_; - const size_t count_; -}; - } // namespace internal // Args(a_matcher) matches a tuple if the selected @@ -625,48 +447,6 @@ $$ // show up in the generated code. // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. -namespace testing { -namespace internal { - -// Constants denoting interpolations in a matcher description string. -const int kTupleInterpolation = -1; // "%(*)s" -const int kPercentInterpolation = -2; // "%%" -const int kInvalidInterpolation = -3; // "%" followed by invalid text - -// Records the location and content of an interpolation. -struct Interpolation { - Interpolation(const char* start, const char* end, int param) - : start_pos(start), end_pos(end), param_index(param) {} - - // Points to the start of the interpolation (the '%' character). - const char* start_pos; - // Points to the first character after the interpolation. - const char* end_pos; - // 0-based index of the interpolated matcher parameter; - // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%". - int param_index; -}; - -typedef ::std::vector Interpolations; - -// Parses a matcher description string and returns a vector of -// interpolations that appear in the string; generates non-fatal -// failures iff 'description' is an invalid matcher description. -// 'param_names' is a NULL-terminated array of parameter names in the -// order they appear in the MATCHER_P*() parameter list. -Interpolations ValidateMatcherDescription( - const char* param_names[], const char* description); - -// Returns the actual matcher description, given the matcher name, -// user-supplied description template string, interpolations in the -// string, and the printed values of the matcher parameters. -string FormatMatcherDescription( - const char* matcher_name, const char* description, - const Interpolations& interp, const Strings& param_values); - -} // namespace internal -} // namespace testing - $range i 0..n $for i diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index db23a1bd..9e97866a 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1925,6 +1925,221 @@ class KeyMatcher { const M matcher_for_key_; }; +// Implements ElementsAre() and ElementsAreArray(). +template +class ElementsAreMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; + typedef internal::StlContainerView View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + typedef typename StlContainer::value_type Element; + + // Constructs the matcher from a sequence of element values or + // element matchers. + template + ElementsAreMatcherImpl(InputIter first, size_t count) { + matchers_.reserve(count); + InputIter it = first; + for (size_t i = 0; i != count; ++i, ++it) { + matchers_.push_back(MatcherCast(*it)); + } + } + + // Returns true iff 'container' matches. + virtual bool Matches(Container container) const { + StlContainerReference stl_container = View::ConstReference(container); + if (stl_container.size() != count()) + return false; + + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + if (!matchers_[i].Matches(*it)) + return false; + } + + return true; + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + if (count() == 0) { + *os << "is empty"; + } else if (count() == 1) { + *os << "has 1 element that "; + matchers_[0].DescribeTo(os); + } else { + *os << "has " << Elements(count()) << " where\n"; + for (size_t i = 0; i != count(); ++i) { + *os << "element " << i << " "; + matchers_[i].DescribeTo(os); + if (i + 1 < count()) { + *os << ",\n"; + } + } + } + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + if (count() == 0) { + *os << "is not empty"; + return; + } + + *os << "does not have " << Elements(count()) << ", or\n"; + for (size_t i = 0; i != count(); ++i) { + *os << "element " << i << " "; + matchers_[i].DescribeNegationTo(os); + if (i + 1 < count()) { + *os << ", or\n"; + } + } + } + + // Explains why 'container' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(Container container, + ::std::ostream* os) const { + StlContainerReference stl_container = View::ConstReference(container); + if (Matches(container)) { + // We need to explain why *each* element matches (the obvious + // ones can be skipped). + + bool reason_printed = false; + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + ::std::stringstream ss; + matchers_[i].ExplainMatchResultTo(*it, &ss); + + const string s = ss.str(); + if (!s.empty()) { + if (reason_printed) { + *os << ",\n"; + } + *os << "element " << i << " " << s; + reason_printed = true; + } + } + } else { + // We need to explain why the container doesn't match. + const size_t actual_count = stl_container.size(); + if (actual_count != count()) { + // The element count doesn't match. If the container is + // empty, there's no need to explain anything as Google Mock + // already prints the empty container. Otherwise we just need + // to show how many elements there actually are. + if (actual_count != 0) { + *os << "has " << Elements(actual_count); + } + return; + } + + // The container has the right size but at least one element + // doesn't match expectation. We need to find this element and + // explain why it doesn't match. + typename StlContainer::const_iterator it = stl_container.begin(); + for (size_t i = 0; i != count(); ++it, ++i) { + if (matchers_[i].Matches(*it)) { + continue; + } + + *os << "element " << i << " doesn't match"; + + ::std::stringstream ss; + matchers_[i].ExplainMatchResultTo(*it, &ss); + const string s = ss.str(); + if (!s.empty()) { + *os << " (" << s << ")"; + } + return; + } + } + } + + private: + static Message Elements(size_t count) { + return Message() << count << (count == 1 ? " element" : " elements"); + } + + size_t count() const { return matchers_.size(); } + std::vector > matchers_; +}; + +// Implements ElementsAre() of 0 arguments. +class ElementsAreMatcher0 { + public: + ElementsAreMatcher0() {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; + typedef typename internal::StlContainerView::type::value_type + Element; + + const Matcher* const matchers = NULL; + return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); + } +}; + +// Implements ElementsAreArray(). +template +class ElementsAreArrayMatcher { + public: + ElementsAreArrayMatcher(const T* first, size_t count) : + first_(first), count_(count) {} + + template + operator Matcher() const { + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + RawContainer; + typedef typename internal::StlContainerView::type::value_type + Element; + + return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); + } + + private: + const T* const first_; + const size_t count_; +}; + +// Constants denoting interpolations in a matcher description string. +const int kTupleInterpolation = -1; // "%(*)s" +const int kPercentInterpolation = -2; // "%%" +const int kInvalidInterpolation = -3; // "%" followed by invalid text + +// Records the location and content of an interpolation. +struct Interpolation { + Interpolation(const char* start, const char* end, int param) + : start_pos(start), end_pos(end), param_index(param) {} + + // Points to the start of the interpolation (the '%' character). + const char* start_pos; + // Points to the first character after the interpolation. + const char* end_pos; + // 0-based index of the interpolated matcher parameter; + // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%". + int param_index; +}; + +typedef ::std::vector Interpolations; + +// Parses a matcher description string and returns a vector of +// interpolations that appear in the string; generates non-fatal +// failures iff 'description' is an invalid matcher description. +// 'param_names' is a NULL-terminated array of parameter names in the +// order they appear in the MATCHER_P*() parameter list. +Interpolations ValidateMatcherDescription( + const char* param_names[], const char* description); + +// Returns the actual matcher description, given the matcher name, +// user-supplied description template string, interpolations in the +// string, and the printed values of the matcher parameters. +string FormatMatcherDescription( + const char* matcher_name, const char* description, + const Interpolations& interp, const Strings& param_values); + } // namespace internal // Implements MatcherCast(). diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index cf3c7891..885097c7 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -59,6 +59,7 @@ using testing::DoAll; using testing::Invoke; using testing::InvokeArgument; using testing::Return; +using testing::ReturnArg; using testing::ReturnNew; using testing::SaveArg; using testing::SetArgReferee; @@ -1382,6 +1383,21 @@ TEST(ActionPnMacroTest, CanExplicitlyInstantiateWithReferenceTypes) { EXPECT_EQ(55, a.Perform(empty)); } +TEST(ReturnArgActionTest, WorksForOneArgIntArg0) { + const Action a = ReturnArg<0>(); + EXPECT_EQ(5, a.Perform(make_tuple(5))); +} + +TEST(ReturnArgActionTest, WorksForMultiArgBoolArg0) { + const Action a = ReturnArg<0>(); + EXPECT_TRUE(a.Perform(make_tuple(true, false, false))); +} + +TEST(ReturnArgActionTest, WorksForMultiArgStringArg2) { + const Action a = ReturnArg<2>(); + EXPECT_EQ("seven", a.Perform(make_tuple(5, 6, string("seven"), 8))); +} + TEST(SaveArgActionTest, WorksForSameType) { int result = 0; const Action a1 = SaveArg<0>(&result); -- cgit v1.2.3 From a18423e0ee0c5cfe69948e4f4d0826dc8fe15f8c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 22 Jul 2009 23:58:19 +0000 Subject: Re-organizes the file structure for actions. --- Makefile.am | 5 + include/gmock/gmock-actions.h | 81 +++ include/gmock/gmock-generated-actions.h | 225 -------- include/gmock/gmock-generated-actions.h.pump | 225 -------- include/gmock/gmock-more-actions.h | 190 +++++++ include/gmock/gmock.h | 1 + test/gmock-actions_test.cc | 164 +++--- test/gmock-generated-actions_test.cc | 521 +----------------- test/gmock-more-actions_test.cc | 796 +++++++++++++++++++++++++++ 9 files changed, 1159 insertions(+), 1049 deletions(-) create mode 100644 include/gmock/gmock-more-actions.h create mode 100644 test/gmock-more-actions_test.cc diff --git a/Makefile.am b/Makefile.am index 196b9271..1ce29ba2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,6 +110,11 @@ check_PROGRAMS += test/gmock-matchers_test test_gmock_matchers_test_SOURCES = test/gmock-matchers_test.cc test_gmock_matchers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la +TESTS += test/gmock-more-actions_test +check_PROGRAMS += test/gmock-more-actions_test +test_gmock_more_actions_test_SOURCES = test/gmock-more-actions_test.cc +test_gmock_more_actions_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la + TESTS += test/gmock-nice-strict_test check_PROGRAMS += test/gmock-nice-strict_test test_gmock_nice_strict_test_SOURCES = test/gmock-nice-strict_test.cc diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index a283ed73..49d5532d 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -43,6 +43,7 @@ #include #endif +#include #include #include @@ -787,6 +788,74 @@ class IgnoreResultAction { const A action_; }; +// 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_; + }; + + Action1 action1_; + Action2 action2_; +}; + } // namespace internal // An Unused object can be implicitly constructed from ANY value. @@ -926,6 +995,18 @@ 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/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 06d9449e..143a99be 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -39,7 +39,6 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #include -#include #include namespace testing { @@ -283,75 +282,6 @@ class InvokeHelper as long as f's type is compatible with F (i.e. f can be -// assigned to a tr1::function). -template -class InvokeAction { - public: - // The c'tor makes a copy of function_impl (either a function - // pointer or a functor). - explicit InvokeAction(FunctionImpl function_impl) - : function_impl_(function_impl) {} - - template - Result Perform(const ArgumentTuple& args) { - return InvokeHelper::Invoke(function_impl_, args); - } - private: - FunctionImpl function_impl_; -}; - -// Implements the Invoke(object_ptr, &Class::Method) action. -template -class InvokeMethodAction { - public: - InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr) - : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} - - template - Result Perform(const ArgumentTuple& args) const { - return InvokeHelper::InvokeMethod( - obj_ptr_, method_ptr_, args); - } - private: - Class* const obj_ptr_; - const MethodPtr method_ptr_; -}; - -// TODO(wan@google.com): ReferenceWrapper and ByRef() are neither -// action-specific nor variadic. Move them to a better place. - -// 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); -} - // CallableHelper has static methods for invoking "callables", // i.e. function pointers and functors. It uses overloading to // provide a uniform interface for invoking different kinds of @@ -687,47 +617,6 @@ class WithArgsAction { const InnerAction action_; }; -// 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_; - }; - - Action1 action1_; - Action2 action2_; -}; - // 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 @@ -863,57 +752,6 @@ class ActionHelper { // Various overloads for Invoke(). -// Creates an action that invokes 'function_impl' with the mock -// function's arguments. -template -PolymorphicAction > Invoke( - FunctionImpl function_impl) { - return MakePolymorphicAction( - internal::InvokeAction(function_impl)); -} - -// Creates an action that invokes the given method on the given object -// with the mock function's arguments. -template -PolymorphicAction > Invoke( - Class* obj_ptr, MethodPtr method_ptr) { - return MakePolymorphicAction( - internal::InvokeMethodAction(obj_ptr, method_ptr)); -} - -// 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); -} - -// WithoutArgs(inner_action) can be used in a mock function with a -// non-empty argument list to perform inner_action, which takes no -// argument. In other words, it adapts an action accepting no -// argument to one that accepts (and ignores) arguments. -template -inline internal::WithArgsAction -WithoutArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -// WithArg(an_action) creates an action that passes the k-th -// (0-based) argument of the mock function to an_action and performs -// it. It adapts an action accepting one argument to one that accepts -// multiple arguments. For convenience, we also provide -// WithArgs(an_action) (defined below) as a synonym. -template -inline internal::WithArgsAction -WithArg(const InnerAction& action) { - return internal::WithArgsAction(action); -} - // 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 @@ -2441,55 +2279,6 @@ ACTION_TEMPLATE(InvokeArgument, ::std::tr1::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } -// Action ReturnArg() returns the k-th argument of the mock function. -ACTION_TEMPLATE(ReturnArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - return std::tr1::get(args); -} - -// Action SaveArg(pointer) saves the k-th (0-based) argument of the -// mock function to *pointer. -ACTION_TEMPLATE(SaveArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(pointer)) { - *pointer = ::std::tr1::get(args); -} - -// Action SetArgReferee(value) assigns 'value' to the variable -// referenced by the k-th (0-based) argument of the mock function. -ACTION_TEMPLATE(SetArgReferee, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(value)) { - typedef typename ::std::tr1::tuple_element::type argk_type; - // Ensures that argument #k is a reference. If you get a compiler - // error on the next line, you are using SetArgReferee(value) in - // a mock function whose k-th (0-based) argument is not a reference. - GMOCK_COMPILE_ASSERT_(internal::is_reference::value, - SetArgReferee_must_be_used_with_a_reference_argument); - ::std::tr1::get(args) = value; -} - -// Action SetArrayArgument(first, last) copies the elements in -// source range [first, last) to the array pointed to by the k-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. -ACTION_TEMPLATE(SetArrayArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_2_VALUE_PARAMS(first, last)) { - // Microsoft compiler deprecates ::std::copy, so we want to suppress warning - // 4996 (Function call with parameters that may be unsafe) there. -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. -#endif - ::std::copy(first, last, ::std::tr1::get(args)); -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif -} - // Various overloads for ReturnNew(). // // The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new @@ -2561,20 +2350,6 @@ ACTION_TEMPLATE(ReturnNew, return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } -// Action DeleteArg() deletes the k-th (0-based) argument of the mock -// function. -ACTION_TEMPLATE(DeleteArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - delete ::std::tr1::get(args); -} - -// Action Throw(exception) can be used in a mock function of any type -// to throw the given exception. Any copyable value can be thrown. -#if GTEST_HAS_EXCEPTIONS -ACTION_P(Throw, exception) { throw exception; } -#endif // GTEST_HAS_EXCEPTIONS - } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index cc11769b..05bf3db3 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -43,7 +43,6 @@ $$}} This meta comment fixes auto-indentation in editors. #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #include -#include #include namespace testing { @@ -85,75 +84,6 @@ $import return (obj_ptr->*method_ptr)($gets); ]] - -// Implements the Invoke(f) action. The template argument -// FunctionImpl is the implementation type of f, which can be either a -// function pointer or a functor. Invoke(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 InvokeAction { - public: - // The c'tor makes a copy of function_impl (either a function - // pointer or a functor). - explicit InvokeAction(FunctionImpl function_impl) - : function_impl_(function_impl) {} - - template - Result Perform(const ArgumentTuple& args) { - return InvokeHelper::Invoke(function_impl_, args); - } - private: - FunctionImpl function_impl_; -}; - -// Implements the Invoke(object_ptr, &Class::Method) action. -template -class InvokeMethodAction { - public: - InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr) - : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} - - template - Result Perform(const ArgumentTuple& args) const { - return InvokeHelper::InvokeMethod( - obj_ptr_, method_ptr_, args); - } - private: - Class* const obj_ptr_; - const MethodPtr method_ptr_; -}; - -// TODO(wan@google.com): ReferenceWrapper and ByRef() are neither -// action-specific nor variadic. Move them to a better place. - -// 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); -} - // CallableHelper has static methods for invoking "callables", // i.e. function pointers and functors. It uses overloading to // provide a uniform interface for invoking different kinds of @@ -300,47 +230,6 @@ class WithArgsAction { const InnerAction action_; }; -// 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_; - }; - - Action1 action1_; - Action2 action2_; -}; - // 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 @@ -388,57 +277,6 @@ $template // Various overloads for Invoke(). -// Creates an action that invokes 'function_impl' with the mock -// function's arguments. -template -PolymorphicAction > Invoke( - FunctionImpl function_impl) { - return MakePolymorphicAction( - internal::InvokeAction(function_impl)); -} - -// Creates an action that invokes the given method on the given object -// with the mock function's arguments. -template -PolymorphicAction > Invoke( - Class* obj_ptr, MethodPtr method_ptr) { - return MakePolymorphicAction( - internal::InvokeMethodAction(obj_ptr, method_ptr)); -} - -// 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); -} - -// WithoutArgs(inner_action) can be used in a mock function with a -// non-empty argument list to perform inner_action, which takes no -// argument. In other words, it adapts an action accepting no -// argument to one that accepts (and ignores) arguments. -template -inline internal::WithArgsAction -WithoutArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -// WithArg(an_action) creates an action that passes the k-th -// (0-based) argument of the mock function to an_action and performs -// it. It adapts an action accepting one argument to one that accepts -// multiple arguments. For convenience, we also provide -// WithArgs(an_action) (defined below) as a synonym. -template -inline internal::WithArgsAction -WithArg(const InnerAction& action) { - return internal::WithArgsAction(action); -} - // 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 @@ -940,55 +778,6 @@ ACTION_TEMPLATE(InvokeArgument, ]] -// Action ReturnArg() returns the k-th argument of the mock function. -ACTION_TEMPLATE(ReturnArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - return std::tr1::get(args); -} - -// Action SaveArg(pointer) saves the k-th (0-based) argument of the -// mock function to *pointer. -ACTION_TEMPLATE(SaveArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(pointer)) { - *pointer = ::std::tr1::get(args); -} - -// Action SetArgReferee(value) assigns 'value' to the variable -// referenced by the k-th (0-based) argument of the mock function. -ACTION_TEMPLATE(SetArgReferee, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(value)) { - typedef typename ::std::tr1::tuple_element::type argk_type; - // Ensures that argument #k is a reference. If you get a compiler - // error on the next line, you are using SetArgReferee(value) in - // a mock function whose k-th (0-based) argument is not a reference. - GMOCK_COMPILE_ASSERT_(internal::is_reference::value, - SetArgReferee_must_be_used_with_a_reference_argument); - ::std::tr1::get(args) = value; -} - -// Action SetArrayArgument(first, last) copies the elements in -// source range [first, last) to the array pointed to by the k-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. -ACTION_TEMPLATE(SetArrayArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_2_VALUE_PARAMS(first, last)) { - // Microsoft compiler deprecates ::std::copy, so we want to suppress warning - // 4996 (Function call with parameters that may be unsafe) there. -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. -#endif - ::std::copy(first, last, ::std::tr1::get(args)); -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif -} - // Various overloads for ReturnNew(). // // The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new @@ -1007,20 +796,6 @@ ACTION_TEMPLATE(ReturnNew, ]] -// Action DeleteArg() deletes the k-th (0-based) argument of the mock -// function. -ACTION_TEMPLATE(DeleteArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - delete ::std::tr1::get(args); -} - -// Action Throw(exception) can be used in a mock function of any type -// to throw the given exception. Any copyable value can be thrown. -#if GTEST_HAS_EXCEPTIONS -ACTION_P(Throw, exception) { throw exception; } -#endif // GTEST_HAS_EXCEPTIONS - } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h new file mode 100644 index 00000000..c6fa6bbd --- /dev/null +++ b/include/gmock/gmock-more-actions.h @@ -0,0 +1,190 @@ +// 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 actions that depend on gmock-generated-actions.h. + +#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ +#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ + +#include + +namespace testing { +namespace internal { + +// Implements the Invoke(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. Invoke(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 InvokeAction { + public: + // The c'tor makes a copy of function_impl (either a function + // pointer or a functor). + explicit InvokeAction(FunctionImpl function_impl) + : function_impl_(function_impl) {} + + template + Result Perform(const ArgumentTuple& args) { + return InvokeHelper::Invoke(function_impl_, args); + } + private: + FunctionImpl function_impl_; +}; + +// Implements the Invoke(object_ptr, &Class::Method) action. +template +class InvokeMethodAction { + public: + InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr) + : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} + + template + Result Perform(const ArgumentTuple& args) const { + return InvokeHelper::InvokeMethod( + obj_ptr_, method_ptr_, args); + } + private: + Class* const obj_ptr_; + const MethodPtr method_ptr_; +}; + +} // namespace internal + +// Various overloads for Invoke(). + +// Creates an action that invokes 'function_impl' with the mock +// function's arguments. +template +PolymorphicAction > Invoke( + FunctionImpl function_impl) { + return MakePolymorphicAction( + internal::InvokeAction(function_impl)); +} + +// Creates an action that invokes the given method on the given object +// with the mock function's arguments. +template +PolymorphicAction > Invoke( + Class* obj_ptr, MethodPtr method_ptr) { + return MakePolymorphicAction( + internal::InvokeMethodAction(obj_ptr, method_ptr)); +} + +// WithoutArgs(inner_action) can be used in a mock function with a +// non-empty argument list to perform inner_action, which takes no +// argument. In other words, it adapts an action accepting no +// argument to one that accepts (and ignores) arguments. +template +inline internal::WithArgsAction +WithoutArgs(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// WithArg(an_action) creates an action that passes the k-th +// (0-based) argument of the mock function to an_action and performs +// it. It adapts an action accepting one argument to one that accepts +// multiple arguments. For convenience, we also provide +// WithArgs(an_action) (defined below) as a synonym. +template +inline internal::WithArgsAction +WithArg(const InnerAction& action) { + return internal::WithArgsAction(action); +} + +// Action ReturnArg() returns the k-th argument of the mock function. +ACTION_TEMPLATE(ReturnArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + return std::tr1::get(args); +} + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +ACTION_TEMPLATE(SaveArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(pointer)) { + *pointer = ::std::tr1::get(args); +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +ACTION_TEMPLATE(SetArgReferee, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(value)) { + typedef typename ::std::tr1::tuple_element::type argk_type; + // Ensures that argument #k is a reference. If you get a compiler + // error on the next line, you are using SetArgReferee(value) in + // a mock function whose k-th (0-based) argument is not a reference. + GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + SetArgReferee_must_be_used_with_a_reference_argument); + ::std::tr1::get(args) = value; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-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. +ACTION_TEMPLATE(SetArrayArgument, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_2_VALUE_PARAMS(first, last)) { + // Microsoft compiler deprecates ::std::copy, so we want to suppress warning + // 4996 (Function call with parameters that may be unsafe) there. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. +#endif + ::std::copy(first, last, ::std::tr1::get(args)); +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +ACTION_TEMPLATE(DeleteArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + delete ::std::tr1::get(args); +} + +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown. +#if GTEST_HAS_EXCEPTIONS +ACTION_P(Throw, exception) { throw exception; } +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace testing + +#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index 29d9727c..daf52884 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 24462609..9bf4c32d 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -56,6 +56,7 @@ using testing::_; using testing::Action; using testing::ActionInterface; using testing::Assign; +using testing::ByRef; using testing::DefaultValue; using testing::DoDefault; using testing::IgnoreResult; @@ -68,7 +69,6 @@ using testing::Return; using testing::ReturnNull; using testing::ReturnRef; using testing::SetArgumentPointee; -using testing::SetArrayArgument; #ifndef _WIN32_WCE using testing::SetErrnoAndReturn; @@ -743,85 +743,6 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferBaseType) { #endif // GMOCK_HAS_PROTOBUF_ -// Tests that SetArrayArgument(first, last) sets the elements of the array -// pointed to by the N-th (0-based) argument to values in range [first, last). -TEST(SetArrayArgumentTest, SetsTheNthArray) { - typedef void MyFunction(bool, int*, char*); - int numbers[] = { 1, 2, 3 }; - Action a = SetArrayArgument<1>(numbers, numbers + 3); - - int n[4] = {}; - int* pn = n; - char ch[4] = {}; - char* pch = ch; - a.Perform(make_tuple(true, pn, pch)); - EXPECT_EQ(1, n[0]); - EXPECT_EQ(2, n[1]); - EXPECT_EQ(3, n[2]); - EXPECT_EQ(0, n[3]); - EXPECT_EQ('\0', ch[0]); - EXPECT_EQ('\0', ch[1]); - EXPECT_EQ('\0', ch[2]); - EXPECT_EQ('\0', ch[3]); - - // Tests first and last are iterators. - std::string letters = "abc"; - a = SetArrayArgument<2>(letters.begin(), letters.end()); - std::fill_n(n, 4, 0); - std::fill_n(ch, 4, '\0'); - a.Perform(make_tuple(true, pn, pch)); - EXPECT_EQ(0, n[0]); - EXPECT_EQ(0, n[1]); - EXPECT_EQ(0, n[2]); - EXPECT_EQ(0, n[3]); - EXPECT_EQ('a', ch[0]); - EXPECT_EQ('b', ch[1]); - EXPECT_EQ('c', ch[2]); - EXPECT_EQ('\0', ch[3]); -} - -// Tests SetArrayArgument(first, last) where first == last. -TEST(SetArrayArgumentTest, SetsTheNthArrayWithEmptyRange) { - typedef void MyFunction(bool, int*); - int numbers[] = { 1, 2, 3 }; - Action a = SetArrayArgument<1>(numbers, numbers); - - int n[4] = {}; - int* pn = n; - a.Perform(make_tuple(true, pn)); - EXPECT_EQ(0, n[0]); - EXPECT_EQ(0, n[1]); - EXPECT_EQ(0, n[2]); - EXPECT_EQ(0, n[3]); -} - -// Tests SetArrayArgument(first, last) where *first is convertible -// (but not equal) to the argument type. -TEST(SetArrayArgumentTest, SetsTheNthArrayWithConvertibleType) { - typedef void MyFunction(bool, char*); - int codes[] = { 97, 98, 99 }; - Action a = SetArrayArgument<1>(codes, codes + 3); - - char ch[4] = {}; - char* pch = ch; - a.Perform(make_tuple(true, pch)); - EXPECT_EQ('a', ch[0]); - EXPECT_EQ('b', ch[1]); - EXPECT_EQ('c', ch[2]); - EXPECT_EQ('\0', ch[3]); -} - -// Test SetArrayArgument(first, last) with iterator as argument. -TEST(SetArrayArgumentTest, SetsTheNthArrayWithIteratorArgument) { - typedef void MyFunction(bool, std::back_insert_iterator); - std::string letters = "abc"; - Action a = SetArrayArgument<1>(letters.begin(), letters.end()); - - std::string s; - a.Perform(make_tuple(true, back_inserter(s))); - EXPECT_EQ(letters, s); -} - // Sample functions and functors for testing Invoke() and etc. int Nullary() { return 1; } @@ -1031,4 +952,87 @@ TEST_F(SetErrnoAndReturnTest, CompatibleTypes) { #endif // _WIN32_WCE +// Tests ByRef(). + +// Tests that ReferenceWrapper is copyable. +TEST(ByRefTest, IsCopyable) { + const std::string s1 = "Hi"; + const std::string s2 = "Hello"; + + ::testing::internal::ReferenceWrapper ref_wrapper = ByRef(s1); + const std::string& r1 = ref_wrapper; + EXPECT_EQ(&s1, &r1); + + // Assigns a new value to ref_wrapper. + ref_wrapper = ByRef(s2); + const std::string& r2 = ref_wrapper; + EXPECT_EQ(&s2, &r2); + + ::testing::internal::ReferenceWrapper ref_wrapper1 = ByRef(s1); + // Copies ref_wrapper1 to ref_wrapper. + ref_wrapper = ref_wrapper1; + const std::string& r3 = ref_wrapper; + EXPECT_EQ(&s1, &r3); +} + +// Tests using ByRef() on a const value. +TEST(ByRefTest, ConstValue) { + const int n = 0; + // int& ref = ByRef(n); // This shouldn't compile - we have a + // negative compilation test to catch it. + const int& const_ref = ByRef(n); + EXPECT_EQ(&n, &const_ref); +} + +// Tests using ByRef() on a non-const value. +TEST(ByRefTest, NonConstValue) { + int n = 0; + + // ByRef(n) can be used as either an int&, + int& ref = ByRef(n); + EXPECT_EQ(&n, &ref); + + // or a const int&. + const int& const_ref = ByRef(n); + EXPECT_EQ(&n, &const_ref); +} + +// Tests explicitly specifying the type when using ByRef(). +TEST(ByRefTest, ExplicitType) { + int n = 0; + const int& r1 = ByRef(n); + EXPECT_EQ(&n, &r1); + + // ByRef(n); // This shouldn't compile - we have a negative + // compilation test to catch it. + + Derived d; + Derived& r2 = ByRef(d); + EXPECT_EQ(&d, &r2); + + const Derived& r3 = ByRef(d); + EXPECT_EQ(&d, &r3); + + Base& r4 = ByRef(d); + EXPECT_EQ(&d, &r4); + + const Base& r5 = ByRef(d); + EXPECT_EQ(&d, &r5); + + // The following shouldn't compile - we have a negative compilation + // test for it. + // + // Base b; + // ByRef(b); +} + +// Tests that Google Mock prints expression ByRef(x) as a reference to x. +TEST(ByRefTest, PrintsCorrectly) { + int n = 42; + ::std::stringstream expected, actual; + testing::internal::UniversalPrinter::Print(n, &expected); + testing::internal::UniversalPrint(ByRef(n), &actual); + EXPECT_EQ(expected.str(), actual.str()); +} + } // Unnamed namespace diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 885097c7..2e6fa0b6 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -54,23 +54,16 @@ using testing::_; using testing::Action; using testing::ActionInterface; using testing::ByRef; -using testing::DeleteArg; using testing::DoAll; using testing::Invoke; -using testing::InvokeArgument; using testing::Return; -using testing::ReturnArg; using testing::ReturnNew; -using testing::SaveArg; -using testing::SetArgReferee; using testing::SetArgumentPointee; using testing::StaticAssertTypeEq; using testing::Unused; -using testing::WithArg; using testing::WithArgs; -using testing::WithoutArgs; -// Sample functions and functors for testing Invoke() and etc. +// Sample functions and functors for testing various actions. int Nullary() { return 1; } class NullaryFunctor { @@ -79,19 +72,11 @@ class NullaryFunctor { }; bool g_done = false; -void VoidNullary() { g_done = true; } - -class VoidNullaryFunctor { - public: - void operator()() { g_done = true; } -}; bool Unary(int x) { return x < 0; } const char* Plus1(const char* s) { return s + 1; } -void VoidUnary(int n) { g_done = true; } - bool ByConstRef(const string& s) { return s == "Hi"; } const double g_double = 0; @@ -113,10 +98,6 @@ void VoidTernary(int, char, bool) { g_done = true; } int SumOf4(int a, int b, int c, int d) { return a + b + c + d; } -int SumOfFirst2(int a, int b, Unused, Unused) { return a + b; } - -void VoidFunctionWithFourArguments(char, int, float, double) { g_done = true; } - string Concat4(const char* s1, const char* s2, const char* s3, const char* s4) { return string(s1) + s2 + s3 + s4; @@ -175,388 +156,10 @@ string Concat10(const char* s1, const char* s2, const char* s3, return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; } -class Foo { - public: - Foo() : value_(123) {} - - int Nullary() const { return value_; } - - short Unary(long x) { return static_cast(value_ + x); } // NOLINT - - string Binary(const string& str, char c) const { return str + c; } - - int Ternary(int x, bool y, char z) { return value_ + x + y*z; } - - int SumOf4(int a, int b, int c, int d) const { - return a + b + c + d + value_; - } - - int SumOfLast2(Unused, Unused, int a, int b) const { return a + b; } - - int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } - - int SumOf6(int a, int b, int c, int d, int e, int f) { - return a + b + c + d + e + f; - } - - string Concat7(const char* s1, const char* s2, const char* s3, - const char* s4, const char* s5, const char* s6, - const char* s7) { - return string(s1) + s2 + s3 + s4 + s5 + s6 + s7; - } - - string Concat8(const char* s1, const char* s2, const char* s3, - const char* s4, const char* s5, const char* s6, - const char* s7, const char* s8) { - return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8; - } - - string Concat9(const char* s1, const char* s2, const char* s3, - const char* s4, const char* s5, const char* s6, - const char* s7, const char* s8, const char* s9) { - return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; - } - - string Concat10(const char* s1, const char* s2, const char* s3, - const char* s4, const char* s5, const char* s6, - const char* s7, const char* s8, const char* s9, - const char* s10) { - return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; - } - private: - int value_; -}; - -// Tests using Invoke() with a nullary function. -TEST(InvokeTest, Nullary) { - Action a = Invoke(Nullary); // NOLINT - EXPECT_EQ(1, a.Perform(make_tuple())); -} - -// Tests using Invoke() with a unary function. -TEST(InvokeTest, Unary) { - Action a = Invoke(Unary); // NOLINT - EXPECT_FALSE(a.Perform(make_tuple(1))); - EXPECT_TRUE(a.Perform(make_tuple(-1))); -} - -// Tests using Invoke() with a binary function. -TEST(InvokeTest, Binary) { - Action a = Invoke(Binary); // NOLINT - const char* p = "Hello"; - EXPECT_EQ(p + 2, a.Perform(make_tuple(p, 2))); -} - -// Tests using Invoke() with a ternary function. -TEST(InvokeTest, Ternary) { - Action a = Invoke(Ternary); // NOLINT - EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', 3))); -} - -// Tests using Invoke() with a 4-argument function. -TEST(InvokeTest, FunctionThatTakes4Arguments) { - Action a = Invoke(SumOf4); // NOLINT - EXPECT_EQ(1234, a.Perform(make_tuple(1000, 200, 30, 4))); -} - -// Tests using Invoke() with a 5-argument function. -TEST(InvokeTest, FunctionThatTakes5Arguments) { - Action a = Invoke(SumOf5); // NOLINT - EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5))); -} - -// Tests using Invoke() with a 6-argument function. -TEST(InvokeTest, FunctionThatTakes6Arguments) { - Action a = Invoke(SumOf6); // NOLINT - EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); -} - // A helper that turns the type of a C-string literal from const // char[N] to const char*. inline const char* CharPtr(const char* s) { return s; } -// Tests using Invoke() with a 7-argument function. -TEST(InvokeTest, FunctionThatTakes7Arguments) { - Action a = - Invoke(Concat7); - EXPECT_EQ("1234567", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7")))); -} - -// Tests using Invoke() with a 8-argument function. -TEST(InvokeTest, FunctionThatTakes8Arguments) { - Action a = - Invoke(Concat8); - EXPECT_EQ("12345678", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7"), CharPtr("8")))); -} - -// Tests using Invoke() with a 9-argument function. -TEST(InvokeTest, FunctionThatTakes9Arguments) { - Action a = Invoke(Concat9); - EXPECT_EQ("123456789", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7"), CharPtr("8"), CharPtr("9")))); -} - -// Tests using Invoke() with a 10-argument function. -TEST(InvokeTest, FunctionThatTakes10Arguments) { - Action a = Invoke(Concat10); - EXPECT_EQ("1234567890", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7"), CharPtr("8"), CharPtr("9"), - CharPtr("0")))); -} - -// Tests using Invoke() with functions with parameters declared as Unused. -TEST(InvokeTest, FunctionWithUnusedParameters) { - Action a1 = - Invoke(SumOfFirst2); - EXPECT_EQ(12, a1.Perform(make_tuple(10, 2, 5.6, CharPtr("hi")))); - - Action a2 = - Invoke(SumOfFirst2); - EXPECT_EQ(23, a2.Perform(make_tuple(20, 3, true, static_cast(NULL)))); -} - -// Tests using Invoke() with methods with parameters declared as Unused. -TEST(InvokeTest, MethodWithUnusedParameters) { - Foo foo; - Action a1 = - Invoke(&foo, &Foo::SumOfLast2); - EXPECT_EQ(12, a1.Perform(make_tuple(CharPtr("hi"), true, 10, 2))); - - Action a2 = - Invoke(&foo, &Foo::SumOfLast2); - EXPECT_EQ(23, a2.Perform(make_tuple('a', 2.5, 20, 3))); -} - -// Tests using Invoke() with a functor. -TEST(InvokeTest, Functor) { - Action a = Invoke(plus()); // NOLINT - EXPECT_EQ(3, a.Perform(make_tuple(1, 2))); -} - -// Tests using Invoke(f) as an action of a compatible type. -TEST(InvokeTest, FunctionWithCompatibleType) { - Action a = Invoke(SumOf4); // NOLINT - EXPECT_EQ(4321, a.Perform(make_tuple(4000, 300, 20, true))); -} - -// Tests using Invoke() with an object pointer and a method pointer. - -// Tests using Invoke() with a nullary method. -TEST(InvokeMethodTest, Nullary) { - Foo foo; - Action a = Invoke(&foo, &Foo::Nullary); // NOLINT - EXPECT_EQ(123, a.Perform(make_tuple())); -} - -// Tests using Invoke() with a unary method. -TEST(InvokeMethodTest, Unary) { - Foo foo; - Action a = Invoke(&foo, &Foo::Unary); // NOLINT - EXPECT_EQ(4123, a.Perform(make_tuple(4000))); -} - -// Tests using Invoke() with a binary method. -TEST(InvokeMethodTest, Binary) { - Foo foo; - Action a = Invoke(&foo, &Foo::Binary); - string s("Hell"); - EXPECT_EQ("Hello", a.Perform(make_tuple(s, 'o'))); -} - -// Tests using Invoke() with a ternary method. -TEST(InvokeMethodTest, Ternary) { - Foo foo; - Action a = Invoke(&foo, &Foo::Ternary); // NOLINT - EXPECT_EQ(1124, a.Perform(make_tuple(1000, true, 1))); -} - -// Tests using Invoke() with a 4-argument method. -TEST(InvokeMethodTest, MethodThatTakes4Arguments) { - Foo foo; - Action a = Invoke(&foo, &Foo::SumOf4); // NOLINT - EXPECT_EQ(1357, a.Perform(make_tuple(1000, 200, 30, 4))); -} - -// Tests using Invoke() with a 5-argument method. -TEST(InvokeMethodTest, MethodThatTakes5Arguments) { - Foo foo; - Action a = Invoke(&foo, &Foo::SumOf5); // NOLINT - EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5))); -} - -// Tests using Invoke() with a 6-argument method. -TEST(InvokeMethodTest, MethodThatTakes6Arguments) { - Foo foo; - Action a = // NOLINT - Invoke(&foo, &Foo::SumOf6); - EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); -} - -// Tests using Invoke() with a 7-argument method. -TEST(InvokeMethodTest, MethodThatTakes7Arguments) { - Foo foo; - Action a = - Invoke(&foo, &Foo::Concat7); - EXPECT_EQ("1234567", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7")))); -} - -// Tests using Invoke() with a 8-argument method. -TEST(InvokeMethodTest, MethodThatTakes8Arguments) { - Foo foo; - Action a = - Invoke(&foo, &Foo::Concat8); - EXPECT_EQ("12345678", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7"), CharPtr("8")))); -} - -// Tests using Invoke() with a 9-argument method. -TEST(InvokeMethodTest, MethodThatTakes9Arguments) { - Foo foo; - Action a = Invoke(&foo, &Foo::Concat9); - EXPECT_EQ("123456789", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7"), CharPtr("8"), CharPtr("9")))); -} - -// Tests using Invoke() with a 10-argument method. -TEST(InvokeMethodTest, MethodThatTakes10Arguments) { - Foo foo; - Action a = Invoke(&foo, &Foo::Concat10); - EXPECT_EQ("1234567890", - a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), - CharPtr("4"), CharPtr("5"), CharPtr("6"), - CharPtr("7"), CharPtr("8"), CharPtr("9"), - CharPtr("0")))); -} - -// Tests using Invoke(f) as an action of a compatible type. -TEST(InvokeMethodTest, MethodWithCompatibleType) { - Foo foo; - Action a = // NOLINT - Invoke(&foo, &Foo::SumOf4); - EXPECT_EQ(4444, a.Perform(make_tuple(4000, 300, 20, true))); -} - -// Tests ByRef(). - -// Tests that ReferenceWrapper is copyable. -TEST(ByRefTest, IsCopyable) { - const string s1 = "Hi"; - const string s2 = "Hello"; - - ::testing::internal::ReferenceWrapper ref_wrapper = ByRef(s1); - const string& r1 = ref_wrapper; - EXPECT_EQ(&s1, &r1); - - // Assigns a new value to ref_wrapper. - ref_wrapper = ByRef(s2); - const string& r2 = ref_wrapper; - EXPECT_EQ(&s2, &r2); - - ::testing::internal::ReferenceWrapper ref_wrapper1 = ByRef(s1); - // Copies ref_wrapper1 to ref_wrapper. - ref_wrapper = ref_wrapper1; - const string& r3 = ref_wrapper; - EXPECT_EQ(&s1, &r3); -} - -// Tests using ByRef() on a const value. -TEST(ByRefTest, ConstValue) { - const int n = 0; - // int& ref = ByRef(n); // This shouldn't compile - we have a - // negative compilation test to catch it. - const int& const_ref = ByRef(n); - EXPECT_EQ(&n, &const_ref); -} - -// Tests using ByRef() on a non-const value. -TEST(ByRefTest, NonConstValue) { - int n = 0; - - // ByRef(n) can be used as either an int&, - int& ref = ByRef(n); - EXPECT_EQ(&n, &ref); - - // or a const int&. - const int& const_ref = ByRef(n); - EXPECT_EQ(&n, &const_ref); -} - -struct Base { - bool operator==(const Base&) { return true; } -}; - -struct Derived : public Base { - bool operator==(const Derived&) { return true; } -}; - -// Tests explicitly specifying the type when using ByRef(). -TEST(ByRefTest, ExplicitType) { - int n = 0; - const int& r1 = ByRef(n); - EXPECT_EQ(&n, &r1); - - // ByRef(n); // This shouldn't compile - we have a negative - // compilation test to catch it. - - - Derived d; - Derived& r2 = ByRef(d); - EXPECT_EQ(&d, &r2); - - const Derived& r3 = ByRef(d); - EXPECT_EQ(&d, &r3); - - Base& r4 = ByRef(d); - EXPECT_EQ(&d, &r4); - - const Base& r5 = ByRef(d); - EXPECT_EQ(&d, &r5); - - // The following shouldn't compile - we have a negative compilation - // test for it. - // - // Base b; - // ByRef(b); -} - -// Tests that Google Mock prints expression ByRef(x) as a reference to x. -TEST(ByRefTest, PrintsCorrectly) { - int n = 42; - ::std::stringstream expected, actual; - testing::internal::UniversalPrinter::Print(n, &expected); - testing::internal::UniversalPrint(ByRef(n), &actual); - EXPECT_EQ(expected.str(), actual.str()); -} - // Tests InvokeArgument(...). // Tests using InvokeArgument with a nullary function. @@ -674,23 +277,11 @@ TEST(InvokeArgumentTest, ByExplicitConstReferenceFunction) { EXPECT_FALSE(a.Perform(make_tuple(&ReferencesGlobalDouble))); } -// Tests using WithoutArgs with an action that takes no argument. -TEST(WithoutArgsTest, NoArg) { - Action a = WithoutArgs(Invoke(Nullary)); // NOLINT - EXPECT_EQ(1, a.Perform(make_tuple(2))); -} - -// Tests using WithArgs and WithArg with an action that takes 1 argument. +// Tests using WithArgs and with an action that takes 1 argument. TEST(WithArgsTest, OneArg) { Action a = WithArgs<1>(Invoke(Unary)); // NOLINT EXPECT_TRUE(a.Perform(make_tuple(1.5, -1))); EXPECT_FALSE(a.Perform(make_tuple(1.5, 1))); - - // Also tests the synonym WithArg. - Action b = WithArg<1>(Invoke(Unary)); // NOLINT - EXPECT_TRUE(a.Perform(make_tuple(1.5, -1))); - EXPECT_FALSE(a.Perform(make_tuple(1.5, 1))); - } // Tests using WithArgs with an action that takes 2 arguments. @@ -1383,56 +974,6 @@ TEST(ActionPnMacroTest, CanExplicitlyInstantiateWithReferenceTypes) { EXPECT_EQ(55, a.Perform(empty)); } -TEST(ReturnArgActionTest, WorksForOneArgIntArg0) { - const Action a = ReturnArg<0>(); - EXPECT_EQ(5, a.Perform(make_tuple(5))); -} - -TEST(ReturnArgActionTest, WorksForMultiArgBoolArg0) { - const Action a = ReturnArg<0>(); - EXPECT_TRUE(a.Perform(make_tuple(true, false, false))); -} - -TEST(ReturnArgActionTest, WorksForMultiArgStringArg2) { - const Action a = ReturnArg<2>(); - EXPECT_EQ("seven", a.Perform(make_tuple(5, 6, string("seven"), 8))); -} - -TEST(SaveArgActionTest, WorksForSameType) { - int result = 0; - const Action a1 = SaveArg<0>(&result); - a1.Perform(make_tuple(5)); - EXPECT_EQ(5, result); -} - -TEST(SaveArgActionTest, WorksForCompatibleType) { - int result = 0; - const Action a1 = SaveArg<1>(&result); - a1.Perform(make_tuple(true, 'a')); - EXPECT_EQ('a', result); -} - -TEST(SetArgRefereeActionTest, WorksForSameType) { - int value = 0; - const Action a1 = SetArgReferee<0>(1); - a1.Perform(tuple(value)); - EXPECT_EQ(1, value); -} - -TEST(SetArgRefereeActionTest, WorksForCompatibleType) { - int value = 0; - const Action a1 = SetArgReferee<1>('a'); - a1.Perform(tuple(0, value)); - EXPECT_EQ('a', value); -} - -TEST(SetArgRefereeActionTest, WorksWithExtraArguments) { - int value = 0; - const Action a1 = SetArgReferee<2>('a'); - a1.Perform(tuple(true, 0, value, "hi")); - EXPECT_EQ('a', value); -} - class NullaryConstructorClass { public: NullaryConstructorClass() : value_(123) {} @@ -1497,64 +1038,6 @@ TEST(ReturnNewTest, ConstructorThatTakes10Arguments) { delete c; } -// A class that can be used to verify that its destructor is called: it will set -// the bool provided to the constructor to true when destroyed. -class DeletionTester { - public: - explicit DeletionTester(bool* is_deleted) - : is_deleted_(is_deleted) { - // Make sure the bit is set to false. - *is_deleted_ = false; - } - - ~DeletionTester() { - *is_deleted_ = true; - } - - private: - bool* is_deleted_; -}; - -TEST(DeleteArgActionTest, OneArg) { - bool is_deleted = false; - DeletionTester* t = new DeletionTester(&is_deleted); - const Action a1 = DeleteArg<0>(); // NOLINT - EXPECT_FALSE(is_deleted); - a1.Perform(make_tuple(t)); - EXPECT_TRUE(is_deleted); -} - -TEST(DeleteArgActionTest, TenArgs) { - bool is_deleted = false; - DeletionTester* t = new DeletionTester(&is_deleted); - const Action a1 = DeleteArg<9>(); - EXPECT_FALSE(is_deleted); - a1.Perform(make_tuple(true, 5, 6, CharPtr("hi"), false, 7, 8, 9, 10, t)); - EXPECT_TRUE(is_deleted); -} - -#if GTEST_HAS_EXCEPTIONS - -TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) { - const Action a = Throw('a'); - EXPECT_THROW(a.Perform(make_tuple(0)), char); -} - -class MyException {}; - -TEST(ThrowActionTest, ThrowsGivenExceptionInNonVoidFunction) { - const Action a = Throw(MyException()); - EXPECT_THROW(a.Perform(make_tuple('0')), MyException); -} - -TEST(ThrowActionTest, ThrowsGivenExceptionInNullaryFunction) { - const Action a = Throw(MyException()); - EXPECT_THROW(a.Perform(make_tuple()), MyException); -} - -#endif // GTEST_HAS_EXCEPTIONS - // Tests that ACTION_TEMPLATE works when there is no value parameter. ACTION_TEMPLATE(CreateNew, HAS_1_TEMPLATE_PARAMS(typename, T), diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc new file mode 100644 index 00000000..95077768 --- /dev/null +++ b/test/gmock-more-actions_test.cc @@ -0,0 +1,796 @@ +// 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 tests the built-in actions in gmock-more-actions.h. + +#include + +#include +#include +#include +#include +#include + +namespace testing { +namespace gmock_more_actions_test { + +using ::std::plus; +using ::std::string; +using ::std::tr1::get; +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +using ::std::tr1::tuple_element; +using testing::_; +using testing::Action; +using testing::ActionInterface; +using testing::DeleteArg; +using testing::Invoke; +using testing::Return; +using testing::ReturnArg; +using testing::SaveArg; +using testing::SetArgReferee; +using testing::SetArgumentPointee; +using testing::StaticAssertTypeEq; +using testing::Unused; +using testing::WithArg; +using testing::WithoutArgs; + +// Sample functions and functors for testing Invoke() and etc. +int Nullary() { return 1; } + +class NullaryFunctor { + public: + int operator()() { return 2; } +}; + +bool g_done = false; +void VoidNullary() { g_done = true; } + +class VoidNullaryFunctor { + public: + void operator()() { g_done = true; } +}; + +bool Unary(int x) { return x < 0; } + +const char* Plus1(const char* s) { return s + 1; } + +void VoidUnary(int n) { g_done = true; } + +bool ByConstRef(const string& s) { return s == "Hi"; } + +const double g_double = 0; +bool ReferencesGlobalDouble(const double& x) { return &x == &g_double; } + +string ByNonConstRef(string& s) { return s += "+"; } // NOLINT + +struct UnaryFunctor { + int operator()(bool x) { return x ? 1 : -1; } +}; + +const char* Binary(const char* input, short n) { return input + n; } // NOLINT + +void VoidBinary(int, char) { g_done = true; } + +int Ternary(int x, char y, short z) { return x + y + z; } // NOLINT + +void VoidTernary(int, char, bool) { g_done = true; } + +int SumOf4(int a, int b, int c, int d) { return a + b + c + d; } + +int SumOfFirst2(int a, int b, Unused, Unused) { return a + b; } + +void VoidFunctionWithFourArguments(char, int, float, double) { g_done = true; } + +string Concat4(const char* s1, const char* s2, const char* s3, + const char* s4) { + return string(s1) + s2 + s3 + s4; +} + +int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } + +struct SumOf5Functor { + int operator()(int a, int b, int c, int d, int e) { + return a + b + c + d + e; + } +}; + +string Concat5(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5) { + return string(s1) + s2 + s3 + s4 + s5; +} + +int SumOf6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +struct SumOf6Functor { + int operator()(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; + } +}; + +string Concat6(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6) { + return string(s1) + s2 + s3 + s4 + s5 + s6; +} + +string Concat7(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7; +} + +string Concat8(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8; +} + +string Concat9(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; +} + +string Concat10(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9, + const char* s10) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; +} + +class Foo { + public: + Foo() : value_(123) {} + + int Nullary() const { return value_; } + + short Unary(long x) { return static_cast(value_ + x); } // NOLINT + + string Binary(const string& str, char c) const { return str + c; } + + int Ternary(int x, bool y, char z) { return value_ + x + y*z; } + + int SumOf4(int a, int b, int c, int d) const { + return a + b + c + d + value_; + } + + int SumOfLast2(Unused, Unused, int a, int b) const { return a + b; } + + int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } + + int SumOf6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; + } + + string Concat7(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7; + } + + string Concat8(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8; + } + + string Concat9(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; + } + + string Concat10(const char* s1, const char* s2, const char* s3, + const char* s4, const char* s5, const char* s6, + const char* s7, const char* s8, const char* s9, + const char* s10) { + return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; + } + private: + int value_; +}; + +// Tests using Invoke() with a nullary function. +TEST(InvokeTest, Nullary) { + Action a = Invoke(Nullary); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple())); +} + +// Tests using Invoke() with a unary function. +TEST(InvokeTest, Unary) { + Action a = Invoke(Unary); // NOLINT + EXPECT_FALSE(a.Perform(make_tuple(1))); + EXPECT_TRUE(a.Perform(make_tuple(-1))); +} + +// Tests using Invoke() with a binary function. +TEST(InvokeTest, Binary) { + Action a = Invoke(Binary); // NOLINT + const char* p = "Hello"; + EXPECT_EQ(p + 2, a.Perform(make_tuple(p, 2))); +} + +// Tests using Invoke() with a ternary function. +TEST(InvokeTest, Ternary) { + Action a = Invoke(Ternary); // NOLINT + EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', 3))); +} + +// Tests using Invoke() with a 4-argument function. +TEST(InvokeTest, FunctionThatTakes4Arguments) { + Action a = Invoke(SumOf4); // NOLINT + EXPECT_EQ(1234, a.Perform(make_tuple(1000, 200, 30, 4))); +} + +// Tests using Invoke() with a 5-argument function. +TEST(InvokeTest, FunctionThatTakes5Arguments) { + Action a = Invoke(SumOf5); // NOLINT + EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5))); +} + +// Tests using Invoke() with a 6-argument function. +TEST(InvokeTest, FunctionThatTakes6Arguments) { + Action a = Invoke(SumOf6); // NOLINT + EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); +} + +// A helper that turns the type of a C-string literal from const +// char[N] to const char*. +inline const char* CharPtr(const char* s) { return s; } + +// Tests using Invoke() with a 7-argument function. +TEST(InvokeTest, FunctionThatTakes7Arguments) { + Action a = + Invoke(Concat7); + EXPECT_EQ("1234567", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7")))); +} + +// Tests using Invoke() with a 8-argument function. +TEST(InvokeTest, FunctionThatTakes8Arguments) { + Action a = + Invoke(Concat8); + EXPECT_EQ("12345678", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8")))); +} + +// Tests using Invoke() with a 9-argument function. +TEST(InvokeTest, FunctionThatTakes9Arguments) { + Action a = Invoke(Concat9); + EXPECT_EQ("123456789", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9")))); +} + +// Tests using Invoke() with a 10-argument function. +TEST(InvokeTest, FunctionThatTakes10Arguments) { + Action a = Invoke(Concat10); + EXPECT_EQ("1234567890", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9"), + CharPtr("0")))); +} + +// Tests using Invoke() with functions with parameters declared as Unused. +TEST(InvokeTest, FunctionWithUnusedParameters) { + Action a1 = + Invoke(SumOfFirst2); + EXPECT_EQ(12, a1.Perform(make_tuple(10, 2, 5.6, CharPtr("hi")))); + + Action a2 = + Invoke(SumOfFirst2); + EXPECT_EQ(23, a2.Perform(make_tuple(20, 3, true, static_cast(NULL)))); +} + +// Tests using Invoke() with methods with parameters declared as Unused. +TEST(InvokeTest, MethodWithUnusedParameters) { + Foo foo; + Action a1 = + Invoke(&foo, &Foo::SumOfLast2); + EXPECT_EQ(12, a1.Perform(make_tuple(CharPtr("hi"), true, 10, 2))); + + Action a2 = + Invoke(&foo, &Foo::SumOfLast2); + EXPECT_EQ(23, a2.Perform(make_tuple('a', 2.5, 20, 3))); +} + +// Tests using Invoke() with a functor. +TEST(InvokeTest, Functor) { + Action a = Invoke(plus()); // NOLINT + EXPECT_EQ(3, a.Perform(make_tuple(1, 2))); +} + +// Tests using Invoke(f) as an action of a compatible type. +TEST(InvokeTest, FunctionWithCompatibleType) { + Action a = Invoke(SumOf4); // NOLINT + EXPECT_EQ(4321, a.Perform(make_tuple(4000, 300, 20, true))); +} + +#if GMOCK_HAS_GOOGLE3_CALLBACK_ + +// Tests IgnoreResult(Invoke(result_callback)). +TEST(InvokeTest, IgnoreResultOfResultCallback) { + ResultCallback* c = NewPermanentCallback(Nullary); + Action a = IgnoreResult(Invoke(c)); + a.Perform(make_tuple()); +} + +// Tests IgnoreResult(Invoke(result_callback4)). +TEST(InvokeTest, IgnoreResultOfResultCallback4) { + ResultCallback4* c = + NewPermanentCallback(SumOf4); + Action a = IgnoreResult(Invoke(c)); + a.Perform(make_tuple(1, 2, 3, 4)); +} + +#endif // GMOCK_HAS_GOOGLE3_CALLBACK_ + +// Tests using Invoke() with an object pointer and a method pointer. + +// Tests using Invoke() with a nullary method. +TEST(InvokeMethodTest, Nullary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Nullary); // NOLINT + EXPECT_EQ(123, a.Perform(make_tuple())); +} + +// Tests using Invoke() with a unary method. +TEST(InvokeMethodTest, Unary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Unary); // NOLINT + EXPECT_EQ(4123, a.Perform(make_tuple(4000))); +} + +// Tests using Invoke() with a binary method. +TEST(InvokeMethodTest, Binary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Binary); + string s("Hell"); + EXPECT_EQ("Hello", a.Perform(make_tuple(s, 'o'))); +} + +// Tests using Invoke() with a ternary method. +TEST(InvokeMethodTest, Ternary) { + Foo foo; + Action a = Invoke(&foo, &Foo::Ternary); // NOLINT + EXPECT_EQ(1124, a.Perform(make_tuple(1000, true, 1))); +} + +// Tests using Invoke() with a 4-argument method. +TEST(InvokeMethodTest, MethodThatTakes4Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::SumOf4); // NOLINT + EXPECT_EQ(1357, a.Perform(make_tuple(1000, 200, 30, 4))); +} + +// Tests using Invoke() with a 5-argument method. +TEST(InvokeMethodTest, MethodThatTakes5Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::SumOf5); // NOLINT + EXPECT_EQ(12345, a.Perform(make_tuple(10000, 2000, 300, 40, 5))); +} + +// Tests using Invoke() with a 6-argument method. +TEST(InvokeMethodTest, MethodThatTakes6Arguments) { + Foo foo; + Action a = // NOLINT + Invoke(&foo, &Foo::SumOf6); + EXPECT_EQ(123456, a.Perform(make_tuple(100000, 20000, 3000, 400, 50, 6))); +} + +// Tests using Invoke() with a 7-argument method. +TEST(InvokeMethodTest, MethodThatTakes7Arguments) { + Foo foo; + Action a = + Invoke(&foo, &Foo::Concat7); + EXPECT_EQ("1234567", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7")))); +} + +// Tests using Invoke() with a 8-argument method. +TEST(InvokeMethodTest, MethodThatTakes8Arguments) { + Foo foo; + Action a = + Invoke(&foo, &Foo::Concat8); + EXPECT_EQ("12345678", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8")))); +} + +// Tests using Invoke() with a 9-argument method. +TEST(InvokeMethodTest, MethodThatTakes9Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::Concat9); + EXPECT_EQ("123456789", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9")))); +} + +// Tests using Invoke() with a 10-argument method. +TEST(InvokeMethodTest, MethodThatTakes10Arguments) { + Foo foo; + Action a = Invoke(&foo, &Foo::Concat10); + EXPECT_EQ("1234567890", + a.Perform(make_tuple(CharPtr("1"), CharPtr("2"), CharPtr("3"), + CharPtr("4"), CharPtr("5"), CharPtr("6"), + CharPtr("7"), CharPtr("8"), CharPtr("9"), + CharPtr("0")))); +} + +// Tests using Invoke(f) as an action of a compatible type. +TEST(InvokeMethodTest, MethodWithCompatibleType) { + Foo foo; + Action a = // NOLINT + Invoke(&foo, &Foo::SumOf4); + EXPECT_EQ(4444, a.Perform(make_tuple(4000, 300, 20, true))); +} + +#if GMOCK_HAS_GOOGLE3_CALLBACK_ + +// We don't have dedicated tests to verify that Invoke(callback) and +// InvokeWithoutArgs(callback) delete the callback argument. Instead, +// we rely on the heap checker linked in this test program to do that. + +// Tests that Invoke(non-permanent-callback) kills the process. +TEST(InvokeCallbackDeathTest, RejectsNonPermanentCallback) { + EXPECT_DEATH({ + Action a = Invoke(NewCallback(Nullary)); // NOLINT + }, ""); +} + +// Tests using Invoke() with a nullary callback. +TEST(InvokeCallbackTest, Nullary) { + // Tests using Invoke(callback) as an action of the exact type. + Action a = Invoke(NewPermanentCallback(Nullary)); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple())); + + // Tests using Invoke(callback) as an action of a compatible type. + Action a2 = Invoke(NewPermanentCallback(Nullary)); // NOLINT + EXPECT_TRUE(a2.Perform(make_tuple())); + + // Tests using Invoke() on a callback that returns void. + Action a3 = Invoke(NewPermanentCallback(VoidNullary)); // NOLINT + g_done = false; + a3.Perform(make_tuple()); + EXPECT_TRUE(g_done); +} + +// Tests using Invoke() with a unary callback. +TEST(InvokeCallbackTest, Unary) { + // Tests using Invoke(callback1) as an action of the exact type. + Action a = Invoke(NewPermanentCallback(Unary)); // NOLINT + EXPECT_FALSE(a.Perform(make_tuple(1))); + EXPECT_TRUE(a.Perform(make_tuple(-1))); + + // Tests using Invoke(callback1) as an action of a compatible type. + Action a2 = Invoke(NewPermanentCallback(Unary)); // NOLINT + EXPECT_EQ(0, a2.Perform(make_tuple(1L))); + EXPECT_EQ(1, a2.Perform(make_tuple(-1L))); + + // Tests using Invoke() on a callback that returns void. + Action a3 = Invoke(NewPermanentCallback(VoidUnary)); // NOLINT + g_done = false; + a3.Perform(make_tuple('a')); + EXPECT_TRUE(g_done); +} + +// Tests using Invoke() with a binary callback. +TEST(InvokeCallbackTest, Binary) { + // Tests using Invoke(callback2) as an action of the exact type. + Action a = // NOLINT + Invoke(NewPermanentCallback(Binary)); + const char* p = "Hello"; + EXPECT_EQ(p + 2, a.Perform(make_tuple(p, 2))); + + // Tests using Invoke(callback2) as an action of a compatible type. + Action a2 = // NOLINT + Invoke(NewPermanentCallback(Binary)); + char str[] = "Hello"; + EXPECT_TRUE(a2.Perform(make_tuple(str, 2))); + + // Tests using Invoke() on a callback that returns void. + Action a3 = + Invoke(NewPermanentCallback(VoidBinary)); // NOLINT + g_done = false; + a3.Perform(make_tuple('a', 'b')); + EXPECT_TRUE(g_done); +} + +// Tests using Invoke() with a ternary callback. +TEST(InvokeCallbackTest, Ternary) { + // Tests using Invoke(callback3) as an action of the exact type. + Action a = // NOLINT + Invoke(NewPermanentCallback(Ternary)); + EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', 3))); + + // Tests using Invoke(callback3) as an action of a compatible type. + Action a2 = // NOLINT + Invoke(NewPermanentCallback(Ternary)); + EXPECT_EQ(6, a2.Perform(make_tuple('\1', 2, 3))); + + // Tests using Invoke() on a callback that returns void. + Action a3 = + Invoke(NewPermanentCallback(VoidTernary)); // NOLINT + g_done = false; + a3.Perform(make_tuple('a', 'b', true)); + EXPECT_TRUE(g_done); +} + +// Tests using Invoke() with a 4-argument callback. +TEST(InvokeCallbackTest, CallbackThatTakes4Arguments) { + // Tests using Invoke(callback4) as an action of the exact type. + Action a = // NOLINT + Invoke(NewPermanentCallback(SumOf4)); + EXPECT_EQ(1234, a.Perform(make_tuple(1000, 200, 30, 4))); + + // Tests using Invoke(callback4) as an action of a compatible type. + Action a2 = // NOLINT + Invoke(NewPermanentCallback(SumOf4)); + EXPECT_EQ(4321, a2.Perform(make_tuple(4000, 300, 20, true))); + + // Tests using Invoke() on a callback that returns void. + Action a3 = + Invoke(NewPermanentCallback(VoidFunctionWithFourArguments)); // NOLINT + g_done = false; + a3.Perform(make_tuple('a', 'b', 0, 1)); + EXPECT_TRUE(g_done); +} + +#endif // GMOCK_HAS_GOOGLE3_CALLBACK_ + +// Tests using WithoutArgs with an action that takes no argument. +TEST(WithoutArgsTest, NoArg) { + Action a = WithoutArgs(Invoke(Nullary)); // NOLINT + EXPECT_EQ(1, a.Perform(make_tuple(2))); +} + +// Tests using WithArg with an action that takes 1 argument. +TEST(WithArgTest, OneArg) { + Action b = WithArg<1>(Invoke(Unary)); // NOLINT + EXPECT_TRUE(b.Perform(make_tuple(1.5, -1))); + EXPECT_FALSE(b.Perform(make_tuple(1.5, 1))); +} + +TEST(ReturnArgActionTest, WorksForOneArgIntArg0) { + const Action a = ReturnArg<0>(); + EXPECT_EQ(5, a.Perform(make_tuple(5))); +} + +TEST(ReturnArgActionTest, WorksForMultiArgBoolArg0) { + const Action a = ReturnArg<0>(); + EXPECT_TRUE(a.Perform(make_tuple(true, false, false))); +} + +TEST(ReturnArgActionTest, WorksForMultiArgStringArg2) { + const Action a = ReturnArg<2>(); + EXPECT_EQ("seven", a.Perform(make_tuple(5, 6, string("seven"), 8))); +} + +TEST(SaveArgActionTest, WorksForSameType) { + int result = 0; + const Action a1 = SaveArg<0>(&result); + a1.Perform(make_tuple(5)); + EXPECT_EQ(5, result); +} + +TEST(SaveArgActionTest, WorksForCompatibleType) { + int result = 0; + const Action a1 = SaveArg<1>(&result); + a1.Perform(make_tuple(true, 'a')); + EXPECT_EQ('a', result); +} + +TEST(SetArgRefereeActionTest, WorksForSameType) { + int value = 0; + const Action a1 = SetArgReferee<0>(1); + a1.Perform(tuple(value)); + EXPECT_EQ(1, value); +} + +TEST(SetArgRefereeActionTest, WorksForCompatibleType) { + int value = 0; + const Action a1 = SetArgReferee<1>('a'); + a1.Perform(tuple(0, value)); + EXPECT_EQ('a', value); +} + +TEST(SetArgRefereeActionTest, WorksWithExtraArguments) { + int value = 0; + const Action a1 = SetArgReferee<2>('a'); + a1.Perform(tuple(true, 0, value, "hi")); + EXPECT_EQ('a', value); +} + +// A class that can be used to verify that its destructor is called: it will set +// the bool provided to the constructor to true when destroyed. +class DeletionTester { + public: + explicit DeletionTester(bool* is_deleted) + : is_deleted_(is_deleted) { + // Make sure the bit is set to false. + *is_deleted_ = false; + } + + ~DeletionTester() { + *is_deleted_ = true; + } + + private: + bool* is_deleted_; +}; + +TEST(DeleteArgActionTest, OneArg) { + bool is_deleted = false; + DeletionTester* t = new DeletionTester(&is_deleted); + const Action a1 = DeleteArg<0>(); // NOLINT + EXPECT_FALSE(is_deleted); + a1.Perform(make_tuple(t)); + EXPECT_TRUE(is_deleted); +} + +TEST(DeleteArgActionTest, TenArgs) { + bool is_deleted = false; + DeletionTester* t = new DeletionTester(&is_deleted); + const Action a1 = DeleteArg<9>(); + EXPECT_FALSE(is_deleted); + a1.Perform(make_tuple(true, 5, 6, CharPtr("hi"), false, 7, 8, 9, 10, t)); + EXPECT_TRUE(is_deleted); +} + +#if GTEST_HAS_EXCEPTIONS + +TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) { + const Action a = Throw('a'); + EXPECT_THROW(a.Perform(make_tuple(0)), char); +} + +class MyException {}; + +TEST(ThrowActionTest, ThrowsGivenExceptionInNonVoidFunction) { + const Action a = Throw(MyException()); + EXPECT_THROW(a.Perform(make_tuple('0')), MyException); +} + +TEST(ThrowActionTest, ThrowsGivenExceptionInNullaryFunction) { + const Action a = Throw(MyException()); + EXPECT_THROW(a.Perform(make_tuple()), MyException); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests that SetArrayArgument(first, last) sets the elements of the array +// pointed to by the N-th (0-based) argument to values in range [first, last). +TEST(SetArrayArgumentTest, SetsTheNthArray) { + typedef void MyFunction(bool, int*, char*); + int numbers[] = { 1, 2, 3 }; + Action a = SetArrayArgument<1>(numbers, numbers + 3); + + int n[4] = {}; + int* pn = n; + char ch[4] = {}; + char* pch = ch; + a.Perform(make_tuple(true, pn, pch)); + EXPECT_EQ(1, n[0]); + EXPECT_EQ(2, n[1]); + EXPECT_EQ(3, n[2]); + EXPECT_EQ(0, n[3]); + EXPECT_EQ('\0', ch[0]); + EXPECT_EQ('\0', ch[1]); + EXPECT_EQ('\0', ch[2]); + EXPECT_EQ('\0', ch[3]); + + // Tests first and last are iterators. + std::string letters = "abc"; + a = SetArrayArgument<2>(letters.begin(), letters.end()); + std::fill_n(n, 4, 0); + std::fill_n(ch, 4, '\0'); + a.Perform(make_tuple(true, pn, pch)); + EXPECT_EQ(0, n[0]); + EXPECT_EQ(0, n[1]); + EXPECT_EQ(0, n[2]); + EXPECT_EQ(0, n[3]); + EXPECT_EQ('a', ch[0]); + EXPECT_EQ('b', ch[1]); + EXPECT_EQ('c', ch[2]); + EXPECT_EQ('\0', ch[3]); +} + +// Tests SetArrayArgument(first, last) where first == last. +TEST(SetArrayArgumentTest, SetsTheNthArrayWithEmptyRange) { + typedef void MyFunction(bool, int*); + int numbers[] = { 1, 2, 3 }; + Action a = SetArrayArgument<1>(numbers, numbers); + + int n[4] = {}; + int* pn = n; + a.Perform(make_tuple(true, pn)); + EXPECT_EQ(0, n[0]); + EXPECT_EQ(0, n[1]); + EXPECT_EQ(0, n[2]); + EXPECT_EQ(0, n[3]); +} + +// Tests SetArrayArgument(first, last) where *first is convertible +// (but not equal) to the argument type. +TEST(SetArrayArgumentTest, SetsTheNthArrayWithConvertibleType) { + typedef void MyFunction(bool, char*); + int codes[] = { 97, 98, 99 }; + Action a = SetArrayArgument<1>(codes, codes + 3); + + char ch[4] = {}; + char* pch = ch; + a.Perform(make_tuple(true, pch)); + EXPECT_EQ('a', ch[0]); + EXPECT_EQ('b', ch[1]); + EXPECT_EQ('c', ch[2]); + EXPECT_EQ('\0', ch[3]); +} + +// Test SetArrayArgument(first, last) with iterator as argument. +TEST(SetArrayArgumentTest, SetsTheNthArrayWithIteratorArgument) { + typedef void MyFunction(bool, std::back_insert_iterator); + std::string letters = "abc"; + Action a = SetArrayArgument<1>(letters.begin(), letters.end()); + + std::string s; + a.Perform(make_tuple(true, back_inserter(s))); + EXPECT_EQ(letters, s); +} + +} // namespace gmock_generated_actions_test +} // namespace testing -- cgit v1.2.3 From 9571b28675a5a602ed3c8a7acf270d03aca69c96 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 7 Aug 2009 07:15:56 +0000 Subject: Removes duplicated definition of SetArgumentPointee (by Vlad Losev); Makes gmock compilable on platforms that don't have ::abort() (by Acadeli Checa); Fixes compatibility with Symbian's STLport (by Acadeli Checa). --- include/gmock/gmock-actions.h | 43 ------------------------------------- include/gmock/internal/gmock-port.h | 2 +- src/gmock-internal-utils.cc | 2 +- src/gmock-spec-builders.cc | 18 +++++++++------- test/gmock-spec-builders_test.cc | 15 +++++++++++++ 5 files changed, 27 insertions(+), 53 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 49d5532d..c8edc8ab 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -669,39 +669,6 @@ class SetArgumentPointeeAction { const internal::linked_ptr proto_; }; -// Implements the SetArrayArgument(first, last) action for any function -// whose N-th argument (0-based) is a pointer or iterator to a type that can be -// implicitly converted from *first. -template -class SetArrayArgumentAction { - public: - // Constructs an action that sets the variable pointed to by the - // N-th function argument to 'value'. - explicit SetArrayArgumentAction(InputIterator first, InputIterator last) - : first_(first), last_(last) { - } - - template - void Perform(const ArgumentTuple& args) const { - CompileAssertTypesEqual(); - - // Microsoft compiler deprecates ::std::copy, so we want to suppress warning - // 4996 (Function call with parameters that may be unsafe) there. -#if GTEST_OS_WINDOWS -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. -#endif // GTEST_OS_WINDOWS - ::std::copy(first_, last_, ::std::tr1::get(args)); -#if GTEST_OS_WINDOWS -#pragma warning(pop) // Restores the warning state. -#endif // GTEST_OS_WINDOWS - } - - private: - const InputIterator first_; - const InputIterator last_; -}; - // 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 @@ -939,16 +906,6 @@ SetArgumentPointee(const T& x) { N, T, internal::IsAProtocolMessage::value>(x)); } -// Creates an action that sets the elements of the array pointed to by the N-th -// (0-based) function argument, which can be either a pointer or an iterator, -// to the values of the elements in the source range [first, last). -template -PolymorphicAction > -SetArrayArgument(InputIterator first, InputIterator last) { - return MakePolymorphicAction(internal::SetArrayArgumentAction< - N, InputIterator>(first, last)); -} - // Creates an action that sets a pointer referent to a given value. template PolymorphicAction > Assign(T1* ptr, T2 val) { diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 9ee8f728..5b00a41a 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -274,7 +274,7 @@ class GMockCheckProvider { } ~GMockCheckProvider() { ::std::cerr << ::std::endl; - abort(); + posix::Abort(); } ::std::ostream& GetStream() { return ::std::cerr; } }; diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 0e693c70..e72e019b 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -80,7 +80,7 @@ class GoogleTestFailureReporter : public FailureReporterInterface { AssertHelper(type == FATAL ? TPRT_FATAL_FAILURE : TPRT_NONFATAL_FAILURE, file, line, message.c_str()) = Message(); if (type == FATAL) { - abort(); + posix::Abort(); } } }; diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 00d16918..94ba24bb 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -186,7 +186,9 @@ class MockObjectRegistry { // object alive. Therefore we report any living object as test // failure, unless the user explicitly asked us to ignore it. ~MockObjectRegistry() { - using ::std::cout; + + // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is + // a macro. if (!GMOCK_FLAG(catch_leaked_mocks)) return; @@ -199,24 +201,24 @@ class MockObjectRegistry { // TODO(wan@google.com): Print the type of the leaked object. // This can help the user identify the leaked object. - cout << "\n"; + std::cout << "\n"; const MockObjectState& state = it->second; internal::FormatFileLocation( - state.first_used_file, state.first_used_line, &cout); - cout << " ERROR: this mock object"; + state.first_used_file, state.first_used_line, &std::cout); + std::cout << " ERROR: this mock object"; if (state.first_used_test != "") { - cout << " (used in test " << state.first_used_test_case << "." + std::cout << " (used in test " << state.first_used_test_case << "." << state.first_used_test << ")"; } - cout << " should be deleted but never is. Its address is @" + std::cout << " should be deleted but never is. Its address is @" << it->first << "."; leaked_count++; } if (leaked_count > 0) { - cout << "\nERROR: " << leaked_count + std::cout << "\nERROR: " << leaked_count << " leaked mock " << (leaked_count == 1 ? "object" : "objects") << " found at program exit.\n"; - cout.flush(); + std::cout.flush(); ::std::cerr.flush(); // RUN_ALL_TESTS() has already returned when this destructor is // called. Therefore we cannot use the normal Google Test diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index f6c3141b..de05c574 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1429,6 +1429,8 @@ TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) { a.DoA(2); } +#if GTEST_HAS_DEATH_TEST + // Calls must be in strict order when specified so. TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { MockA a; @@ -1496,6 +1498,8 @@ TEST(AfterTest, CanBeUsedWithInSequence) { a.ReturnResult(3); } +#endif // GTEST_HAS_DEATH_TEST + // .After() can be called multiple times. TEST(AfterTest, CanBeCalledManyTimes) { MockA a; @@ -1532,6 +1536,8 @@ TEST(AfterTest, AcceptsUpToFiveArguments) { a.DoA(6); } +#if GTEST_HAS_DEATH_TEST + // .After() allows input to contain duplicated Expectations. TEST(AfterTest, AcceptsDuplicatedInput) { MockA a; @@ -1551,6 +1557,8 @@ TEST(AfterTest, AcceptsDuplicatedInput) { a.ReturnResult(3); } +#endif // GTEST_HAS_DEATH_TEST + // An Expectation added to an ExpectationSet after it has been used in // an .After() has no effect. TEST(AfterTest, ChangesToExpectationSetHaveNoEffectAfterwards) { @@ -2327,7 +2335,14 @@ void Helper(MockC* c) { } // namespace +// Allows the user to define his own main and then invoke gmock_main +// from it. This might be necessary on some platforms which require +// specific setup and teardown. +#if GMOCK_RENAME_MAIN +int gmock_main(int argc, char **argv) { +#else int main(int argc, char **argv) { +#endif // GMOCK_RENAME_MAIN testing::InitGoogleMock(&argc, argv); // Ensures that the tests pass no matter what value of -- cgit v1.2.3 From 0ea67f88aea208e7ef13c91b374b352679beab38 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 14 Aug 2009 04:50:02 +0000 Subject: Improves protobuf print format. --- include/gmock/gmock-printers.h | 15 +++++++++++---- test/gmock-internal-utils_test.cc | 7 +++++++ test/gmock-printers_test.cc | 25 ++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 561de3d9..69eee120 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -129,14 +129,21 @@ class TypeWithoutFormatter { sizeof(value), os); } }; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { - // Both ProtocolMessage and proto2::Message have the - // ShortDebugString() method, so the same implementation works for - // both. - ::std::operator<<(*os, "<" + value.ShortDebugString() + ">"); + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + ::std::operator<<(*os, "<" + pretty_str + ">"); } }; diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 20289288..c949dd75 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -48,6 +48,12 @@ #include // For ssize_t. NOLINT #endif +class ProtocolMessage; + +namespace proto2 { +class Message; +} // namespace proto2 + namespace testing { namespace internal { @@ -384,6 +390,7 @@ TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { // Tests that IsAProtocolMessage::value is true when T is // ProtocolMessage or a sub-class of it. TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { + EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); EXPECT_TRUE(IsAProtocolMessage::value); #if GMOCK_HAS_PROTOBUF_ EXPECT_TRUE(IsAProtocolMessage::value); diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 8c03ec46..af2e83c0 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -919,12 +919,31 @@ TEST(PrintProtocolMessageTest, PrintsShortDebugString) { EXPECT_EQ("", Print(msg)); } -// Tests printing a proto2 message. -TEST(PrintProto2MessageTest, PrintsShortDebugString) { +// Tests printing a short proto2 message. +TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) { testing::internal::FooMessage msg; msg.set_int_field(2); + msg.set_string_field("hello"); EXPECT_PRED2(RE::FullMatch, Print(msg), - ""); + ""); +} + +// Tests printing a long proto2 message. +TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong) { + testing::internal::FooMessage msg; + msg.set_int_field(2); + msg.set_string_field("hello"); + msg.add_names("peter"); + msg.add_names("paul"); + msg.add_names("mary"); + EXPECT_PRED2(RE::FullMatch, Print(msg), + "<\n" + "int_field:\\s*2\n" + "string_field:\\s*\"hello\"\n" + "names:\\s*\"peter\"\n" + "names:\\s*\"paul\"\n" + "names:\\s*\"mary\"\n" + ">"); } #endif // GMOCK_HAS_PROTOBUF_ -- cgit v1.2.3 From 2b43a9ecd16edc1ec55429967e0f2de1aaf8e8bb Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 31 Aug 2009 23:51:23 +0000 Subject: Adds mutable_impl() and impl() to PolymorphicMatcher (by Zhanyong Wan); Enables gMock to compile with VC 7.1 (by Vlad Losev). --- include/gmock/gmock-matchers.h | 11 +++++++- include/gmock/internal/gmock-port.h | 30 +++------------------- src/gmock-printers.cc | 6 +++-- test/gmock-matchers_test.cc | 50 ++++++++++++++++++++++++++++--------- test/gmock-spec-builders_test.cc | 18 ++++++------- 5 files changed, 65 insertions(+), 50 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 9e97866a..7266fba7 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -236,6 +236,14 @@ class PolymorphicMatcher { public: explicit PolymorphicMatcher(const Impl& impl) : impl_(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_)); @@ -273,11 +281,12 @@ class PolymorphicMatcher { // doesn't need to customize it. ExplainMatchResultTo(impl_, x, os); } + private: const Impl impl_; }; - const Impl impl_; + Impl impl_; }; // Creates a matcher from its implementation. This is easier to use diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 5b00a41a..6bee9966 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -75,33 +75,11 @@ namespace testing { namespace internal { -// For Windows, check the compiler version. At least VS 2005 SP1 is +// For MS Visual C++, check the compiler version. At least VS 2003 is // required to compile Google Mock. -#if GTEST_OS_WINDOWS - -#if _MSC_VER < 1400 -#error "At least Visual Studio 2005 SP1 is required to compile Google Mock." -#elif _MSC_VER == 1400 - -// Unfortunately there is no unique _MSC_VER number for SP1. So for VS 2005 -// we have to check if it has SP1 by checking whether a bug fixed in SP1 -// is present. The bug in question is -// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101702 -// where the compiler incorrectly reports sizeof(poiter to an array). - -class TestForSP1 { - private: // GCC complains if x_ is used by sizeof before defining it. - static char x_[100]; - // VS 2005 RTM incorrectly reports sizeof(&x) as 100, and that value - // is used to trigger 'invalid negative array size' error. If you - // see this error, upgrade to VS 2005 SP1 since Google Mock will not - // compile in VS 2005 RTM. - static char Google_Mock_requires_Visual_Studio_2005_SP1_or_later_to_compile_[ - sizeof(&x_) != 100 ? 1 : -1]; -}; - -#endif // _MSC_VER -#endif // GTEST_OS_WINDOWS +#if defined(_MSC_VER) && _MSC_VER < 1310 +#error "At least Visual C++ 2003 (7.1) is required to compile Google Mock." +#endif // Use implicit_cast as a safe version of static_cast or const_cast // for upcasting in the type hierarchy (i.e. casting a pointer to Foo diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc index 922a7b2d..0473dba1 100644 --- a/src/gmock-printers.cc +++ b/src/gmock-printers.cc @@ -55,10 +55,12 @@ namespace { using ::std::ostream; -#ifdef _WIN32_WCE +#ifdef _WIN32_WCE // Windows CE does not define _snprintf_s. #define snprintf _snprintf -#elif GTEST_OS_WINDOWS +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. #define snprintf _snprintf_s +#elif _MSC_VER +#define snprintf _snprintf #endif // Prints a segment of bytes in the given object. diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 052202d7..ac5fd110 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -1784,17 +1784,23 @@ TEST(MatcherAssertionTest, WorksWhenMatcherIsNotSatisfied) { // which cannot reference auto variables. static int n; n = 5; - EXPECT_FATAL_FAILURE(ASSERT_THAT(n, Gt(10)) << "This should fail.", + + // VC++ prior to version 8.0 SP1 has a bug where it will not see any + // functions declared in the namespace scope from within nested classes. + // EXPECT/ASSERT_(NON)FATAL_FAILURE macros use nested classes so that all + // namespace-level functions invoked inside them need to be explicitly + // resolved. + EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Gt(10)), "Value of: n\n" "Expected: is greater than 10\n" - " Actual: 5\n" - "This should fail."); + " Actual: 5"); n = 0; - EXPECT_NONFATAL_FAILURE(EXPECT_THAT(n, AllOf(Le(7), Ge(5))), - "Value of: n\n" - "Expected: (is less than or equal to 7) and " - "(is greater than or equal to 5)\n" - " Actual: 0"); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT(n, ::testing::AllOf(::testing::Le(7), ::testing::Ge(5))), + "Value of: n\n" + "Expected: (is less than or equal to 7) and " + "(is greater than or equal to 5)\n" + " Actual: 0"); } // Tests that ASSERT_THAT() and EXPECT_THAT() work when the argument @@ -1805,11 +1811,11 @@ TEST(MatcherAssertionTest, WorksForByRefArguments) { static int n; n = 0; EXPECT_THAT(n, AllOf(Le(7), Ref(n))); - EXPECT_FATAL_FAILURE(ASSERT_THAT(n, Not(Ref(n))), + EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Not(::testing::Ref(n))), "Value of: n\n" "Expected: does not reference the variable @"); // Tests the "Actual" part. - EXPECT_FATAL_FAILURE(ASSERT_THAT(n, Not(Ref(n))), + EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Not(::testing::Ref(n))), "Actual: 0 (is located @"); } @@ -2745,7 +2751,6 @@ TEST(ResultOfTest, WorksForReferencingCallables) { EXPECT_FALSE(matcher3.Matches(n2)); } - class DivisibleByImpl { public: explicit DivisibleByImpl(int divider) : divider_(divider) {} @@ -2763,9 +2768,11 @@ class DivisibleByImpl { *os << "is not divisible by " << divider_; } + void set_divider(int divider) { divider_ = divider; } int divider() const { return divider_; } + private: - const int divider_; + int divider_; }; // For testing using ExplainMatchResultTo() with polymorphic matchers. @@ -2859,6 +2866,7 @@ TEST(ByRefTest, AllowsNotCopyableValueInMatchers) { EXPECT_TRUE(m.Matches(n2)); } +#if GTEST_HAS_TYPED_TEST // Tests ContainerEq with different container types, and // different element types. @@ -2927,6 +2935,7 @@ TYPED_TEST(ContainerEqTest, DuplicateDifference) { // But in any case there should be no explanation. EXPECT_EQ("", Explain(m, test_set)); } +#endif // GTEST_HAS_TYPED_TEST // Tests that mutliple missing values are reported. // Using just vector here, so order is predicatble. @@ -3345,5 +3354,22 @@ TEST(FormatMatcherDescriptionTest, Strings(params, params + 1))); } +// Tests PolymorphicMatcher::mutable_impl(). +TEST(PolymorphicMatcherTest, CanAccessMutableImpl) { + PolymorphicMatcher m(DivisibleByImpl(42)); + DivisibleByImpl& impl = m.mutable_impl(); + EXPECT_EQ(42, impl.divider()); + + impl.set_divider(0); + EXPECT_EQ(0, m.mutable_impl().divider()); +} + +// Tests PolymorphicMatcher::impl(). +TEST(PolymorphicMatcherTest, CanAccessImpl) { + const PolymorphicMatcher m(DivisibleByImpl(42)); + const DivisibleByImpl& impl = m.impl(); + EXPECT_EQ(42, impl.divider()); +} + } // namespace gmock_matchers_test } // namespace testing diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index de05c574..f9c595eb 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1432,7 +1432,7 @@ TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) { #if GTEST_HAS_DEATH_TEST // Calls must be in strict order when specified so. -TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { +TEST(AfterDeathTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { MockA a; MockB b; Expectation e1 = EXPECT_CALL(a, DoA(1)); @@ -1454,17 +1454,17 @@ TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { // gtest and gmock print messages to stdout, which isn't captured by // death tests. Therefore we have to match with an empty regular // expression in all the EXPECT_DEATH()s. - EXPECT_DEATH(a.ReturnResult(2), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(2), ""); b.DoB(); - EXPECT_DEATH(a.ReturnResult(2), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(2), ""); b.DoB(); a.ReturnResult(2); } // Calls must satisfy the partial order when specified so. -TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { +TEST(AfterDeathTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { MockA a; Expectation e = EXPECT_CALL(a, DoA(1)); const ExpectationSet es = EXPECT_CALL(a, DoA(2)); @@ -1472,17 +1472,17 @@ TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { .After(e, es) .WillOnce(Return(Result())); - EXPECT_DEATH(a.ReturnResult(3), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); a.DoA(2); - EXPECT_DEATH(a.ReturnResult(3), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); a.DoA(1); a.ReturnResult(3); } // .After() can be combined with .InSequence(). -TEST(AfterTest, CanBeUsedWithInSequence) { +TEST(AfterDeathTest, CanBeUsedWithInSequence) { MockA a; Sequence s; Expectation e = EXPECT_CALL(a, DoA(1)); @@ -1492,7 +1492,7 @@ TEST(AfterTest, CanBeUsedWithInSequence) { .WillOnce(Return(Result())); a.DoA(1); - EXPECT_DEATH(a.ReturnResult(3), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); a.DoA(2); a.ReturnResult(3); @@ -1551,7 +1551,7 @@ TEST(AfterTest, AcceptsDuplicatedInput) { .WillOnce(Return(Result())); a.DoA(1); - EXPECT_DEATH(a.ReturnResult(3), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); a.DoA(2); a.ReturnResult(3); -- cgit v1.2.3 From 46642857b18abae8537317f944569ef552e2d301 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 1 Sep 2009 19:10:50 +0000 Subject: Depends on gtest r300, which allows String to contain NUL. --- src/gmock.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmock.cc b/src/gmock.cc index caafb015..f487265d 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -63,7 +63,7 @@ static const char* ParseGoogleMockFlagValue(const char* str, // The flag must start with "--gmock_". const String flag_str = String::Format("--gmock_%s", flag); - const size_t flag_len = flag_str.GetLength(); + const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. -- cgit v1.2.3 From 5bc7cfe8174af5f299529f7ad15b26d4b2cb60af Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 4 Sep 2009 18:10:53 +0000 Subject: Updates CHANGES. --- CHANGES | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 8b62defa..9845eb91 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,26 @@ +Changes for 1.2.0 (up to r194): + + * New feature: own implementation of TR1 tuple (no more dependency on + Boost!). + * New feature: support for Visual C++ 7.1. + * 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(m), Args<...>(m), AllArgs(m), and + Contains(m). + * 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, Symbian, and gcc. + * Bug fixes and implementation clean-ups. + Changes for 1.1.0: * New feature: ability to use Google Mock with any testing framework. @@ -7,7 +30,7 @@ Changes for 1.1.0: * 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-up. + * Bug fixes and implementation clean-ups. Changes for 1.0.0: -- cgit v1.2.3 From d6ffd13698d17215c2069e036a179f22cb1289a6 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 8 Sep 2009 17:15:49 +0000 Subject: Adds gmock-more-actions.h to the distribution ('make distcheck' passes). --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 1ce29ba2..e176bbec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ pkginclude_HEADERS = include/gmock/gmock.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-printers.h \ include/gmock/gmock-spec-builders.h -- cgit v1.2.3 From 04d6ed817e40f676225e0bf20ff1470d8f0c4a20 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 11 Sep 2009 07:01:08 +0000 Subject: Simplifies the tests using EXPECT_DEATH_IF_SUPPORTED. --- test/gmock-actions_test.cc | 28 ++++++++-------------------- test/gmock-internal-utils_test.cc | 8 ++------ test/gmock-matchers_test.cc | 4 +--- test/gmock-port_test.cc | 7 ++++--- test/gmock-spec-builders_test.cc | 36 ++++++++---------------------------- 5 files changed, 23 insertions(+), 60 deletions(-) diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 9bf4c32d..772f0605 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -199,26 +199,22 @@ TEST(BuiltInDefaultValueTest, UserTypeHasNoDefault) { EXPECT_FALSE(BuiltInDefaultValue::Exists()); } -#if GTEST_HAS_DEATH_TEST - // Tests that BuiltInDefaultValue::Get() aborts the program. TEST(BuiltInDefaultValueDeathTest, IsUndefinedForReferences) { - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ BuiltInDefaultValue::Get(); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ BuiltInDefaultValue::Get(); }, ""); } TEST(BuiltInDefaultValueDeathTest, IsUndefinedForUserTypes) { - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ BuiltInDefaultValue::Get(); }, ""); } -#endif // GTEST_HAS_DEATH_TEST - // Tests that DefaultValue::IsSet() is false initially. TEST(DefaultValueTest, IsInitiallyUnset) { EXPECT_FALSE(DefaultValue::IsSet()); @@ -260,11 +256,9 @@ TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_EQ(0, DefaultValue::Get()); -#if GTEST_HAS_DEATH_TEST - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ DefaultValue::Get(); }, ""); -#endif // GTEST_HAS_DEATH_TEST } // Tests that DefaultValue::Get() returns void. @@ -316,14 +310,12 @@ TEST(DefaultValueOfReferenceDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_FALSE(DefaultValue::IsSet()); -#if GTEST_HAS_DEATH_TEST - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ DefaultValue::Get(); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ DefaultValue::Get(); }, ""); -#endif // GTEST_HAS_DEATH_TEST } // Tests that ActionInterface can be implemented by defining the @@ -559,15 +551,13 @@ TEST(DoDefaultTest, ReturnsBuiltInDefaultValueByDefault) { EXPECT_EQ(0, mock.IntFunc(true)); } -#if GTEST_HAS_DEATH_TEST - // Tests that DoDefault() aborts the process when there is no built-in // default value for the return type. TEST(DoDefaultDeathTest, DiesForUnknowType) { MockClass mock; EXPECT_CALL(mock, Foo()) .WillRepeatedly(DoDefault()); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ mock.Foo(); }, ""); } @@ -587,13 +577,11 @@ TEST(DoDefaultDeathTest, DiesIfUsedInCompositeAction) { // EXPECT_DEATH() can only capture stderr, while Google Mock's // errors are printed on stdout. Therefore we have to settle for // not verifying the message. - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ mock.IntFunc(true); }, ""); } -#endif // GTEST_HAS_DEATH_TEST - // Tests that DoDefault() returns the default value set by // DefaultValue::Set() when it's not overriden by an ON_CALL(). TEST(DoDefaultTest, ReturnsUserSpecifiedPerTypeDefaultValueWhenThereIsOne) { diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index c949dd75..4867e119 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -472,21 +472,17 @@ TEST(AssertTest, SucceedsOnTrue) { Assert(true, __FILE__, __LINE__); // This should succeed too. } -#if GTEST_HAS_DEATH_TEST - // Tests that Assert(false, ...) generates a fatal failure. TEST(AssertTest, FailsFatallyOnFalse) { - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ Assert(false, __FILE__, __LINE__, "This should fail."); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ Assert(false, __FILE__, __LINE__); }, ""); } -#endif // GTEST_HAS_DEATH_TEST - // Tests that Expect(true, ...) succeeds. TEST(ExpectTest, SucceedsOnTrue) { Expect(true, __FILE__, __LINE__, "This should succeed."); diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index ac5fd110..8926e944 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -2678,15 +2678,13 @@ TEST(ResultOfTest, WorksForCompatibleMatcherTypes) { EXPECT_FALSE(matcher.Matches(42)); } -#if GTEST_HAS_DEATH_TEST // Tests that the program aborts when ResultOf is passed // a NULL function pointer. TEST(ResultOfDeathTest, DiesOnNullFunctionPointers) { - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( ResultOf(static_cast(NULL), Eq(string("foo"))), "NULL function pointer is passed into ResultOf\\(\\)\\."); } -#endif // GTEST_HAS_DEATH_TEST // Tests that ResultOf(f, ...) compiles and works as expected when f is a // function reference. diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 2e85bccd..7335405c 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -65,8 +65,6 @@ TEST(GmockCheckSyntaxTest, WorksWithSwitch) { GMOCK_CHECK_(true) << "Check failed in switch case"; } -#if GTEST_HAS_DEATH_TEST - TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; // MSVC and gcc use different formats to print source file locations. @@ -81,9 +79,12 @@ TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { #endif // _MSC_VER ".*a_false_condition.*Extra info"; - EXPECT_DEATH(GMOCK_CHECK_(a_false_condition) << "Extra info", regex); + EXPECT_DEATH_IF_SUPPORTED(GMOCK_CHECK_(a_false_condition) << "Extra info", + regex); } +#if GTEST_HAS_DEATH_TEST + TEST(GmockCheckDeathTest, LivesSilentlyOnSuccess) { EXPECT_EXIT({ GMOCK_CHECK_(true) << "Extra info"; diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index f9c595eb..3f2918fa 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -197,19 +197,15 @@ TEST(OnCallSyntaxTest, WithCanAppearAtMostOnce) { }, ".With() cannot appear more than once in an ON_CALL()"); } -#if GTEST_HAS_DEATH_TEST - TEST(OnCallSyntaxTest, WillByDefaultIsMandatory) { MockA a; - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ ON_CALL(a, DoA(5)); a.DoA(5); }, ""); } -#endif // GTEST_HAS_DEATH_TEST - TEST(OnCallSyntaxTest, WillByDefaultCanAppearAtMostOnce) { MockA a; @@ -1018,18 +1014,14 @@ TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { #endif // GMOCK_HAS_REGEX -#if GTEST_HAS_DEATH_TEST - TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) { MockA a; // TODO(wan@google.com): We should really verify the output message, // but we cannot yet due to that EXPECT_DEATH only captures stderr // while Google Mock logs to stdout. - EXPECT_DEATH(a.ReturnResult(1), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(1), ""); } -#endif // GTEST_HAS_DEATH_TEST - // Tests that an excessive call (one whose arguments match the // matchers but is called too many times) performs the default action. TEST(ExcessiveCallTest, DoesDefaultAction) { @@ -1174,8 +1166,6 @@ TEST(SequenceTest, AnyOrderIsOkByDefault) { } } -#if GTEST_HAS_DEATH_TEST - // Tests that the calls must be in strict order when a complete order // is specified. TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo) { @@ -1194,13 +1184,13 @@ TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo) { .InSequence(s) .WillOnce(Return(Result())); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ a.ReturnResult(1); a.ReturnResult(3); a.ReturnResult(2); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ a.ReturnResult(2); a.ReturnResult(1); a.ReturnResult(3); @@ -1233,21 +1223,21 @@ TEST(SequenceTest, CallsMustConformToSpecifiedDag) { .InSequence(x) .WillOnce(Return(Result())); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ a.ReturnResult(1); b.DoB(); a.ReturnResult(2); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ a.ReturnResult(2); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ a.ReturnResult(3); }, ""); - EXPECT_DEATH({ // NOLINT + EXPECT_DEATH_IF_SUPPORTED({ a.ReturnResult(1); b.DoB(); b.DoB(); @@ -1261,8 +1251,6 @@ TEST(SequenceTest, CallsMustConformToSpecifiedDag) { a.ReturnResult(3); } -#endif // GTEST_HAS_DEATH_TEST - TEST(SequenceTest, Retirement) { MockA a; Sequence s; @@ -1429,8 +1417,6 @@ TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) { a.DoA(2); } -#if GTEST_HAS_DEATH_TEST - // Calls must be in strict order when specified so. TEST(AfterDeathTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { MockA a; @@ -1498,8 +1484,6 @@ TEST(AfterDeathTest, CanBeUsedWithInSequence) { a.ReturnResult(3); } -#endif // GTEST_HAS_DEATH_TEST - // .After() can be called multiple times. TEST(AfterTest, CanBeCalledManyTimes) { MockA a; @@ -1536,8 +1520,6 @@ TEST(AfterTest, AcceptsUpToFiveArguments) { a.DoA(6); } -#if GTEST_HAS_DEATH_TEST - // .After() allows input to contain duplicated Expectations. TEST(AfterTest, AcceptsDuplicatedInput) { MockA a; @@ -1557,8 +1539,6 @@ TEST(AfterTest, AcceptsDuplicatedInput) { a.ReturnResult(3); } -#endif // GTEST_HAS_DEATH_TEST - // An Expectation added to an ExpectationSet after it has been used in // an .After() has no effect. TEST(AfterTest, ChangesToExpectationSetHaveNoEffectAfterwards) { -- cgit v1.2.3 From c53b3dca1b9ad6a6480b13744753916146b891d3 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sat, 12 Sep 2009 06:46:26 +0000 Subject: Removes dead code in gmock-more-actions_test.cc. --- test/gmock-more-actions_test.cc | 132 ---------------------------------------- 1 file changed, 132 deletions(-) diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index 95077768..f5dab5bf 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -350,25 +350,6 @@ TEST(InvokeTest, FunctionWithCompatibleType) { EXPECT_EQ(4321, a.Perform(make_tuple(4000, 300, 20, true))); } -#if GMOCK_HAS_GOOGLE3_CALLBACK_ - -// Tests IgnoreResult(Invoke(result_callback)). -TEST(InvokeTest, IgnoreResultOfResultCallback) { - ResultCallback* c = NewPermanentCallback(Nullary); - Action a = IgnoreResult(Invoke(c)); - a.Perform(make_tuple()); -} - -// Tests IgnoreResult(Invoke(result_callback4)). -TEST(InvokeTest, IgnoreResultOfResultCallback4) { - ResultCallback4* c = - NewPermanentCallback(SumOf4); - Action a = IgnoreResult(Invoke(c)); - a.Perform(make_tuple(1, 2, 3, 4)); -} - -#endif // GMOCK_HAS_GOOGLE3_CALLBACK_ - // Tests using Invoke() with an object pointer and a method pointer. // Tests using Invoke() with a nullary method. @@ -479,119 +460,6 @@ TEST(InvokeMethodTest, MethodWithCompatibleType) { EXPECT_EQ(4444, a.Perform(make_tuple(4000, 300, 20, true))); } -#if GMOCK_HAS_GOOGLE3_CALLBACK_ - -// We don't have dedicated tests to verify that Invoke(callback) and -// InvokeWithoutArgs(callback) delete the callback argument. Instead, -// we rely on the heap checker linked in this test program to do that. - -// Tests that Invoke(non-permanent-callback) kills the process. -TEST(InvokeCallbackDeathTest, RejectsNonPermanentCallback) { - EXPECT_DEATH({ - Action a = Invoke(NewCallback(Nullary)); // NOLINT - }, ""); -} - -// Tests using Invoke() with a nullary callback. -TEST(InvokeCallbackTest, Nullary) { - // Tests using Invoke(callback) as an action of the exact type. - Action a = Invoke(NewPermanentCallback(Nullary)); // NOLINT - EXPECT_EQ(1, a.Perform(make_tuple())); - - // Tests using Invoke(callback) as an action of a compatible type. - Action a2 = Invoke(NewPermanentCallback(Nullary)); // NOLINT - EXPECT_TRUE(a2.Perform(make_tuple())); - - // Tests using Invoke() on a callback that returns void. - Action a3 = Invoke(NewPermanentCallback(VoidNullary)); // NOLINT - g_done = false; - a3.Perform(make_tuple()); - EXPECT_TRUE(g_done); -} - -// Tests using Invoke() with a unary callback. -TEST(InvokeCallbackTest, Unary) { - // Tests using Invoke(callback1) as an action of the exact type. - Action a = Invoke(NewPermanentCallback(Unary)); // NOLINT - EXPECT_FALSE(a.Perform(make_tuple(1))); - EXPECT_TRUE(a.Perform(make_tuple(-1))); - - // Tests using Invoke(callback1) as an action of a compatible type. - Action a2 = Invoke(NewPermanentCallback(Unary)); // NOLINT - EXPECT_EQ(0, a2.Perform(make_tuple(1L))); - EXPECT_EQ(1, a2.Perform(make_tuple(-1L))); - - // Tests using Invoke() on a callback that returns void. - Action a3 = Invoke(NewPermanentCallback(VoidUnary)); // NOLINT - g_done = false; - a3.Perform(make_tuple('a')); - EXPECT_TRUE(g_done); -} - -// Tests using Invoke() with a binary callback. -TEST(InvokeCallbackTest, Binary) { - // Tests using Invoke(callback2) as an action of the exact type. - Action a = // NOLINT - Invoke(NewPermanentCallback(Binary)); - const char* p = "Hello"; - EXPECT_EQ(p + 2, a.Perform(make_tuple(p, 2))); - - // Tests using Invoke(callback2) as an action of a compatible type. - Action a2 = // NOLINT - Invoke(NewPermanentCallback(Binary)); - char str[] = "Hello"; - EXPECT_TRUE(a2.Perform(make_tuple(str, 2))); - - // Tests using Invoke() on a callback that returns void. - Action a3 = - Invoke(NewPermanentCallback(VoidBinary)); // NOLINT - g_done = false; - a3.Perform(make_tuple('a', 'b')); - EXPECT_TRUE(g_done); -} - -// Tests using Invoke() with a ternary callback. -TEST(InvokeCallbackTest, Ternary) { - // Tests using Invoke(callback3) as an action of the exact type. - Action a = // NOLINT - Invoke(NewPermanentCallback(Ternary)); - EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', 3))); - - // Tests using Invoke(callback3) as an action of a compatible type. - Action a2 = // NOLINT - Invoke(NewPermanentCallback(Ternary)); - EXPECT_EQ(6, a2.Perform(make_tuple('\1', 2, 3))); - - // Tests using Invoke() on a callback that returns void. - Action a3 = - Invoke(NewPermanentCallback(VoidTernary)); // NOLINT - g_done = false; - a3.Perform(make_tuple('a', 'b', true)); - EXPECT_TRUE(g_done); -} - -// Tests using Invoke() with a 4-argument callback. -TEST(InvokeCallbackTest, CallbackThatTakes4Arguments) { - // Tests using Invoke(callback4) as an action of the exact type. - Action a = // NOLINT - Invoke(NewPermanentCallback(SumOf4)); - EXPECT_EQ(1234, a.Perform(make_tuple(1000, 200, 30, 4))); - - // Tests using Invoke(callback4) as an action of a compatible type. - Action a2 = // NOLINT - Invoke(NewPermanentCallback(SumOf4)); - EXPECT_EQ(4321, a2.Perform(make_tuple(4000, 300, 20, true))); - - // Tests using Invoke() on a callback that returns void. - Action a3 = - Invoke(NewPermanentCallback(VoidFunctionWithFourArguments)); // NOLINT - g_done = false; - a3.Perform(make_tuple('a', 'b', 0, 1)); - EXPECT_TRUE(g_done); -} - -#endif // GMOCK_HAS_GOOGLE3_CALLBACK_ - // Tests using WithoutArgs with an action that takes no argument. TEST(WithoutArgsTest, NoArg) { Action a = WithoutArgs(Invoke(Nullary)); // NOLINT -- cgit v1.2.3 From f5e1ce5b9237edbc2e524ae9ebcb2452dc842937 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Sep 2009 07:02:02 +0000 Subject: Adds new matcher Pair(). Replaces GMOCK_CHECK_ with GTEST_CHECK_ (by Vlad Losev). --- include/gmock/gmock-matchers.h | 102 ++++++++++++++++++++++++- include/gmock/internal/gmock-port.h | 50 ------------- src/gmock-spec-builders.cc | 4 +- test/gmock-matchers_test.cc | 144 ++++++++++++++++++++++++++++-------- test/gmock-port_test.cc | 59 +-------------- 5 files changed, 219 insertions(+), 140 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 7266fba7..688ce64f 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1623,7 +1623,7 @@ struct CallableTraits { typedef ResType(*StorageType)(ArgType); static void CheckIsValid(ResType(*f)(ArgType)) { - GMOCK_CHECK_(f != NULL) + GTEST_CHECK_(f != NULL) << "NULL function pointer is passed into ResultOf()."; } template @@ -1934,6 +1934,94 @@ class KeyMatcher { const M matcher_for_key_; }; +// Implements Pair(first_matcher, second_matcher) for the given argument pair +// type with its two matchers. See Pair() function below. +template +class PairMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef typename RawPairType::first_type FirstType; + typedef typename RawPairType::second_type SecondType; + + template + PairMatcherImpl(FirstMatcher first_matcher, SecondMatcher second_matcher) + : first_matcher_( + testing::SafeMatcherCast(first_matcher)), + second_matcher_( + testing::SafeMatcherCast(second_matcher)) { + } + + // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' + // matches second_matcher. + virtual bool Matches(PairType a_pair) const { + return first_matcher_.Matches(a_pair.first) && + second_matcher_.Matches(a_pair.second); + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "has a first field that "; + first_matcher_.DescribeTo(os); + *os << ", and has a second field that "; + second_matcher_.DescribeTo(os); + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "has a first field that "; + first_matcher_.DescribeNegationTo(os); + *os << ", or has a second field that "; + second_matcher_.DescribeNegationTo(os); + } + + // Explains why 'a_pair' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(PairType a_pair, + ::std::ostream* os) const { + ::std::stringstream ss1; + first_matcher_.ExplainMatchResultTo(a_pair.first, &ss1); + internal::string s1 = ss1.str(); + if (s1 != "") { + s1 = "the first field " + s1; + } + + ::std::stringstream ss2; + second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2); + internal::string s2 = ss2.str(); + if (s2 != "") { + s2 = "the second field " + s2; + } + + *os << s1; + if (s1 != "" && s2 != "") { + *os << ", and "; + } + *os << s2; + } + + private: + const Matcher first_matcher_; + const Matcher second_matcher_; +}; + +// Implements polymorphic Pair(first_matcher, second_matcher). +template +class PairMatcher { + public: + PairMatcher(FirstMatcher first_matcher, SecondMatcher second_matcher) + : first_matcher_(first_matcher), second_matcher_(second_matcher) {} + + template + operator Matcher () const { + return MakeMatcher( + new PairMatcherImpl( + first_matcher_, second_matcher_)); + } + + private: + const FirstMatcher first_matcher_; + const SecondMatcher second_matcher_; +}; + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -2632,6 +2720,18 @@ inline internal::KeyMatcher Key(M inner_matcher) { return internal::KeyMatcher(inner_matcher); } +// Pair(first_matcher, second_matcher) matches a std::pair whose 'first' field +// matches first_matcher and whose 'second' field matches second_matcher. For +// example, EXPECT_THAT(map_type, ElementsAre(Pair(Ge(5), "foo"))) can be used +// to match a std::map that contains exactly one element whose key +// is >= 5 and whose value equals "foo". +template +inline internal::PairMatcher +Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) { + return internal::PairMatcher( + first_matcher, second_matcher); +} + // Returns a predicate that is satisfied by anything that matches the // given matcher. template diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 6bee9966..0263491e 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -214,56 +214,6 @@ typedef ::wstring wstring; typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING -// Prints the file location in the format native to the compiler. -inline void FormatFileLocation(const char* file, int line, ::std::ostream* os) { - if (file == NULL) - file = "unknown file"; - if (line < 0) { - *os << file << ":"; - } else { -#if _MSC_VER - *os << file << "(" << line << "):"; -#else - *os << file << ":" << line << ":"; -#endif - } -} - -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GMOCK_CHECK_(boolean_condition); -// or -// GMOCK_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. - -class GMockCheckProvider { - public: - GMockCheckProvider(const char* condition, const char* file, int line) { - FormatFileLocation(file, line, &::std::cerr); - ::std::cerr << " ERROR: Condition " << condition << " failed. "; - } - ~GMockCheckProvider() { - ::std::cerr << ::std::endl; - posix::Abort(); - } - ::std::ostream& GetStream() { return ::std::cerr; } -}; -#define GMOCK_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (condition) \ - ; \ - else \ - ::testing::internal::GMockCheckProvider(\ - #condition, __FILE__, __LINE__).GetStream() - } // namespace internal } // namespace testing diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 94ba24bb..72558658 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -203,8 +203,8 @@ class MockObjectRegistry { // This can help the user identify the leaked object. std::cout << "\n"; const MockObjectState& state = it->second; - internal::FormatFileLocation( - state.first_used_file, state.first_used_line, &std::cout); + std::cout << internal::FormatFileLocation(state.first_used_file, + state.first_used_line); std::cout << " ERROR: this mock object"; if (state.first_used_test != "") { std::cout << " (used in test " << state.first_used_test_case << "." diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 8926e944..ef878898 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +92,7 @@ using testing::NanSensitiveFloatEq; using testing::Ne; using testing::Not; using testing::NotNull; +using testing::Pair; using testing::Pointee; using testing::PolymorphicMatcher; using testing::Property; @@ -126,6 +128,35 @@ using testing::MatchesRegex; using testing::internal::RE; #endif // GMOCK_HAS_REGEX +// For testing ExplainMatchResultTo(). +class GreaterThanMatcher : public MatcherInterface { + public: + explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} + + virtual bool Matches(int lhs) const { return lhs > rhs_; } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is greater than " << rhs_; + } + + virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { + const int diff = lhs - rhs_; + if (diff > 0) { + *os << "is " << diff << " more than " << rhs_; + } else if (diff == 0) { + *os << "is the same as " << rhs_; + } else { + *os << "is " << -diff << " less than " << rhs_; + } + } + private: + const int rhs_; +}; + +Matcher GreaterThan(int n) { + return MakeMatcher(new GreaterThanMatcher(n)); +} + // Returns the description of the given matcher. template string Describe(const Matcher& m) { @@ -899,6 +930,90 @@ TEST(KeyTest, InsideContainsUsingMultimap) { EXPECT_THAT(container, Not(Contains(Key(3)))); } +TEST(PairTest, Typing) { + // Test verifies the following type conversions can be compiled. + Matcher&> m1 = Pair("foo", 42); + Matcher > m2 = Pair("foo", 42); + Matcher > m3 = Pair("foo", 42); + + Matcher > m4 = Pair(25, "42"); + Matcher > m5 = Pair("25", 42); +} + +TEST(PairTest, CanDescribeSelf) { + Matcher&> m1 = Pair("foo", 42); + EXPECT_EQ("has a first field that is equal to \"foo\"" + ", and has a second field that is equal to 42", + Describe(m1)); + EXPECT_EQ("has a first field that is not equal to \"foo\"" + ", or has a second field that is not equal to 42", + DescribeNegation(m1)); + // Double and triple negation (1 or 2 times not and description of negation). + Matcher&> m2 = Not(Pair(Not(13), 42)); + EXPECT_EQ("has a first field that is not equal to 13" + ", and has a second field that is equal to 42", + DescribeNegation(m2)); +} + +TEST(PairTest, CanExplainMatchResultTo) { + const Matcher > m0 = Pair(0, 0); + EXPECT_EQ("", Explain(m0, std::make_pair(25, 42))); + + const Matcher > m1 = Pair(GreaterThan(0), 0); + EXPECT_EQ("the first field is 25 more than 0", + Explain(m1, std::make_pair(25, 42))); + + const Matcher > m2 = Pair(0, GreaterThan(0)); + EXPECT_EQ("the second field is 42 more than 0", + Explain(m2, std::make_pair(25, 42))); + + const Matcher > m3 = Pair(GreaterThan(0), GreaterThan(0)); + EXPECT_EQ("the first field is 25 more than 0" + ", and the second field is 42 more than 0", + Explain(m3, std::make_pair(25, 42))); +} + +TEST(PairTest, MatchesCorrectly) { + std::pair p(25, "foo"); + + // Both fields match. + EXPECT_THAT(p, Pair(25, "foo")); + EXPECT_THAT(p, Pair(Ge(20), HasSubstr("o"))); + + // 'first' doesnt' match, but 'second' matches. + EXPECT_THAT(p, Not(Pair(42, "foo"))); + EXPECT_THAT(p, Not(Pair(Lt(25), "foo"))); + + // 'first' matches, but 'second' doesn't match. + EXPECT_THAT(p, Not(Pair(25, "bar"))); + EXPECT_THAT(p, Not(Pair(25, Not("foo")))); + + // Neither field matches. + EXPECT_THAT(p, Not(Pair(13, "bar"))); + EXPECT_THAT(p, Not(Pair(Lt(13), HasSubstr("a")))); +} + +TEST(PairTest, SafelyCastsInnerMatchers) { + Matcher is_positive = Gt(0); + Matcher is_negative = Lt(0); + std::pair p('a', true); + EXPECT_THAT(p, Pair(is_positive, _)); + EXPECT_THAT(p, Not(Pair(is_negative, _))); + EXPECT_THAT(p, Pair(_, is_positive)); + EXPECT_THAT(p, Not(Pair(_, is_negative))); +} + +TEST(PairTest, InsideContainsUsingMap) { + std::map container; + container.insert(std::make_pair(1, "foo")); + container.insert(std::make_pair(2, "bar")); + container.insert(std::make_pair(4, "baz")); + EXPECT_THAT(container, Contains(Pair(1, "foo"))); + EXPECT_THAT(container, Contains(Pair(1, _))); + EXPECT_THAT(container, Contains(Pair(_, "foo"))); + EXPECT_THAT(container, Not(Contains(Pair(3, _)))); +} + // Tests StartsWith(s). TEST(StartsWithTest, MatchesStringWithGivenPrefix) { @@ -2150,35 +2265,6 @@ TEST(PointeeTest, CanDescribeSelf) { DescribeNegation(m)); } -// For testing ExplainMatchResultTo(). -class GreaterThanMatcher : public MatcherInterface { - public: - explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - - virtual bool Matches(int lhs) const { return lhs > rhs_; } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "is greater than " << rhs_; - } - - virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { - const int diff = lhs - rhs_; - if (diff > 0) { - *os << "is " << diff << " more than " << rhs_; - } else if (diff == 0) { - *os << "is the same as " << rhs_; - } else { - *os << "is " << -diff << " less than " << rhs_; - } - } - private: - const int rhs_; -}; - -Matcher GreaterThan(int n) { - return MakeMatcher(new GreaterThanMatcher(n)); -} - TEST(PointeeTest, CanExplainMatchResult) { const Matcher m = Pointee(StartsWith("Hi")); diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 7335405c..9a64ec33 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -36,61 +36,4 @@ #include #include -TEST(GmockCheckSyntaxTest, BehavesLikeASingleStatement) { - if (false) - GMOCK_CHECK_(false) << "This should never be executed; " - "It's a compilation test only."; - - if (true) - GMOCK_CHECK_(true); - else - ; - - if (false) - ; - else - GMOCK_CHECK_(true) << ""; -} - -TEST(GmockCheckSyntaxTest, WorksWithSwitch) { - switch (0) { - case 1: - break; - default: - GMOCK_CHECK_(true); - } - - switch(0) - case 0: - GMOCK_CHECK_(true) << "Check failed in switch case"; -} - -TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { - const bool a_false_condition = false; - // MSVC and gcc use different formats to print source file locations. - // Google Mock's failure messages use the same format as used by the - // compiler, in order for the IDE to recognize them. Therefore we look - // for different patterns here depending on the compiler. - const char regex[] = -#ifdef _MSC_VER - "gmock-port_test\\.cc\\(\\d+\\):" -#else - "gmock-port_test\\.cc:[0-9]+" -#endif // _MSC_VER - ".*a_false_condition.*Extra info"; - - EXPECT_DEATH_IF_SUPPORTED(GMOCK_CHECK_(a_false_condition) << "Extra info", - regex); -} - -#if GTEST_HAS_DEATH_TEST - -TEST(GmockCheckDeathTest, LivesSilentlyOnSuccess) { - EXPECT_EXIT({ - GMOCK_CHECK_(true) << "Extra info"; - ::std::cerr << "Success\n"; - exit(0); }, - ::testing::ExitedWithCode(0), "Success"); -} - -#endif // GTEST_HAS_DEATH_TEST +// This file intentionally contains no test at this moment. -- cgit v1.2.3 From 4bd79e4f25a86f3a2a99f6af06cc43cdacc55853 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Sep 2009 17:38:08 +0000 Subject: Simplifies the definition of NativeArray. Works around a VC bug in StrictMock & NiceMock. --- include/gmock/gmock-generated-nice-strict.h | 72 ++++++++++++++++-------- include/gmock/gmock-generated-nice-strict.h.pump | 24 +++++--- include/gmock/internal/gmock-internal-utils.h | 28 +++------ test/gmock-internal-utils_test.cc | 37 ++++-------- test/gmock-nice-strict_test.cc | 29 ++++++++++ test/gmock-printers_test.cc | 8 +-- 6 files changed, 117 insertions(+), 81 deletions(-) diff --git a/include/gmock/gmock-generated-nice-strict.h b/include/gmock/gmock-generated-nice-strict.h index f961d796..fc9a81b5 100644 --- a/include/gmock/gmock-generated-nice-strict.h +++ b/include/gmock/gmock-generated-nice-strict.h @@ -70,42 +70,49 @@ class NiceMock : public MockClass { // 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() { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(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) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : MockClass(a1, a2, a3, a4) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : MockClass(a1, a2, a3, a4, a5) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(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) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } virtual ~NiceMock() { - Mock::UnregisterCallReaction(internal::implicit_cast(this)); + ::testing::Mock::UnregisterCallReaction( + internal::implicit_cast(this)); } }; @@ -151,40 +163,47 @@ class StrictMock : public MockClass { // 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() { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template explicit StrictMock(const A1& a1) : MockClass(a1) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : MockClass(a1, a2, a3, a4) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : MockClass(a1, a2, a3, a4, a5) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(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) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template (this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } virtual ~StrictMock() { - Mock::UnregisterCallReaction(internal::implicit_cast(this)); + ::testing::Mock::UnregisterCallReaction( + internal::implicit_cast(this)); } }; diff --git a/include/gmock/gmock-generated-nice-strict.h.pump b/include/gmock/gmock-generated-nice-strict.h.pump index 580e79f0..b265c2e4 100644 --- a/include/gmock/gmock-generated-nice-strict.h.pump +++ b/include/gmock/gmock-generated-nice-strict.h.pump @@ -73,14 +73,16 @@ class NiceMock : public MockClass { // 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() { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(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) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } $range i 2..n @@ -88,13 +90,15 @@ $for i [[ $range j 1..i template <$for j, [[typename A$j]]> NiceMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { - Mock::AllowUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::AllowUninterestingCalls( + internal::implicit_cast(this)); } ]] virtual ~NiceMock() { - Mock::UnregisterCallReaction(internal::implicit_cast(this)); + ::testing::Mock::UnregisterCallReaction( + internal::implicit_cast(this)); } }; @@ -104,25 +108,29 @@ class StrictMock : public MockClass { // 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() { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } template explicit StrictMock(const A1& a1) : MockClass(a1) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } $for i [[ $range j 1..i template <$for j, [[typename A$j]]> StrictMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { - Mock::FailUninterestingCalls(internal::implicit_cast(this)); + ::testing::Mock::FailUninterestingCalls( + internal::implicit_cast(this)); } ]] virtual ~StrictMock() { - Mock::UnregisterCallReaction(internal::implicit_cast(this)); + ::testing::Mock::UnregisterCallReaction( + internal::implicit_cast(this)); } }; diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index ee6aa1e2..39e70b3f 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -581,21 +581,9 @@ class NativeArray { typedef Element value_type; typedef const Element* const_iterator; - // Constructs from a native array passed by reference. - template - NativeArray(const Element (&array)[N], RelationToSource relation) { - Init(array, N, relation); - } - - // Constructs from a native array passed by a pointer and a size. - // For generality we don't artificially restrict the types of the - // pointer and the size. - template - NativeArray(const ::std::tr1::tuple& array, - RelationToSource relation) { - Init(internal::GetRawPointer(::std::tr1::get<0>(array)), - ::std::tr1::get<1>(array), - relation); + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); } // Copy constructor. @@ -691,10 +679,10 @@ class StlContainerView { static const_reference ConstReference(const Element (&array)[N]) { // Ensures that Element is not a const type. testing::StaticAssertTypeEq(); - return type(array, kReference); + return type(array, N, kReference); } static type Copy(const Element (&array)[N]) { - return type(array, kCopy); + return type(array, N, kCopy); } }; @@ -710,10 +698,12 @@ class StlContainerView< ::std::tr1::tuple > { static const_reference ConstReference( const ::std::tr1::tuple& array) { - return type(array, kReference); + using ::std::tr1::get; + return type(get<0>(array), get<1>(array), kReference); } static type Copy(const ::std::tr1::tuple& array) { - return type(array, kCopy); + using ::std::tr1::get; + return type(get<0>(array), get<1>(array), kCopy); } }; diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 4867e119..d3a16ad3 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -815,34 +815,19 @@ TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { // Tests NativeArray. -TEST(NativeArrayTest, ConstructorFromArrayReferenceWorks) { +TEST(NativeArrayTest, ConstructorFromArrayWorks) { const int a[3] = { 0, 1, 2 }; - NativeArray na(a, kReference); + NativeArray na(a, 3, kReference); EXPECT_EQ(3, na.size()); EXPECT_EQ(a, na.begin()); } -TEST(NativeArrayTest, ConstructorFromTupleWorks) { - int a[3] = { 0, 1, 2 }; - int* const p = a; - // Tests with a plain pointer. - NativeArray na(make_tuple(p, 3U), kReference); - EXPECT_EQ(a, na.begin()); - - const linked_ptr b(new char); - *b = 'a'; - // Tests with a smart pointer. - NativeArray nb(make_tuple(b, 1), kCopy); - EXPECT_NE(b.get(), nb.begin()); - EXPECT_EQ('a', nb.begin()[0]); -} - TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { typedef int Array[2]; Array* a = new Array[1]; (*a)[0] = 0; (*a)[1] = 1; - NativeArray na(*a, kCopy); + NativeArray na(*a, 2, kCopy); EXPECT_NE(*a, na.begin()); delete[] a; EXPECT_EQ(0, na.begin()[0]); @@ -861,8 +846,8 @@ TEST(NativeArrayTest, TypeMembersAreCorrect) { } TEST(NativeArrayTest, MethodsWork) { - const int a[] = { 0, 1, 2 }; - NativeArray na(a, kCopy); + const int a[3] = { 0, 1, 2 }; + NativeArray na(a, 3, kCopy); ASSERT_EQ(3, na.size()); EXPECT_EQ(3, na.end() - na.begin()); @@ -877,18 +862,18 @@ TEST(NativeArrayTest, MethodsWork) { EXPECT_THAT(na, Eq(na)); - NativeArray na2(a, kReference); + NativeArray na2(a, 3, kReference); EXPECT_THAT(na, Eq(na2)); - const int b1[] = { 0, 1, 1 }; - const int b2[] = { 0, 1, 2, 3 }; - EXPECT_THAT(na, Not(Eq(NativeArray(b1, kReference)))); - EXPECT_THAT(na, Not(Eq(NativeArray(b2, kCopy)))); + const int b1[3] = { 0, 1, 1 }; + const int b2[4] = { 0, 1, 2, 3 }; + EXPECT_THAT(na, Not(Eq(NativeArray(b1, 3, kReference)))); + EXPECT_THAT(na, Not(Eq(NativeArray(b2, 4, kCopy)))); } TEST(NativeArrayTest, WorksForTwoDimensionalArray) { const char a[2][3] = { "hi", "lo" }; - NativeArray na(a, kReference); + NativeArray na(a, 2, kReference); ASSERT_EQ(2, na.size()); EXPECT_EQ(a, na.begin()); } diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 955961c5..15984a55 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -36,6 +36,13 @@ #include #include +// This must not be defined inside the ::testing namespace, or it will +// clash with ::testing::Mock. +class Mock { + public: + MOCK_METHOD0(DoThis, void()); +}; + namespace testing { namespace gmock_nice_strict_test { @@ -166,6 +173,17 @@ TEST(NiceMockTest, NonDefaultConstructor10) { nice_bar.That(5, true); } +// Tests that NiceMock compiles where Mock is a user-defined +// class (as opposed to ::testing::Mock). We had to workaround an +// MSVC 8.0 bug that caused the symbol Mock used in the definition of +// NiceMock to be looked up in the wrong context, and this test +// ensures that our fix works. +TEST(NiceMockTest, AcceptsClassNamedMock) { + NiceMock< ::Mock> nice; + EXPECT_CALL(nice, DoThis()); + nice.DoThis(); +} + // Tests that a strict mock allows expected calls. TEST(StrictMockTest, AllowsExpectedCall) { StrictMock strict_foo; @@ -224,5 +242,16 @@ TEST(StrictMockTest, NonDefaultConstructor10) { "Uninteresting mock function call"); } +// Tests that StrictMock compiles where Mock is a user-defined +// class (as opposed to ::testing::Mock). We had to workaround an +// MSVC 8.0 bug that caused the symbol Mock used in the definition of +// StrictMock to be looked up in the wrong context, and this test +// ensures that our fix works. +TEST(StrictMockTest, AcceptsClassNamedMock) { + StrictMock< ::Mock> nice; + EXPECT_CALL(nice, DoThis()); + nice.DoThis(); +} + } // namespace gmock_nice_strict_test } // namespace testing diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index af2e83c0..0eb8e094 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -790,14 +790,14 @@ TEST(PrintStlContainerTest, NestedContainer) { } TEST(PrintStlContainerTest, OneDimensionalNativeArray) { - const int a[] = { 1, 2, 3 }; - NativeArray b(a, kReference); + const int a[3] = { 1, 2, 3 }; + NativeArray b(a, 3, kReference); EXPECT_EQ("{ 1, 2, 3 }", Print(b)); } TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { - const int a[][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; - NativeArray b(a, kReference); + const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + NativeArray b(a, 2, kReference); EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); } -- cgit v1.2.3 From 93244dc36979a7755d02f0b210659160ce593144 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 17 Sep 2009 19:11:00 +0000 Subject: Disbles two tests that crash on Symbian. --- test/gmock-nice-strict_test.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 15984a55..0dc71069 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -173,16 +173,21 @@ TEST(NiceMockTest, NonDefaultConstructor10) { nice_bar.That(5, true); } +#if !GTEST_OS_SYMBIAN // Tests that NiceMock compiles where Mock is a user-defined // class (as opposed to ::testing::Mock). We had to workaround an // MSVC 8.0 bug that caused the symbol Mock used in the definition of // NiceMock to be looked up in the wrong context, and this test // ensures that our fix works. +// +// We have to skip this test on Symbian, as it causes the program to +// crash there, for reasons unclear to us yet. TEST(NiceMockTest, AcceptsClassNamedMock) { NiceMock< ::Mock> nice; EXPECT_CALL(nice, DoThis()); nice.DoThis(); } +#endif // !GTEST_OS_SYMBIAN // Tests that a strict mock allows expected calls. TEST(StrictMockTest, AllowsExpectedCall) { @@ -242,16 +247,21 @@ TEST(StrictMockTest, NonDefaultConstructor10) { "Uninteresting mock function call"); } +#if !GTEST_OS_SYMBIAN // Tests that StrictMock compiles where Mock is a user-defined // class (as opposed to ::testing::Mock). We had to workaround an // MSVC 8.0 bug that caused the symbol Mock used in the definition of // StrictMock to be looked up in the wrong context, and this test // ensures that our fix works. +// +// We have to skip this test on Symbian, as it causes the program to +// crash there, for reasons unclear to us yet. TEST(StrictMockTest, AcceptsClassNamedMock) { - StrictMock< ::Mock> nice; - EXPECT_CALL(nice, DoThis()); - nice.DoThis(); + StrictMock< ::Mock> strict; + EXPECT_CALL(strict, DoThis()); + strict.DoThis(); } +#endif // !GTEST_OS_SYMBIAN } // namespace gmock_nice_strict_test } // namespace testing -- cgit v1.2.3 From bbd6e105e786dd6d4e1fdd6b1467f969121bcca3 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 18 Sep 2009 18:17:19 +0000 Subject: Picks up gtest r314. --- src/gmock-internal-utils.cc | 8 ++++++-- test/gmock-spec-builders_test.cc | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index e72e019b..196ec74b 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -77,8 +77,12 @@ class GoogleTestFailureReporter : public FailureReporterInterface { public: virtual void ReportFailure(FailureType type, const char* file, int line, const string& message) { - AssertHelper(type == FATAL ? TPRT_FATAL_FAILURE : TPRT_NONFATAL_FAILURE, - file, line, message.c_str()) = Message(); + AssertHelper(type == FATAL ? + TestPartResult::kFatalFailure : + TestPartResult::kNonFatalFailure, + file, + line, + message.c_str()) = Message(); if (type == FATAL) { posix::Abort(); } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 3f2918fa..707d8968 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -985,7 +985,7 @@ TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { // There should be one non-fatal failure. ASSERT_EQ(1, failures.size()); const ::testing::TestPartResult& r = failures.GetTestPartResult(0); - EXPECT_EQ(::testing::TPRT_NONFATAL_FAILURE, r.type()); + EXPECT_EQ(::testing::TestPartResult::kNonFatalFailure, r.type()); // Verifies that the failure message contains the two unsatisfied // pre-requisites but not the satisfied one. -- cgit v1.2.3 From a89034c8021ea6e55bf55688eeb99065de9de928 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 22 Sep 2009 16:18:42 +0000 Subject: Removes gmock's dependency on python2.4. --- scripts/gmock_doctor.py | 2 +- test/gmock_test_utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 7b45fa17..40512fcd 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.4 +#!/usr/bin/env python # # Copyright 2008, Google Inc. # All rights reserved. diff --git a/test/gmock_test_utils.py b/test/gmock_test_utils.py index 4c09e39d..2fda138d 100755 --- a/test/gmock_test_utils.py +++ b/test/gmock_test_utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.4 +#!/usr/bin/env python # # Copyright 2006, Google Inc. # All rights reserved. -- cgit v1.2.3 From f47a2df57bd83291e69ece23b0d5b480fbb90bbf Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Sep 2009 16:39:30 +0000 Subject: Makes gmock compile on minGW, which uses gcc 3.4.5. --- include/gmock/gmock-printers.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 69eee120..e07d92af 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -279,9 +279,12 @@ void DefaultPrintTo(IsNotContainer /* dummy */, if (p == NULL) { *os << "NULL"; } else { - // We cannot use implicit_cast or static_cast here, as they don't - // work when p is a function pointer. - *os << reinterpret_cast(p); + // We want to print p as a const void*. However, we cannot cast + // it to const void* directly, even using reinterpret_cast, as + // earlier versions of gcc (e.g. 3.4.5) cannot compile the cast + // when p is a function pointer. Casting to UInt64 first solves + // the problem. + *os << reinterpret_cast(reinterpret_cast(p)); } } -- cgit v1.2.3 From b0d1c08ff2dc98a1f2ed395ccfed5585ff048d2b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Sep 2009 20:55:18 +0000 Subject: Bumps up the version number for release 1.2.0. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 78ff30d8..d9041388 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_INIT([Google C++ Mocking Framework], - [1.1.0], + [1.2.0], [googlemock@googlegroups.com], [gmock]) @@ -80,7 +80,7 @@ AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" -GTEST_MIN_VERSION="1.3.0" +GTEST_MIN_VERSION="1.4.0" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. -- cgit v1.2.3 From f7af24c7de14ccb10a24909a6f3440a763cb1164 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Sep 2009 21:17:24 +0000 Subject: Simplifies gmock code using gtest's OS-indicating macros. --- include/gmock/gmock-actions.h | 8 ++++---- src/gmock-printers.cc | 4 ++-- src/gmock_main.cc | 4 ++-- test/gmock-actions_test.cc | 8 ++++---- test/gmock_link_test.h | 14 +++++++------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index c8edc8ab..f7daf826 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -606,7 +606,7 @@ class AssignAction { const T2 value_; }; -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE // Implements the SetErrnoAndReturn action to simulate return from // various system calls and libc functions. @@ -626,7 +626,7 @@ class SetErrnoAndReturnAction { const T result_; }; -#endif // _WIN32_WCE +#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 @@ -912,7 +912,7 @@ PolymorphicAction > Assign(T1* ptr, T2 val) { return MakePolymorphicAction(internal::AssignAction(ptr, val)); } -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE // Creates an action that sets errno and returns the appropriate error. template @@ -922,7 +922,7 @@ SetErrnoAndReturn(int errval, T result) { internal::SetErrnoAndReturnAction(errval, result)); } -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE // Various overloads for InvokeWithoutArgs(). diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc index 0473dba1..8efba782 100644 --- a/src/gmock-printers.cc +++ b/src/gmock-printers.cc @@ -55,13 +55,13 @@ namespace { using ::std::ostream; -#ifdef _WIN32_WCE // Windows CE does not define _snprintf_s. +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. #define snprintf _snprintf #elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. #define snprintf _snprintf_s #elif _MSC_VER #define snprintf _snprintf -#endif +#endif // GTEST_OS_WINDOWS_MOBILE // Prints a segment of bytes in the given object. void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, diff --git a/src/gmock_main.cc b/src/gmock_main.cc index 85689d5d..0a3071bf 100644 --- a/src/gmock_main.cc +++ b/src/gmock_main.cc @@ -38,13 +38,13 @@ // is enabled. For this reason instead of _tmain, main function is used on // Windows. See the following link to track the current status of this bug: // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=394464 // NOLINT -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE #include // NOLINT int _tmain(int argc, TCHAR** argv) { #else int main(int argc, char** argv) { -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE std::cout << "Running main() from gmock_main.cc\n"; // Since Google Mock depends on Google Test, InitGoogleMock() is // also responsible for initializing Google Test. Therefore there's diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 772f0605..5d05bc50 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -70,9 +70,9 @@ using testing::ReturnNull; using testing::ReturnRef; using testing::SetArgumentPointee; -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE using testing::SetErrnoAndReturn; -#endif // _WIN32_WCE +#endif #if GMOCK_HAS_PROTOBUF_ using testing::internal::TestMessage; @@ -911,7 +911,7 @@ TEST(AssignTest, CompatibleTypes) { EXPECT_DOUBLE_EQ(5, x); } -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE class SetErrnoAndReturnTest : public testing::Test { protected: @@ -938,7 +938,7 @@ TEST_F(SetErrnoAndReturnTest, CompatibleTypes) { EXPECT_EQ(EINVAL, errno); } -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE // Tests ByRef(). diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index b903f3cb..bbac8ae2 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -116,7 +116,7 @@ #include -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE #include #endif @@ -176,18 +176,18 @@ using testing::WithArg; using testing::WithArgs; using testing::WithoutArgs; -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE using testing::SetErrnoAndReturn; -#endif // _WIN32_WCE +#endif #if GTEST_HAS_EXCEPTIONS using testing::Throw; -#endif // GTEST_HAS_EXCEPTIONS +#endif #if GMOCK_HAS_REGEX using testing::ContainsRegex; using testing::MatchesRegex; -#endif // GMOCK_HAS_REGEX +#endif class Interface { public: @@ -297,7 +297,7 @@ TEST(LinkTest, TestSetArrayArgument) { mock.VoidFromString(&ch); } -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE // Tests the linkage of the SetErrnoAndReturn action. TEST(LinkTest, TestSetErrnoAndReturn) { @@ -309,7 +309,7 @@ TEST(LinkTest, TestSetErrnoAndReturn) { errno = saved_errno; } -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE // Tests the linkage of the Invoke(function) and Invoke(object, method) actions. TEST(LinkTest, TestInvoke) { -- cgit v1.2.3 From 2d970ee3bad530703ff24bc3a011390b45cdd293 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Sep 2009 21:41:36 +0000 Subject: Adds the IsNull() matcher. --- include/gmock/gmock-matchers.h | 18 ++++++++++++++++++ test/gmock-matchers_test.cc | 27 +++++++++++++++++++++++++++ test/gmock_link_test.h | 8 ++++++++ 3 files changed, 53 insertions(+) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 688ce64f..e2beff4e 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -621,6 +621,19 @@ GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "not equal to"); #undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_ +// Implements the polymorphic IsNull() matcher, which matches any +// pointer that is NULL. +class IsNullMatcher { + public: + template + bool Matches(T* p) const { return p == NULL; } + + void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } + void DescribeNegationTo(::std::ostream* os) const { + *os << "is not NULL"; + } +}; + // Implements the polymorphic NotNull() matcher, which matches any // pointer that is not NULL. class NotNullMatcher { @@ -2319,6 +2332,11 @@ inline internal::NeMatcher Ne(Rhs x) { return internal::NeMatcher(x); } +// Creates a polymorphic matcher that matches any NULL pointer. +inline PolymorphicMatcher IsNull() { + return MakePolymorphicMatcher(internal::IsNullMatcher()); +} + // Creates a polymorphic matcher that matches any non-NULL pointer. // This is convenient as Not(NULL) doesn't compile (the compiler // thinks that that expression is comparing a pointer with an integer). diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index ef878898..fe88c643 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -78,6 +78,7 @@ using testing::FloatEq; using testing::Ge; using testing::Gt; using testing::HasSubstr; +using testing::IsNull; using testing::Key; using testing::Le; using testing::Lt; @@ -685,6 +686,32 @@ TEST(NeTest, CanDescribeSelf) { EXPECT_EQ("is not equal to 5", Describe(m)); } +// Tests that IsNull() matches any NULL pointer of any type. +TEST(IsNullTest, MatchesNullPointer) { + Matcher m1 = IsNull(); + int* p1 = NULL; + int n = 0; + EXPECT_TRUE(m1.Matches(p1)); + EXPECT_FALSE(m1.Matches(&n)); + + Matcher m2 = IsNull(); + const char* p2 = NULL; + EXPECT_TRUE(m2.Matches(p2)); + EXPECT_FALSE(m2.Matches("hi")); + + Matcher m3 = IsNull(); + void* p3 = NULL; + EXPECT_TRUE(m3.Matches(p3)); + EXPECT_FALSE(m3.Matches(reinterpret_cast(0xbeef))); +} + +// Tests that IsNull() describes itself properly. +TEST(IsNullTest, CanDescribeSelf) { + Matcher m = IsNull(); + EXPECT_EQ("is NULL", Describe(m)); + EXPECT_EQ("is not NULL", DescribeNegation(m)); +} + // Tests that NotNull() matches any non-NULL pointer of any type. TEST(NotNullTest, MatchesNonNullPointer) { Matcher m1 = NotNull(); diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index bbac8ae2..40554bfe 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -147,6 +147,7 @@ using testing::IgnoreResult; using testing::Invoke; using testing::InvokeArgument; using testing::InvokeWithoutArgs; +using testing::IsNull; using testing::Le; using testing::Lt; using testing::Matcher; @@ -491,6 +492,13 @@ TEST(LinkTest, TestMatcherNotNull) { ON_CALL(mock, VoidFromString(NotNull())).WillByDefault(Return()); } +// Tests the linkage of the IsNull matcher. +TEST(LinkTest, TestMatcherIsNull) { + Mock mock; + + ON_CALL(mock, VoidFromString(IsNull())).WillByDefault(Return()); +} + // Tests the linkage of the Ref matcher. TEST(LinkTest, TestMatcherRef) { Mock mock; -- cgit v1.2.3 From 95b12332c345cee508a8e2b68e007280392506e0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 25 Sep 2009 18:55:50 +0000 Subject: Makes gmock work on Symbian (both 3rd & 5th editions), original patch contributed by Mika Raento. --- include/gmock/gmock-actions.h | 21 +------ include/gmock/gmock-generated-matchers.h | 14 +++-- include/gmock/gmock-generated-matchers.h.pump | 15 +++++ include/gmock/gmock-matchers.h | 88 +++++++++++++++------------ include/gmock/internal/gmock-internal-utils.h | 54 ++++++++++++++-- test/gmock-actions_test.cc | 19 ++++-- test/gmock-internal-utils_test.cc | 3 +- test/gmock-matchers_test.cc | 55 ++++++++++++----- test/gmock-printers_test.cc | 8 +-- 9 files changed, 185 insertions(+), 92 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index f7daf826..7f21a7d4 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -125,32 +125,13 @@ 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'); -// signed wchar_t and unsigned wchar_t are NOT in the C++ standard. -// Using them is a bad practice and not portable. So don't use them. -// -// Still, Google Mock is designed to work even if the user uses signed -// wchar_t or unsigned wchar_t (obviously, assuming the compiler -// supports them). -// -// To gcc, -// -// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int -// -// MSVC does not recognize signed wchar_t or unsigned wchar_t. It -// treats wchar_t as a native type usually, but treats it as the same -// as unsigned short when the compiler option /Zc:wchar_t- is -// specified. -// -// Therefore we provide a default action for wchar_t when compiled -// with gcc or _NATIVE_WCHAR_T_DEFINED is defined. -// // 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 defined(__GNUC__) || defined(_NATIVE_WCHAR_T_DEFINED) +#if GMOCK_WCHAR_T_IS_NATIVE_ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT #endif diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index b2d55768..a59e457f 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -304,11 +304,15 @@ class ElementsAreMatcher1 { typedef typename internal::StlContainerView::type::value_type Element; - const Matcher matchers[] = { - MatcherCast(e1_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 1)); + // Nokia's Symbian Compiler has a nasty bug where the object put + // in a one-element local array is not destructed when the array + // goes out of scope. This leads to obvious badness as we've + // added the linked_ptr in it to our other linked_ptrs list. + // Hence we implement ElementsAreMatcher1 specially to avoid using + // a local array. + const Matcher matcher = + MatcherCast(e1_); + return MakeMatcher(new ElementsAreMatcherImpl(&matcher, 1)); } private: diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 41294b7a..c43aa873 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -192,6 +192,19 @@ class ElementsAreMatcher$i { typedef typename internal::StlContainerView::type::value_type Element; +$if i==1 [[ + + // Nokia's Symbian Compiler has a nasty bug where the object put + // in a one-element local array is not destructed when the array + // goes out of scope. This leads to obvious badness as we've + // added the linked_ptr in it to our other linked_ptrs list. + // Hence we implement ElementsAreMatcher1 specially to avoid using + // a local array. + const Matcher matcher = + MatcherCast(e1_); + return MakeMatcher(new ElementsAreMatcherImpl(&matcher, 1)); +]] $else [[ + const Matcher matchers[] = { $for j [[ @@ -201,6 +214,8 @@ $for j [[ }; return MakeMatcher(new ElementsAreMatcherImpl(matchers, $i)); +]] + } private: diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index e2beff4e..3d82279b 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -320,47 +320,59 @@ inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { template Matcher MatcherCast(M m); -// TODO(vladl@google.com): Modify the implementation to reject casting -// Matcher to Matcher. // Implements SafeMatcherCast(). // -// This overload handles polymorphic matchers only since monomorphic -// matchers are handled by the next one. -template -inline Matcher SafeMatcherCast(M polymorphic_matcher) { - return Matcher(polymorphic_matcher); -} +// 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 only since monomorphic + // matchers are handled by the next one. + template + static inline Matcher Cast(M polymorphic_matcher) { + return Matcher(polymorphic_matcher); + } -// 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 -Matcher SafeMatcherCast(const Matcher& matcher) { - // Enforce that T can be implicitly converted to U. - GMOCK_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. - GMOCK_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 GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT; - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU; - const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; - const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; - GMOCK_COMPILE_ASSERT_( - kTIsOther || kUIsOther || - (internal::LosslessArithmeticConvertible::value), - conversion_of_arithmetic_types_must_be_lossless); - return MatcherCast(matcher); + // 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. + GMOCK_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. + GMOCK_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 GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU; + const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; + const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; + GMOCK_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. diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 39e70b3f..7b173350 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -221,6 +221,34 @@ class ImplicitlyConvertible { template const bool ImplicitlyConvertible::value; +// Symbian compilation can be done with wchar_t being either a native +// type or a typedef. Using Google Mock with OpenC without wchar_t +// should require the definition of _STLP_NO_WCHAR_T. +// +// MSVC treats wchar_t as a native type usually, but treats it as the +// same as unsigned short when the compiler option /Zc:wchar_t- is +// specified. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t +// is a native type. +#if (GTEST_OS_SYMBIAN && defined(_STLP_NO_WCHAR_T)) || \ + (defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)) +// wchar_t is a typedef. +#else +#define GMOCK_WCHAR_T_IS_NATIVE_ 1 +#endif + +// signed wchar_t and unsigned wchar_t are NOT in the C++ standard. +// Using them is a bad practice and not portable. So DON'T use them. +// +// Still, Google Mock is designed to work even if the user uses signed +// wchar_t or unsigned wchar_t (obviously, assuming the compiler +// supports them). +// +// To gcc, +// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int +#ifdef __GNUC__ +#define GMOCK_HAS_SIGNED_WCHAR_T_ 1 // signed/unsigned wchar_t are valid types. +#endif + // In what follows, we use the term "kind" to indicate whether a type // is bool, an integer type (excluding bool), a floating-point type, // or none of them. This categorization is useful for determining @@ -252,10 +280,7 @@ GMOCK_DECLARE_KIND_(unsigned int, kInteger); GMOCK_DECLARE_KIND_(long, kInteger); // NOLINT GMOCK_DECLARE_KIND_(unsigned long, kInteger); // NOLINT -// MSVC can be configured to define wchar_t as a typedef of unsigned -// short. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t is a -// native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +#if GMOCK_WCHAR_T_IS_NATIVE_ GMOCK_DECLARE_KIND_(wchar_t, kInteger); #endif @@ -679,10 +704,31 @@ class StlContainerView { static const_reference ConstReference(const Element (&array)[N]) { // Ensures that Element is not a const type. testing::StaticAssertTypeEq(); +#if GTEST_OS_SYMBIAN + // The Nokia Symbian compiler confuses itself in template instantiation + // for this call without the cast to Element*: + // function call '[testing::internal::NativeArray].NativeArray( + // {lval} const char *[4], long, testing::internal::RelationToSource)' + // does not match + // 'testing::internal::NativeArray::NativeArray( + // char *const *, unsigned int, testing::internal::RelationToSource)' + // (instantiating: 'testing::internal::ContainsMatcherImpl + // ::Matches(const char * (&)[4]) const') + // (instantiating: 'testing::internal::StlContainerView:: + // ConstReference(const char * (&)[4])') + // (and though the N parameter type is mismatched in the above explicit + // conversion of it doesn't help - only the conversion of the array). + return type(const_cast(&array[0]), N, kReference); +#else return type(array, N, kReference); +#endif // GTEST_OS_SYMBIAN } static type Copy(const Element (&array)[N]) { +#if GTEST_OS_SYMBIAN + return type(const_cast(&array[0]), N, kCopy); +#else return type(array, N, kCopy); +#endif // GTEST_OS_SYMBIAN } }; diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 5d05bc50..d3d96c6d 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -98,11 +98,13 @@ TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); -#if !GTEST_OS_WINDOWS +#if GMOCK_HAS_SIGNED_WCHAR_T_ EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); -#endif // !GTEST_OS_WINDOWS +#endif +#if GMOCK_WCHAR_T_IS_NATIVE_ EXPECT_EQ(0, BuiltInDefaultValue::Get()); +#endif EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT @@ -124,11 +126,13 @@ TEST(BuiltInDefaultValueTest, ExistsForNumericTypes) { EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); -#if !GTEST_OS_WINDOWS +#if GMOCK_HAS_SIGNED_WCHAR_T_ EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); -#endif // !GTEST_OS_WINDOWS +#endif +#if GMOCK_WCHAR_T_IS_NATIVE_ EXPECT_TRUE(BuiltInDefaultValue::Exists()); +#endif EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT @@ -395,12 +399,19 @@ class IsNotZero : public ActionInterface { // NOLINT } }; +#if !GTEST_OS_SYMBIAN +// Compiling this test on Nokia's Symbian compiler fails with: +// 'Result' is not a member of class 'testing::internal::Function' +// (point of instantiation: '@unnamed@gmock_actions_test_cc@:: +// ActionTest_CanBeConvertedToOtherActionType_Test::TestBody()') +// with no obvious fix. TEST(ActionTest, CanBeConvertedToOtherActionType) { const Action a1(new IsNotZero); // NOLINT const Action a2 = Action(a1); // NOLINT EXPECT_EQ(1, a2.Perform(make_tuple('a'))); EXPECT_EQ(0, a2.Perform(make_tuple('\0'))); } +#endif // !GTEST_OS_SYMBIAN // The following two classes are for testing MakePolymorphicAction(). diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index d3a16ad3..ac3b2dd2 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -211,7 +211,8 @@ TEST(GetRawPointerTest, WorksForSmartPointers) { TEST(GetRawPointerTest, WorksForRawPointers) { int* p = NULL; - EXPECT_EQ(NULL, GetRawPointer(p)); + // Don't use EXPECT_EQ as no NULL-testing magic on Symbian. + EXPECT_TRUE(NULL == GetRawPointer(p)); int n = 1; EXPECT_EQ(&n, GetRawPointer(&n)); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index fe88c643..20b9387f 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -699,10 +699,20 @@ TEST(IsNullTest, MatchesNullPointer) { EXPECT_TRUE(m2.Matches(p2)); EXPECT_FALSE(m2.Matches("hi")); +#if !GTEST_OS_SYMBIAN + // Nokia's Symbian compiler generates: + // gmock-matchers.h: ambiguous access to overloaded function + // gmock-matchers.h: 'testing::Matcher::Matcher(void *)' + // gmock-matchers.h: 'testing::Matcher::Matcher(const testing:: + // MatcherInterface *)' + // gmock-matchers.h: (point of instantiation: 'testing:: + // gmock_matchers_test::IsNullTest_MatchesNullPointer_Test::TestBody()') + // gmock-matchers.h: (instantiating: 'testing::PolymorphicMatc Matcher m3 = IsNull(); void* p3 = NULL; EXPECT_TRUE(m3.Matches(p3)); EXPECT_FALSE(m3.Matches(reinterpret_cast(0xbeef))); +#endif } // Tests that IsNull() describes itself properly. @@ -933,24 +943,24 @@ TEST(KeyTest, SafelyCastsInnerMatcher) { } TEST(KeyTest, InsideContainsUsingMap) { - std::map container; - container.insert(std::make_pair(1, "foo")); - container.insert(std::make_pair(2, "bar")); - container.insert(std::make_pair(4, "baz")); + std::map container; + container.insert(std::make_pair(1, 'a')); + container.insert(std::make_pair(2, 'b')); + container.insert(std::make_pair(4, 'c')); EXPECT_THAT(container, Contains(Key(1))); EXPECT_THAT(container, Not(Contains(Key(3)))); } TEST(KeyTest, InsideContainsUsingMultimap) { - std::multimap container; - container.insert(std::make_pair(1, "foo")); - container.insert(std::make_pair(2, "bar")); - container.insert(std::make_pair(4, "baz")); + std::multimap container; + container.insert(std::make_pair(1, 'a')); + container.insert(std::make_pair(2, 'b')); + container.insert(std::make_pair(4, 'c')); EXPECT_THAT(container, Not(Contains(Key(25)))); - container.insert(std::make_pair(25, "more foo")); + container.insert(std::make_pair(25, 'd')); EXPECT_THAT(container, Contains(Key(25))); - container.insert(std::make_pair(25, "more bar")); + container.insert(std::make_pair(25, 'e')); EXPECT_THAT(container, Contains(Key(25))); EXPECT_THAT(container, Contains(Key(1))); @@ -1031,13 +1041,13 @@ TEST(PairTest, SafelyCastsInnerMatchers) { } TEST(PairTest, InsideContainsUsingMap) { - std::map container; - container.insert(std::make_pair(1, "foo")); - container.insert(std::make_pair(2, "bar")); - container.insert(std::make_pair(4, "baz")); - EXPECT_THAT(container, Contains(Pair(1, "foo"))); + std::map container; + container.insert(std::make_pair(1, 'a')); + container.insert(std::make_pair(2, 'b')); + container.insert(std::make_pair(4, 'c')); + EXPECT_THAT(container, Contains(Pair(1, 'a'))); EXPECT_THAT(container, Contains(Pair(1, _))); - EXPECT_THAT(container, Contains(Pair(_, "foo"))); + EXPECT_THAT(container, Contains(Pair(_, 'a'))); EXPECT_THAT(container, Not(Contains(Pair(3, _)))); } @@ -1961,8 +1971,20 @@ TEST(MatcherAssertionTest, WorksForByRefArguments) { "Actual: 0 (is located @"); } +#if !GTEST_OS_SYMBIAN // Tests that ASSERT_THAT() and EXPECT_THAT() work when the matcher is // monomorphic. + +// ASSERT_THAT("hello", starts_with_he) fails to compile with Nokia's +// Symbian compiler: it tries to compile +// template class MatcherCastImpl { ... +// virtual bool Matches(T x) const { +// return source_matcher_.Matches(static_cast(x)); +// with U == string and T == const char* +// With ASSERT_THAT("hello"...) changed to ASSERT_THAT(string("hello") ... ) +// the compiler silently crashes with no output. +// If MatcherCastImpl is changed to use U(x) instead of static_cast(x) +// the code compiles but the converted string is bogus. TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { Matcher starts_with_he = StartsWith("he"); ASSERT_THAT("hello", starts_with_he); @@ -1976,6 +1998,7 @@ TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { "Expected: is greater than 5\n" " Actual: 5"); } +#endif // !GTEST_OS_SYMBIAN // Tests floating-point matchers. template diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 0eb8e094..4b900c57 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -840,16 +840,16 @@ TEST(PrintTupleTest, VariousSizes) { const char* const str = "8"; tuple - t10(false, 'a', 3, 4, 5, 6.5F, 7.5, str, NULL, "10"); - EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 6.5, 7.5, " + PrintPointer(str) + + t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, NULL, "10"); + EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + " pointing to \"8\", NULL, \"10\")", Print(t10)); } // Nested tuples. TEST(PrintTupleTest, NestedTuple) { - tuple, char> nested(make_tuple(5, 9.5), 'a'); - EXPECT_EQ("((5, 9.5), 'a' (97))", Print(nested)); + tuple, char> nested(make_tuple(5, true), 'a'); + EXPECT_EQ("((5, true), 'a' (97))", Print(nested)); } // Tests printing user-defined unprintable types. -- cgit v1.2.3 From f3aa4d2934a485d756d5709feb97ea6146fe08d6 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 25 Sep 2009 22:34:47 +0000 Subject: Implements the MockFunction class. --- include/gmock/gmock-generated-function-mockers.h | 111 +++++++++++++++++++++ .../gmock/gmock-generated-function-mockers.h.pump | 49 +++++++++ test/gmock-generated-function-mockers_test.cc | 44 ++++++++ 3 files changed, 204 insertions(+) diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index b6c1d82e..3002b6c5 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -712,6 +712,117 @@ using internal::FunctionMocker; #define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ GMOCK_METHOD10_(typename, const, ct, m, F) +// 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(). +template +class MockFunction; + +template +class MockFunction { + public: + MOCK_METHOD0_T(Call, R()); +}; + +template +class MockFunction { + public: + MOCK_METHOD1_T(Call, R(A0)); +}; + +template +class MockFunction { + public: + MOCK_METHOD2_T(Call, R(A0, A1)); +}; + +template +class MockFunction { + public: + MOCK_METHOD3_T(Call, R(A0, A1, A2)); +}; + +template +class MockFunction { + public: + MOCK_METHOD4_T(Call, R(A0, A1, A2, A3)); +}; + +template +class MockFunction { + public: + MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4)); +}; + +template +class MockFunction { + public: + MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5)); +}; + +template +class MockFunction { + public: + MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6)); +}; + +template +class MockFunction { + public: + MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7)); +}; + +template +class MockFunction { + public: + MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8)); +}; + +template +class MockFunction { + public: + MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)); +}; + } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 54b848f6..3c845632 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -198,6 +198,55 @@ $for i [[ ]] +// 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(). +template +class MockFunction; + + +$for i [[ +$range j 0..i-1 +template +class MockFunction { + public: + MOCK_METHOD$i[[]]_T(Call, R($for j, [[A$j]])); +}; + + +]] } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index 7267c10e..1ce8c451 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -66,6 +66,7 @@ using testing::Const; using testing::DoDefault; using testing::Eq; using testing::Lt; +using testing::MockFunction; using testing::Ref; using testing::Return; using testing::ReturnRef; @@ -462,5 +463,48 @@ TEST(OverloadedMockMethodTest, CanOverloadOnConstnessInMacroBody) { EXPECT_EQ(3, const_mock->Overloaded(1)); } +TEST(MockFunctionTest, WorksForVoidNullary) { + MockFunction foo; + EXPECT_CALL(foo, Call()); + foo.Call(); +} + +TEST(MockFunctionTest, WorksForNonVoidNullary) { + MockFunction foo; + EXPECT_CALL(foo, Call()) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + EXPECT_EQ(1, foo.Call()); + EXPECT_EQ(2, foo.Call()); +} + +TEST(MockFunctionTest, WorksForVoidUnary) { + MockFunction foo; + EXPECT_CALL(foo, Call(1)); + foo.Call(1); +} + +TEST(MockFunctionTest, WorksForNonVoidBinary) { + MockFunction foo; + EXPECT_CALL(foo, Call(false, 42)) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + EXPECT_CALL(foo, Call(true, Ge(100))) + .WillOnce(Return(3)); + EXPECT_EQ(1, foo.Call(false, 42)); + EXPECT_EQ(2, foo.Call(false, 42)); + EXPECT_EQ(3, foo.Call(true, 120)); +} + +TEST(MockFunctionTest, WorksFor10Arguments) { + MockFunction foo; + EXPECT_CALL(foo, Call(_, 'a', _, _, _, _, _, _, _, _)) + .WillOnce(Return(1)) + .WillOnce(Return(2)); + EXPECT_EQ(1, foo.Call(false, 'a', 0, 0, 0, 0, 0, 'b', 0, true)); + EXPECT_EQ(2, foo.Call(true, 'a', 0, 0, 0, 0, 0, 'b', 1, false)); +} + } // namespace gmock_generated_function_mockers_test } // namespace testing -- cgit v1.2.3 From 79643f51ed835bc8c897fb429a9d77a41701d7ad Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 30 Sep 2009 20:24:30 +0000 Subject: Changes gmock's version to 1.4.0. Also fixes a compiler warning. --- configure.ac | 2 +- test/gmock-printers_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d9041388..25ab6f36 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_INIT([Google C++ Mocking Framework], - [1.2.0], + [1.4.0], [googlemock@googlegroups.com], [gmock]) diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 4b900c57..c72e3d3d 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -705,7 +705,7 @@ TEST(PrintStlContainerTest, HashMultiSet) { std::vector numbers; for (size_t i = 0; i != result.length(); i++) { if (expected_pattern[i] == 'd') { - ASSERT_TRUE(isdigit(result[i])); + ASSERT_TRUE(isdigit(result[i]) != 0); numbers.push_back(result[i] - '0'); } else { EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " -- cgit v1.2.3 From 7c95d8346e9c62e9d6d7e8202fbcfb34c4404db9 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 1 Oct 2009 21:56:16 +0000 Subject: Works around a Symbian compiler bug that causes memory leak (by Mika Raento). --- include/gmock/gmock-spec-builders.h | 13 ++++++++++--- src/gmock-spec-builders.cc | 8 ++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 0748d9d4..765e06d9 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -351,10 +351,18 @@ class Mock { // - Constness is shallow: a const Expectation object itself cannot // be modified, but the mutable methods of the ExpectationBase // object it references can be called via expectation_base(). +// - The constructors and destructor are defined out-of-line because +// the Symbian WINSCW compiler wants to otherwise instantiate them +// when it sees this class definition, at which point it doesn't have +// ExpectationBase available yet, leading to incorrect destruction +// in the linked_ptr (or compilation errors if using a checking +// linked_ptr). class Expectation { public: // Constructs a null object that doesn't reference any expectation. - Expectation() {} + Expectation(); + + ~Expectation(); // This single-argument ctor must not be explicit, in order to support the // Expectation e = EXPECT_CALL(...); @@ -399,8 +407,7 @@ class Expectation { typedef ::std::set Set; Expectation( - const internal::linked_ptr& expectation_base) : - expectation_base_(expectation_base) {} + const internal::linked_ptr& expectation_base); // Returns the expectation this object references. const internal::linked_ptr& diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 72558658..6cc94ddd 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -420,6 +420,14 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj) { // needed by VerifyAndClearExpectationsLocked(). } +Expectation::Expectation() {} + +Expectation::Expectation( + const internal::linked_ptr& expectation_base) + : expectation_base_(expectation_base) {} + +Expectation::~Expectation() {} + // Adds an expectation to a sequence. void Sequence::AddExpectation(const Expectation& expectation) const { if (*last_expectation_ != expectation) { -- cgit v1.2.3 From 7db42db1c649f1613813385d4a180630ad1dc95a Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 1 Oct 2009 23:31:41 +0000 Subject: Updates the 1.4.0 release notes. --- CHANGES | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index 9845eb91..f703ac2e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,9 @@ -Changes for 1.2.0 (up to r194): +Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of +Google Test): - * New feature: own implementation of TR1 tuple (no more dependency on - Boost!). - * New feature: support for Visual C++ 7.1. + * 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. @@ -10,15 +11,16 @@ Changes for 1.2.0 (up to r194): constraints. * New feature: actions ReturnArg(), ReturnNew(...), and DeleteArg(). - * New feature: matchers Key(m), Args<...>(m), AllArgs(m), and - Contains(m). + * 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, Symbian, and gcc. + * Compatibility fixes for Mac OS X and gcc. * Bug fixes and implementation clean-ups. Changes for 1.1.0: -- cgit v1.2.3 From 6c54a5e1f91e033fa937be5d647ce43dee597ad8 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 21 Oct 2009 06:15:34 +0000 Subject: Enables more verbose output for expectations (by Sverre Sundsdal); Fixes information loss warning when compiled by VC8.0 with /Wp64; Skips two tests on Windows Mobile that don't work there. --- CONTRIBUTORS | 1 + include/gmock/gmock-spec-builders.h | 54 ++++++++++++++++++--------- src/gmock-spec-builders.cc | 6 ++- test/gmock-nice-strict_test.cc | 16 ++++---- test/gmock-spec-builders_test.cc | 74 ++++++++++++++++++++----------------- test/gmock_output_test_.cc | 4 ++ test/gmock_output_test_golden.txt | 50 ++++++++++++++----------- 7 files changed, 124 insertions(+), 81 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a661d8fa..9a8cc2e2 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -31,6 +31,7 @@ Paneendra Ba Paul Menage Piotr Kaminski Russ Rufer +Sverre Sundsdal Takeshi Yoshino Vadim Berman Vlad Losev diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 765e06d9..9cb549ab 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -561,14 +561,15 @@ extern ThreadLocal g_gmock_implicit_sequence; // This class is internal and mustn't be used by user code directly. class ExpectationBase { public: - ExpectationBase(const char* file, int line); + // source_text is the EXPECT_CALL(...) source that created this Expectation. + ExpectationBase(const char* file, int line, const string& source_text); virtual ~ExpectationBase(); // Where in the source file was the expectation spec defined? const char* file() const { return file_; } int line() const { return line_; } - + const char* source_text() const { return source_text_.c_str(); } // Returns the cardinality specified in the expectation spec. const Cardinality& cardinality() const { return cardinality_; } @@ -697,8 +698,9 @@ class ExpectationBase { // This group of fields are part of the spec and won't change after // an EXPECT_CALL() statement finishes. - const char* file_; // The file that contains the expectation. - int line_; // The line number of the expectation. + const char* file_; // The file that contains the expectation. + int line_; // The line number of the expectation. + const string source_text_; // The EXPECT_CALL(...) source text. // True iff the cardinality is specified explicitly. bool cardinality_specified_; Cardinality cardinality_; // The cardinality of the expectation. @@ -724,11 +726,13 @@ class TypedExpectation : public ExpectationBase { typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; typedef typename Function::Result Result; - TypedExpectation(FunctionMockerBase* owner, const char* file, int line, + TypedExpectation(FunctionMockerBase* owner, + const char* file, int line, const string& source_text, const ArgumentMatcherTuple& m) - : ExpectationBase(file, line), + : ExpectationBase(file, line, source_text), owner_(owner), matchers_(m), + extra_matcher_specified_(false), // By default, extra_matcher_ should match anything. However, // we cannot initialize it with _ as that triggers a compiler // bug in Symbian's C++ compiler (cannot decide between two @@ -760,6 +764,7 @@ class TypedExpectation : public ExpectationBase { last_clause_ = kWith; extra_matcher_ = m; + extra_matcher_specified_ = true; return *this; } @@ -938,6 +943,15 @@ class TypedExpectation : public ExpectationBase { << " and " << (is_retired() ? "retired" : "active"); } + + void MaybeDescribeExtraMatcherTo(::std::ostream* os) { + if (extra_matcher_specified_) { + *os << " Expected args: "; + extra_matcher_.DescribeTo(os); + *os << "\n"; + } + } + private: template friend class FunctionMockerBase; @@ -1034,7 +1048,7 @@ class TypedExpectation : public ExpectationBase { // we warn the user when the WillOnce() clauses ran out. ::std::stringstream ss; DescribeLocationTo(&ss); - ss << "Actions ran out.\n" + ss << "Actions ran out in " << source_text() << "...\n" << "Called " << count << " times, but only " << action_count << " WillOnce()" << (action_count == 1 ? " is" : "s are") << " specified - "; @@ -1078,7 +1092,7 @@ class TypedExpectation : public ExpectationBase { } // Must be done after IncrementCount()! - *what << "Expected mock function call.\n"; + *what << "Mock function call matches " << source_text() <<"...\n"; return GetCurrentAction(mocker, args); } @@ -1123,7 +1137,7 @@ class TypedExpectation : public ExpectationBase { ::std::stringstream ss; DescribeLocationTo(&ss); ss << "Too " << (too_many ? "many" : "few") - << " actions specified.\n" + << " actions specified in " << source_text() << "...\n" << "Expected to be "; cardinality().DescribeTo(&ss); ss << ", but has " << (too_many ? "" : "only ") @@ -1141,6 +1155,7 @@ class TypedExpectation : public ExpectationBase { // statement finishes. FunctionMockerBase* const owner_; ArgumentMatcherTuple matchers_; + bool extra_matcher_specified_; Matcher extra_matcher_; std::vector > actions_; bool repeated_action_specified_; // True if a WillRepeatedly() was specified. @@ -1186,9 +1201,10 @@ class MockSpec { // the newly created spec. internal::TypedExpectation& InternalExpectedAt( const char* file, int line, const char* obj, const char* call) { - LogWithLocation(internal::INFO, file, line, - string("EXPECT_CALL(") + obj + ", " + call + ") invoked"); - return function_mocker_->AddNewExpectation(file, line, matchers_); + const string source_text(string("EXPECT_CALL(") + obj + ", " + call + ")"); + LogWithLocation(internal::INFO, file, line, source_text + " invoked"); + return function_mocker_->AddNewExpectation( + file, line, source_text, matchers_); } private: @@ -1440,11 +1456,13 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Adds and returns an expectation spec for this mock function. // L < g_gmock_mutex TypedExpectation& AddNewExpectation( - const char* file, int line, + const char* file, + int line, + const string& source_text, const ArgumentMatcherTuple& m) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); const linked_ptr > expectation( - new TypedExpectation(this, file, line, m)); + new TypedExpectation(this, file, line, source_text, m)); expectations_.push_back(expectation); // Adds this expectation into the implicit sequence if there is one. @@ -1584,9 +1602,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { *why << "\n"; expectations_[i]->DescribeLocationTo(why); if (count > 1) { - *why << "tried expectation #" << i; + *why << "tried expectation #" << i << ": "; } - *why << "\n"; + *why << expectations_[i]->source_text() << "...\n"; expectations_[i]->DescribeMatchResultTo(args, why); expectations_[i]->DescribeCallCountTo(why); } @@ -1651,10 +1669,12 @@ bool FunctionMockerBase::VerifyAndClearExpectationsLocked() { } else if (!exp->IsSatisfied()) { expectations_met = false; ::std::stringstream ss; - ss << "Actual function call count doesn't match this expectation.\n"; + ss << "Actual function call count doesn't match " + << exp->source_text() << "...\n"; // No need to show the source file location of the expectation // in the description, as the Expect() call that follows already // takes care of it. + exp->MaybeDescribeExtraMatcherTo(&ss); exp->DescribeCallCountTo(&ss); Expect(false, exp->file(), exp->line(), ss.str()); } diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 6cc94ddd..edd60fec 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -40,6 +40,7 @@ #include // NOLINT #include #include +#include #include #include @@ -55,9 +56,12 @@ namespace internal { Mutex g_gmock_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); // Constructs an ExpectationBase object. -ExpectationBase::ExpectationBase(const char* file, int line) +ExpectationBase::ExpectationBase(const char* file, + int line, + const string& source_text) : file_(file), line_(line), + source_text_(source_text), cardinality_specified_(false), cardinality_(Exactly(1)), call_count_(0), diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 0dc71069..faf0145b 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -173,21 +173,21 @@ TEST(NiceMockTest, NonDefaultConstructor10) { nice_bar.That(5, true); } -#if !GTEST_OS_SYMBIAN +#if !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE // Tests that NiceMock compiles where Mock is a user-defined // class (as opposed to ::testing::Mock). We had to workaround an // MSVC 8.0 bug that caused the symbol Mock used in the definition of // NiceMock to be looked up in the wrong context, and this test // ensures that our fix works. // -// We have to skip this test on Symbian, as it causes the program to -// crash there, for reasons unclear to us yet. +// We have to skip this test on Symbian and Windows Mobile, as it +// causes the program to crash there, for reasons unclear to us yet. TEST(NiceMockTest, AcceptsClassNamedMock) { NiceMock< ::Mock> nice; EXPECT_CALL(nice, DoThis()); nice.DoThis(); } -#endif // !GTEST_OS_SYMBIAN +#endif // !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE // Tests that a strict mock allows expected calls. TEST(StrictMockTest, AllowsExpectedCall) { @@ -247,21 +247,21 @@ TEST(StrictMockTest, NonDefaultConstructor10) { "Uninteresting mock function call"); } -#if !GTEST_OS_SYMBIAN +#if !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE // Tests that StrictMock compiles where Mock is a user-defined // class (as opposed to ::testing::Mock). We had to workaround an // MSVC 8.0 bug that caused the symbol Mock used in the definition of // StrictMock to be looked up in the wrong context, and this test // ensures that our fix works. // -// We have to skip this test on Symbian, as it causes the program to -// crash there, for reasons unclear to us yet. +// We have to skip this test on Symbian and Windows Mobile, as it +// causes the program to crash there, for reasons unclear to us yet. TEST(StrictMockTest, AcceptsClassNamedMock) { StrictMock< ::Mock> strict; EXPECT_CALL(strict, DoThis()); strict.DoThis(); } -#endif // !GTEST_OS_SYMBIAN +#endif // !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE } // namespace gmock_nice_strict_test } // namespace testing diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 707d8968..5fd97112 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -571,29 +571,34 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooManyActions) { b.DoB(2); } const string& output = GetCapturedTestStdout(); - EXPECT_PRED_FORMAT2(IsSubstring, - "Too many actions specified.\n" - "Expected to be never called, but has 1 WillOnce().", - output); // #1 - EXPECT_PRED_FORMAT2(IsSubstring, - "Too many actions specified.\n" - "Expected to be called at most once, " - "but has 2 WillOnce()s.", - output); // #2 - EXPECT_PRED_FORMAT2(IsSubstring, - "Too many actions specified.\n" - "Expected to be called once, but has 2 WillOnce()s.", - output); // #3 - EXPECT_PRED_FORMAT2(IsSubstring, - "Too many actions specified.\n" - "Expected to be never called, but has 0 WillOnce()s " - "and a WillRepeatedly().", - output); // #4 - EXPECT_PRED_FORMAT2(IsSubstring, - "Too many actions specified.\n" - "Expected to be called once, but has 1 WillOnce() " - "and a WillRepeatedly().", - output); // #5 + EXPECT_PRED_FORMAT2( + IsSubstring, + "Too many actions specified in EXPECT_CALL(b, DoB())...\n" + "Expected to be never called, but has 1 WillOnce().", + output); // #1 + EXPECT_PRED_FORMAT2( + IsSubstring, + "Too many actions specified in EXPECT_CALL(b, DoB())...\n" + "Expected to be called at most once, " + "but has 2 WillOnce()s.", + output); // #2 + EXPECT_PRED_FORMAT2( + IsSubstring, + "Too many actions specified in EXPECT_CALL(b, DoB(1))...\n" + "Expected to be called once, but has 2 WillOnce()s.", + output); // #3 + EXPECT_PRED_FORMAT2( + IsSubstring, + "Too many actions specified in EXPECT_CALL(b, DoB())...\n" + "Expected to be never called, but has 0 WillOnce()s " + "and a WillRepeatedly().", + output); // #4 + EXPECT_PRED_FORMAT2( + IsSubstring, + "Too many actions specified in EXPECT_CALL(b, DoB(2))...\n" + "Expected to be called once, but has 1 WillOnce() " + "and a WillRepeatedly().", + output); // #5 } // Tests that Google Mock warns on having too few actions in an @@ -608,11 +613,12 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooFewActions) { CaptureTestStdout(); b.DoB(); const string& output = GetCapturedTestStdout(); - EXPECT_PRED_FORMAT2(IsSubstring, - "Too few actions specified.\n" - "Expected to be called between 2 and 3 times, " - "but has only 1 WillOnce().", - output); + EXPECT_PRED_FORMAT2( + IsSubstring, + "Too few actions specified in EXPECT_CALL(b, DoB())...\n" + "Expected to be called between 2 and 3 times, " + "but has only 1 WillOnce().", + output); b.DoB(); } @@ -688,7 +694,7 @@ TEST(ExpectCallTest, CatchesTooFewCalls) { .Times(AtLeast(2)); b.DoB(5); - }, "Actual function call count doesn't match this expectation.\n" + }, "Actual function call count doesn't match EXPECT_CALL(b, DoB(5))...\n" " Expected: to be called at least twice\n" " Actual: called once - unsatisfied and active"); } @@ -895,14 +901,14 @@ TEST(UnexpectedCallTest, GeneratesFailureForVoidFunction) { "Google Mock tried the following 2 expectations, but none matched:"); EXPECT_NONFATAL_FAILURE( a2.DoA(2), - "tried expectation #0\n" + "tried expectation #0: EXPECT_CALL(a2, DoA(1))...\n" " Expected arg #0: is equal to 1\n" " Actual: 2\n" " Expected: to be called once\n" " Actual: called once - saturated and active"); EXPECT_NONFATAL_FAILURE( a2.DoA(2), - "tried expectation #1\n" + "tried expectation #1: EXPECT_CALL(a2, DoA(3))...\n" " Expected arg #0: is equal to 3\n" " Actual: 2\n" " Expected: to be called once\n" @@ -2046,7 +2052,7 @@ TEST(VerifyAndClearExpectationsTest, SomeMethodsHaveExpectationsAndFail) { MockB b; EXPECT_CALL(b, DoB()) .WillOnce(Return(1)); - bool result; + bool result = true; EXPECT_NONFATAL_FAILURE(result = Mock::VerifyAndClearExpectations(&b), "Actual: never called"); ASSERT_FALSE(result); @@ -2084,7 +2090,7 @@ TEST(VerifyAndClearExpectationsTest, AMethodHasManyExpectations) { EXPECT_CALL(b, DoB(_)) .WillOnce(Return(2)); b.DoB(1); - bool result; + bool result = true; EXPECT_NONFATAL_FAILURE(result = Mock::VerifyAndClearExpectations(&b), "Actual: never called"); ASSERT_FALSE(result); @@ -2216,7 +2222,7 @@ TEST(VerifyAndClearTest, Failure) { .WillOnce(Return(2)); b.DoB(1); - bool result; + bool result = true; EXPECT_NONFATAL_FAILURE(result = Mock::VerifyAndClear(&b), "Actual: never called"); ASSERT_FALSE(result); diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index 8244f10b..c33dc6fb 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -161,6 +161,10 @@ TEST_F(GMockOutputTest, UnsatisfiedPrerequisites) { foo_.Bar2(1, 0); } +TEST_F(GMockOutputTest, UnsatisfiedWith) { + EXPECT_CALL(foo_, Bar2(_, _)).With(Ge()); +} + TEST_F(GMockOutputTest, UnsatisfiedExpectation) { EXPECT_CALL(foo_, Bar(_, _, _)); EXPECT_CALL(foo_, Bar2(0, _)) diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index aeec660f..ed8decac 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -3,7 +3,7 @@ FILE:#: EXPECT_CALL(foo_, Bar2(0, _)) invoked Stack trace: -FILE:#: Expected mock function call. +FILE:#: Mock function call matches EXPECT_CALL(foo_, Bar2(0, _))... Function call: Bar2(0, 0) Returns: false Stack trace: @@ -13,17 +13,17 @@ Stack trace: FILE:#: EXPECT_CALL(foo_, Bar3(0, _)) invoked Stack trace: -FILE:#: Expected mock function call. +FILE:#: Mock function call matches EXPECT_CALL(foo_, Bar3(0, _))... Function call: Bar3(0, 0) Stack trace: [ OK ] GMockOutputTest.ExpectedCallToVoidFunction [ RUN ] GMockOutputTest.ExplicitActionsRunOut GMOCK WARNING: -FILE:#: Too few actions specified. +FILE:#: Too few actions specified in EXPECT_CALL(foo_, Bar2(_, _))... Expected to be called twice, but has only 1 WillOnce(). GMOCK WARNING: -FILE:#: Actions ran out. +FILE:#: Actions ran out in EXPECT_CALL(foo_, Bar2(_, _))... Called 2 times, but only 1 WillOnce() is specified - returning default value. Stack trace: [ OK ] GMockOutputTest.ExplicitActionsRunOut @@ -35,7 +35,7 @@ Unexpected mock function call - returning default value. Returns: false Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar2(0, _))... Expected arg #0: is equal to 0 Actual: 1 Expected: to be called once @@ -48,7 +48,7 @@ Unexpected mock function call - returning directly. Function call: Bar3(1, 0) Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar3(0, _))... Expected arg #0: is equal to 0 Actual: 1 Expected: to be called once @@ -92,12 +92,12 @@ Unexpected mock function call - returning default value. Returns: false Google Mock tried the following 2 expectations, but none matched: -FILE:#: tried expectation #0 +FILE:#: tried expectation #0: EXPECT_CALL(foo_, Bar2(_, _))... Expected: the expectation is active Actual: it is retired Expected: to be called once Actual: called once - saturated and retired -FILE:#: tried expectation #1 +FILE:#: tried expectation #1: EXPECT_CALL(foo_, Bar2(0, 0))... Expected arg #0: is equal to 0 Actual: 1 Expected arg #1: is equal to 0 @@ -113,12 +113,12 @@ Unexpected mock function call - returning default value. Returns: false Google Mock tried the following 2 expectations, but none matched: -FILE:#: tried expectation #0 +FILE:#: tried expectation #0: EXPECT_CALL(foo_, Bar2(0, 0))... Expected arg #0: is equal to 0 Actual: 1 Expected: to be called once Actual: never called - unsatisfied and active -FILE:#: tried expectation #1 +FILE:#: tried expectation #1: EXPECT_CALL(foo_, Bar2(1, _))... Expected: all pre-requisites are satisfied Actual: the following immediate pre-requisites are not satisfied: FILE:#: pre-requisite #0 @@ -134,12 +134,12 @@ Unexpected mock function call - returning default value. Returns: false Google Mock tried the following 2 expectations, but none matched: -FILE:#: tried expectation #0 +FILE:#: tried expectation #0: EXPECT_CALL(foo_, Bar2(0, 0))... Expected arg #0: is equal to 0 Actual: 1 Expected: to be called once Actual: never called - unsatisfied and active -FILE:#: tried expectation #1 +FILE:#: tried expectation #1: EXPECT_CALL(foo_, Bar2(1, _))... Expected: all pre-requisites are satisfied Actual: the following immediate pre-requisites are not satisfied: FILE:#: pre-requisite #0 @@ -148,13 +148,20 @@ FILE:#: pre-requisite #1 Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.UnsatisfiedPrerequisites +[ RUN ] GMockOutputTest.UnsatisfiedWith +FILE:#: Failure +Actual function call count doesn't match EXPECT_CALL(foo_, Bar2(_, _))... + Expected args: are a pair (x, y) where x >= y + Expected: to be called once + Actual: never called - unsatisfied and active +[ FAILED ] GMockOutputTest.UnsatisfiedWith [ RUN ] GMockOutputTest.UnsatisfiedExpectation FILE:#: Failure -Actual function call count doesn't match this expectation. +Actual function call count doesn't match EXPECT_CALL(foo_, Bar2(0, _))... Expected: to be called twice Actual: called once - unsatisfied and active FILE:#: Failure -Actual function call count doesn't match this expectation. +Actual function call count doesn't match EXPECT_CALL(foo_, Bar(_, _, _))... Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.UnsatisfiedExpectation @@ -166,7 +173,7 @@ Unexpected mock function call - returning default value. Returns: '\0' Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar(Ref(s), _, Ge(0)))... Expected arg #0: references the variable @0x# "Hi" Actual: "Ho" (is located @0x#) Expected arg #2: is greater than or equal to 0 @@ -182,7 +189,7 @@ Unexpected mock function call - returning default value. Returns: false Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... Expected args: are a pair (x, y) where x >= y Actual: don't match Expected: to be called once @@ -196,7 +203,7 @@ Unexpected mock function call - returning default value. Returns: false Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... Expected arg #0: is greater than or equal to 2 Actual: 1 Expected args: are a pair (x, y) where x >= y @@ -213,7 +220,7 @@ FILE:#: Returns: false Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar2(2, 2))... Expected arg #0: is equal to 2 Actual: 1 Expected arg #1: is equal to 2 @@ -228,7 +235,7 @@ FILE:#: Returns: true Google Mock tried the following 1 expectation, but it didn't match: -FILE:#: +FILE:#: EXPECT_CALL(foo_, Bar2(2, 2))... Expected arg #0: is equal to 2 Actual: 0 Expected arg #1: is equal to 2 @@ -271,10 +278,10 @@ Stack trace: [ RUN ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction GMOCK WARNING: -FILE:#: Too few actions specified. +FILE:#: Too few actions specified in EXPECT_CALL(foo_, Bar2(_, _))... Expected to be called twice, but has only 1 WillOnce(). GMOCK WARNING: -FILE:#: Actions ran out. +FILE:#: Actions ran out in EXPECT_CALL(foo_, Bar2(_, _))... Called 2 times, but only 1 WillOnce() is specified - taking default action specified at: FILE:#: Stack trace: @@ -288,6 +295,7 @@ Stack trace: [ FAILED ] GMockOutputTest.RetiredExpectation [ FAILED ] GMockOutputTest.UnsatisfiedPrerequisite [ FAILED ] GMockOutputTest.UnsatisfiedPrerequisites +[ FAILED ] GMockOutputTest.UnsatisfiedWith [ FAILED ] GMockOutputTest.UnsatisfiedExpectation [ FAILED ] GMockOutputTest.MismatchArguments [ FAILED ] GMockOutputTest.MismatchWith -- cgit v1.2.3 From 2e7c475e1611ee9bf2ac9d6e63eeef59614bf2ca Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 6 Nov 2009 23:43:30 +0000 Subject: Adds a dummy test to gmock-port.test.cc. --- test/gmock-port_test.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 9a64ec33..fe844e72 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -36,4 +36,8 @@ #include #include -// This file intentionally contains no test at this moment. +// This file intentionally contains no tests at this moment. + +// Putting a dummy test here makes references to symbols in the gtest +// library and avoids 'undefined symbol' linker errors in gmock_main. +TEST(DummyTest, Dummy) {} -- cgit v1.2.3 From 4910d29e1e1eed4f6946871168a234be5b490163 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 10 Nov 2009 19:16:27 +0000 Subject: Makes gmock-all.cc catch errors in fuse_gmock.py. --- src/gmock-all.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gmock-all.cc b/src/gmock-all.cc index a14c397d..c9223fce 100644 --- a/src/gmock-all.cc +++ b/src/gmock-all.cc @@ -35,6 +35,11 @@ // purpose is to allow a user to build Google Mock by compiling this // file alone. +// This line ensures that gmock.h can be compiled on its own, even +// when it's fused. +#include + +// The following lines pull in the real gmock *.cc files. #include "src/gmock-cardinalities.cc" #include "src/gmock-internal-utils.cc" #include "src/gmock-matchers.cc" -- cgit v1.2.3 From 21a5846afdd19ae9907cdc7c45264c35175b1651 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 12 Nov 2009 19:18:08 +0000 Subject: Makes gmock-generated-function-mockers.h conform to the C++ standard. --- include/gmock/gmock-generated-function-mockers.h | 71 +++++++++++++++++----- .../gmock/gmock-generated-function-mockers.h.pump | 10 +-- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 3002b6c5..9f3a956c 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -42,10 +42,6 @@ #include namespace testing { - -template -class MockSpec; - namespace internal { template @@ -71,7 +67,11 @@ class FunctionMocker : public } R Invoke() { - return InvokeWith(ArgumentTuple()); + // 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()); } }; @@ -88,7 +88,11 @@ class FunctionMocker : public } R Invoke(A1 a1) { - return InvokeWith(ArgumentTuple(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)); } }; @@ -105,7 +109,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2) { - return InvokeWith(ArgumentTuple(a1, 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)); } }; @@ -123,7 +131,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3) { - return InvokeWith(ArgumentTuple(a1, a2, 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)); } }; @@ -141,7 +153,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) { - return InvokeWith(ArgumentTuple(a1, a2, a3, 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)); } }; @@ -161,7 +177,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - return InvokeWith(ArgumentTuple(a1, a2, a3, a4, 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)); } }; @@ -182,7 +202,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { - return InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, 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)); } }; @@ -203,7 +227,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { - return InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, 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)); } }; @@ -224,7 +252,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { - return InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, 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)); } }; @@ -246,7 +278,11 @@ class FunctionMocker : public } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { - return InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, 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)); } }; @@ -270,7 +306,12 @@ class FunctionMocker : public R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { - return InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9, 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)); } }; diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 3c845632..82106eb1 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -45,10 +45,6 @@ $var n = 10 $$ The maximum arity we support. #include namespace testing { - -template -class MockSpec; - namespace internal { template @@ -89,7 +85,11 @@ $if i >= 1 [[ } R Invoke($Aas) { - return InvokeWith(ArgumentTuple($as)); + // 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)); } }; -- cgit v1.2.3 From 2871bb4d34117aad6e3c30e9fa094c06bece51fc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 12 Nov 2009 19:18:48 +0000 Subject: Adds gmock_all_test.cc for compiling most gmock tests in a single file. --- test/gmock_all_test.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 test/gmock_all_test.cc diff --git a/test/gmock_all_test.cc b/test/gmock_all_test.cc new file mode 100644 index 00000000..73612591 --- /dev/null +++ b/test/gmock_all_test.cc @@ -0,0 +1,49 @@ +// Copyright 2009, 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) +// +// Tests for Google C++ Mocking Framework (Google Mock) +// +// Sometimes it's desirable to build most of Google Mock's own tests +// by compiling a single file. This file serves this purpose. +#include "test/gmock-actions_test.cc" +#include "test/gmock-cardinalities_test.cc" +#include "test/gmock-generated-actions_test.cc" +#include "test/gmock-generated-function-mockers_test.cc" +#include "test/gmock-generated-internal-utils_test.cc" +#include "test/gmock-generated-matchers_test.cc" +#include "test/gmock-internal-utils_test.cc" +#include "test/gmock-matchers_test.cc" +#include "test/gmock-more-actions_test.cc" +#include "test/gmock-nice-strict_test.cc" +#include "test/gmock-port_test.cc" +#include "test/gmock-printers_test.cc" +#include "test/gmock-spec-builders_test.cc" +#include "test/gmock_test.cc" -- cgit v1.2.3 From a070cbd91c2a8bfe7caed64e31387312a1c5df5a Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 00:09:28 +0000 Subject: Enables gmock's implicit_cast to work with source types that --- include/gmock/gmock-actions.h | 37 +++++++++++++++++++++++++++++++--- test/gmock-actions_test.cc | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 7f21a7d4..214b2912 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -310,7 +310,7 @@ class Action { // 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 cann be implicitly converted to + // to Func's and Func's return type can be implicitly converted to // F's. template explicit Action(const Action& action); @@ -425,6 +425,27 @@ class ActionAdaptor : public ActionInterface { // 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: @@ -459,12 +480,22 @@ class ReturnAction { typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; - explicit Impl(R value) : value_(value) {} + // 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. implicit_cast 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(R value) + : value_(::testing::internal::implicit_cast(value)) {} virtual Result Perform(const ArgumentTuple&) { return value_; } private: - R value_; + GMOCK_COMPILE_ASSERT_(!internal::is_reference::value, + Result_cannot_be_a_reference_type); + Result value_; }; R value_; diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index d3d96c6d..e2b1d052 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -515,6 +515,53 @@ TEST(ReturnTest, IsCovariant) { EXPECT_EQ(&derived, ret.Perform(make_tuple())); } +// Tests that the type of the value passed into Return is converted into T +// when the action is cast to Action rather than when the action is +// performed. See comments on testing::internal::ReturnAction in +// gmock-actions.h for more information. +class FromType { + public: + FromType(bool* converted) : converted_(converted) {} + bool* converted() const { return converted_; } + + private: + bool* const converted_; +}; + +class ToType { + public: + ToType(const FromType& x) { *x.converted() = true; } +}; + +TEST(ReturnTest, ConvertsArgumentWhenConverted) { + bool converted = false; + FromType x(&converted); + Action action(Return(x)); + EXPECT_TRUE(converted) << "Return must convert its argument in its own " + << "conversion operator."; + converted = false; + action.Perform(tuple<>()); + EXPECT_FALSE(converted) << "Action must NOT convert its argument " + << "when performed." ; +} + +// We do not support non-const type conversions on Symbian. See +// definition of implicit_cast in gmock-port.h for more information. +#if !GTEST_OS_SYMBIAN +class DestinationType {}; + +class SourceType { + public: + // Note: a non-const typecast operator. + operator DestinationType() { return DestinationType(); } +}; + +TEST(ReturnTest, CanConvertArgumentUsingNonConstTypeCastOperator) { + SourceType s; + Action action(Return(s)); +} +#endif // !GTEST_OS_SYMBIAN + // Tests that ReturnNull() returns NULL in a pointer-returning function. TEST(ReturnNullTest, WorksInPointerReturningFunction) { const Action a1 = ReturnNull(); -- cgit v1.2.3 From 201ac161919b2c7f464b4f966a4f1a1a2379c486 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 00:12:05 +0000 Subject: Enables gmock's implicit_cast to work with source types that have a non-const conversion operator (by Zhanyong Wan). --- include/gmock/internal/gmock-port.h | 14 +++- test/gmock-port_test.cc | 139 ++++++++++++++++++++++++++++++++++-- 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 0263491e..1bd455b2 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -99,9 +99,21 @@ namespace internal { // but the proposal was submitted too late. It will probably make // its way into the language in the future. template -inline To implicit_cast(From const &f) { +inline To implicit_cast(const From& f) { return f; } +// Nokia's compiler can't tell which version of implicit_cast to use when +// the source is a const, causing the compilation to fail with the error +// "ambiguous access to overloaded function". So we only support the const +// version of implicit_cast on Symbian. +#if !GTEST_OS_SYMBIAN +// This overload is needed in case the From type has a non-const type +// conversion operator to type To. +template +inline To implicit_cast(From& f) { + return f; +} +#endif // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index fe844e72..3d983d52 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -36,8 +36,139 @@ #include #include -// This file intentionally contains no tests at this moment. +// NOTE: if this file is left without tests for some reason, put a dummy +// test here to make references to symbols in the gtest library and avoid +// 'undefined symbol' linker errors in gmock_main: +// +// TEST(DummyTest, Dummy) {} + +namespace testing { +namespace internal { +// Needed to avoid name collisions in gmock_all_test.cc. +namespace gmock_port_test { + +class Base { + public: + // Copy constructor and assignment operator do exactly what we need, so we + // use them. + Base() : member_(0) {} + explicit Base(int n) : member_(n) {} + virtual ~Base() {} + int member() { return member_; } + + private: + int member_; +}; + +class Derived : public Base { + public: + explicit Derived(int n) : Base(n) {} +}; + +TEST(ImplicitCastTest, ConvertsPointers) { + Derived derived(0); + EXPECT_TRUE(&derived == ::testing::internal::implicit_cast(&derived)); +} + +TEST(ImplicitCastTest, CanUseInheritance) { + Derived derived(1); + Base base = ::testing::internal::implicit_cast(derived); + EXPECT_EQ(derived.member(), base.member()); +} + +// The non-const version is not enabled for Symbian since the Nokia compiler +// cannot decide which version of the overloaded implicit_cast method to use +// when the source is a const. +#if !GTEST_OS_SYMBIAN +class Castable { + public: + Castable(bool* converted) : converted_(converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + + private: + bool* const converted_; +}; + +TEST(ImplicitCastTest, CanUseNonConstCastOperator) { + bool converted = false; + Castable castable(&converted); + Base base = ::testing::internal::implicit_cast(castable); + EXPECT_TRUE(converted); +} +#endif // !GTEST_OS_SYMBIAN + +class ConstCastable { + public: + ConstCastable(bool* converted) : converted_(converted) {} + operator Base() const { + *converted_ = true; + return Base(); + } + + private: + bool* const converted_; +}; + +TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { + bool converted = false; + const ConstCastable const_castable(&converted); + Base base = ::testing::internal::implicit_cast(const_castable); + EXPECT_TRUE(converted); +} + +// The non-const version is not enabled for Symbian since the Nokia compiler +// cannot decide which version of the overloaded implicit_cast method to use +// when the source is a const. +#if !GTEST_OS_SYMBIAN +class ConstAndNonConstCastable { + public: + ConstAndNonConstCastable(bool* converted, bool* const_converted) + : converted_(converted), const_converted_(const_converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + operator Base() const { + *const_converted_ = true; + return Base(); + } + + private: + bool* const converted_; + bool* const const_converted_; +}; + +TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { + bool converted = false; + bool const_converted = false; + ConstAndNonConstCastable castable(&converted, &const_converted); + Base base = ::testing::internal::implicit_cast(castable); + EXPECT_TRUE(converted); + EXPECT_FALSE(const_converted); + + converted = false; + const_converted = false; + const ConstAndNonConstCastable const_castable(&converted, &const_converted); + base = ::testing::internal::implicit_cast(const_castable); + EXPECT_FALSE(converted); + EXPECT_TRUE(const_converted); +} +#endif // !GTEST_OS_SYMBIAN + +class To { + public: + To(bool* converted) { *converted = true; } // NOLINT +}; + +TEST(ImplicitCastTest, CanUseImplicitConstructor) { + bool converted = false; + To to = ::testing::internal::implicit_cast(&converted); + EXPECT_TRUE(converted); +} -// Putting a dummy test here makes references to symbols in the gtest -// library and avoids 'undefined symbol' linker errors in gmock_main. -TEST(DummyTest, Dummy) {} +} // namespace gmock_port_test +} // namespace internal +} // namespace testing -- cgit v1.2.3 From a63be0bd91ebbcb33635b1730a8cd8cb70fb3733 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 00:42:27 +0000 Subject: Adjusts gMock Doctor to work with Return implementation updated in r233 --- scripts/gmock_doctor.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 40512fcd..d21b9ee7 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -186,8 +186,9 @@ def _NeedToReturnNothingDiagnoser(msg): """Diagnoses the NRN disease, given the error messages by gcc.""" regex = (_FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-actions\.h.*error: return-statement with a value, ' - r'in function returning \'void\'') + r'.*gmock-actions\.h.*error: instantiation of ' + r'\'testing::internal::ReturnAction::Impl::value_\' ' + r'as type \'void\'') diagnosis = """ You are using an action that returns *something*, but it needs to return void. Please use a void-returning action instead. @@ -336,8 +337,10 @@ Did you forget to write def _NeedToUseReturnNullDiagnoser(msg): """Diagnoses the NRNULL disease, given the error messages by gcc.""" - regex = (_FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-actions\.h.*error: invalid conversion from ' + regex = ('instantiated from \'testing::internal::ReturnAction' + '::operator testing::Action\(\) const.*\n' + + _FILE_LINE_RE + r'instantiated from here\n' + r'.*gmock-port\.h.*error: invalid conversion from ' r'\'long int\' to \'(?P.+\*)') diagnosis = """ You are probably calling Return(NULL) and the compiler isn't sure how to turn -- cgit v1.2.3 From 79b83505bcf73bf2903ebf2e2f82cb1e1f181816 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 00:43:37 +0000 Subject: Updates IsNull and NotNull matchers to work with smart pointers. --- include/gmock/gmock-matchers.h | 12 ++++++------ test/gmock-matchers_test.cc | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 3d82279b..deb09463 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -633,12 +633,12 @@ GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "not equal to"); #undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_ -// Implements the polymorphic IsNull() matcher, which matches any +// Implements the polymorphic IsNull() matcher, which matches any raw or smart // pointer that is NULL. class IsNullMatcher { public: - template - bool Matches(T* p) const { return p == NULL; } + template + bool Matches(const Pointer& p) const { return GetRawPointer(p) == NULL; } void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } void DescribeNegationTo(::std::ostream* os) const { @@ -646,12 +646,12 @@ class IsNullMatcher { } }; -// Implements the polymorphic NotNull() matcher, which matches any +// Implements the polymorphic NotNull() matcher, which matches any raw or smart // pointer that is not NULL. class NotNullMatcher { public: - template - bool Matches(T* p) const { return p != NULL; } + template + bool Matches(const Pointer& p) const { return GetRawPointer(p) != NULL; } void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } void DescribeNegationTo(::std::ostream* os) const { diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 20b9387f..08cbcb64 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -121,6 +121,7 @@ using testing::internal::ValidateMatcherDescription; using testing::internal::kInvalidInterpolation; using testing::internal::kPercentInterpolation; using testing::internal::kTupleInterpolation; +using testing::internal::linked_ptr; using testing::internal::string; #ifdef GMOCK_HAS_REGEX @@ -715,6 +716,24 @@ TEST(IsNullTest, MatchesNullPointer) { #endif } +TEST(IsNullTest, LinkedPtr) { + const Matcher > m = IsNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new int); + + EXPECT_TRUE(m.Matches(null_p)); + EXPECT_FALSE(m.Matches(non_null_p)); +} + +TEST(IsNullTest, ReferenceToConstLinkedPtr) { + const Matcher&> m = IsNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new double); + + EXPECT_TRUE(m.Matches(null_p)); + EXPECT_FALSE(m.Matches(non_null_p)); +} + // Tests that IsNull() describes itself properly. TEST(IsNullTest, CanDescribeSelf) { Matcher m = IsNull(); @@ -736,6 +755,24 @@ TEST(NotNullTest, MatchesNonNullPointer) { EXPECT_TRUE(m2.Matches("hi")); } +TEST(NotNullTest, LinkedPtr) { + const Matcher > m = NotNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new int); + + EXPECT_FALSE(m.Matches(null_p)); + EXPECT_TRUE(m.Matches(non_null_p)); +} + +TEST(NotNullTest, ReferenceToConstLinkedPtr) { + const Matcher&> m = NotNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new double); + + EXPECT_FALSE(m.Matches(null_p)); + EXPECT_TRUE(m.Matches(non_null_p)); +} + // Tests that NotNull() describes itself properly. TEST(NotNullTest, CanDescribeSelf) { Matcher m = NotNull(); -- cgit v1.2.3 From b006f165b1efd34a7d40957a3ded577fcfef4af1 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 00:44:26 +0000 Subject: Adds SCons build files for Google Mock --- scons/SConscript | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ scons/SConstruct | 99 +++++++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 scons/SConscript create mode 100644 scons/SConstruct diff --git a/scons/SConscript b/scons/SConscript new file mode 100644 index 00000000..80891209 --- /dev/null +++ b/scons/SConscript @@ -0,0 +1,216 @@ +# -*- Python -*- +# +# 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. + + +"""Builds the Google Mock (gmock) lib. + +You should be able to call this file from more or less any SConscript +file. + +You can optionally set a variable on the construction environment to +have the unit test executables copied to your output directory. The +variable should be env['EXE_OUTPUT']. + +Another optional variable is env['LIB_OUTPUT']. If set, the generated +libraries are copied to the folder indicated by the variable. + +If you place the Google Mock sources within your own project's source +directory, you should be able to call this SConscript file simply as +follows: + +# -- cut here -- +# Build gmock library; first tell it where to copy executables. +env['EXE_OUTPUT'] = '#/mybuilddir/mybuildmode' # example, optional +env['LIB_OUTPUT'] = '#/mybuilddir/mybuildmode/lib' +env.SConscript('whateverpath/gmock/scons/SConscript') +# -- cut here -- + +If on the other hand you place the Google Mock sources in a directory +outside of your project's source tree, you would use a snippet similar +to the following: + +# -- cut here -- + +# The following assumes that $BUILD_DIR refers to the root of the +# directory for your current build mode, e.g. "#/mybuilddir/mybuildmode" + +# Build gmock library; as it is outside of our source root, we need to +# tell SCons that the directory it will refer to as +# e.g. $BUILD_DIR/gmock is actually on disk in original form as +# ../../gmock (relative to your project root directory). Recall that +# SCons by default copies all source files into the build directory +# before building. +gmock_dir = env.Dir('$BUILD_DIR/gmock') + +# Modify this part to point to Google Mock relative to the current +# SConscript or SConstruct file's directory. The ../.. path would +# be different per project, to locate the base directory for Google Mock. +gmock_dir.addRepository(env.Dir('../../gmock')) + +# Tell the Google Mock SCons file where to copy executables. +env['EXE_OUTPUT'] = '$BUILD_DIR' # example, optional + +# Call the Google Mock SConscript to build gmock.lib and unit tests. The +# location of the library should end up as +# '$BUILD_DIR/gmock/scons/gmock.lib' +env.SConscript(env.File('scons/SConscript', gmock_dir)) + +# -- cut here -- +""" + + +__author__ = 'joi@google.com (Joi Sigurdsson)' + + +import os + +############################################################ +# Environments for building the targets, sorted by name. + +Import('env', 'gtest_exports') + +GTEST_DIR = env['GTEST_DIR'] + +GtestObject = gtest_exports['GtestObject'] +GtestBinary = gtest_exports['GtestBinary'] +GtestTest = gtest_exports['GtestTest'] + +gtest_common_exports = SConscript(GTEST_DIR + '/scons/SConscript.common') +EnvCreator = gtest_common_exports['EnvCreator'] + +# TODO(vladl@google.com): restore warnings as errors once all warnings are fixed +# in gMock. +env = EnvCreator.Create(env, EnvCreator.WarningOk) + +# Note: The relative paths in SConscript files are relative to the location +# of the SConscript file itself. To make a path relative to the location of +# the main SConstruct file, prepend the path with the # sign. +# +# Include paths to gtest headers are relative to either the gmock +# directory or the 'include' subdirectory of it, and this SConscript +# file is one directory deeper than the gmock directory. +env.Prepend(CPPPATH = ['..', '../include', GTEST_DIR + '/include']) + +env_use_own_tuple = EnvCreator.Create(env, EnvCreator.UseOwnTuple) +env_with_exceptions = EnvCreator.Create(env, EnvCreator.WithExceptions) +env_without_rtti = EnvCreator.Create(env, EnvCreator.NoRtti) + +############################################################ +# Helpers for creating build targets. + +def GmockStaticLibraries(build_env): + """Builds static libraries for gmock and gmock_main in build_env. + + Args: + build_env: An environment in which to build libraries. + + Returns: + A pair (gmock_library, gmock_main_library) built in the build_env + environment. + """ + + gmock_object = GtestObject(build_env, '../src/gmock-all.cc') + gmock_main_object = GtestObject(build_env, '../src/gmock_main.cc') + + return (build_env.StaticLibrary(target='gmock' + build_env['OBJ_SUFFIX'], + source=[gmock_object]), + build_env.StaticLibrary(target='gmock_main' + build_env['OBJ_SUFFIX'], + source=[gmock_object, gmock_main_object])) + + +############################################################ +# Object and library targets. + +gtest = gtest_exports['gtest'] +gtest_ex = gtest_exports['gtest_ex'] +gtest_no_rtti = gtest_exports['gtest_no_rtti'] +gtest_use_own_tuple = gtest_exports['gtest_use_own_tuple'] + +# gmock.lib to be used by most apps (if you have your own main function). +# gmock_main.lib can be used if you just want a basic main function; it is +# also used by some tests for Google Test itself. +gmock, gmock_main = GmockStaticLibraries(env) +gmock_ex, gmock_main_ex = GmockStaticLibraries(env_with_exceptions) +gmock_no_rtti, gmock_main_no_rtti = GmockStaticLibraries(env_without_rtti) +gmock_use_own_tuple, gmock_main_use_own_tuple = GmockStaticLibraries( + env_use_own_tuple) + +# Install the libraries if needed. +if 'LIB_OUTPUT' in env.Dictionary(): + env.Install('$LIB_OUTPUT', source=[gmock, gmock_main, + gmock_ex, gmock_main_ex, + gmock_no_rtti, gmock_main_no_rtti, + gmock_use_own_tuple, + gmock_main_use_own_tuple]) + +############################################################# +# Test targets using the standard environment. +GtestTest(env, 'gmock-actions_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-cardinalities_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-generated-actions_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-generated-function-mockers_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-generated-internal-utils_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-generated-matchers_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-internal-utils_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-matchers_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-more-actions_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-nice-strict_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-port_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-printers_test', [gtest, gmock_main]) +GtestTest(env, 'gmock-spec-builders_test', [gtest, gmock_main]) +GtestTest(env, 'gmock_leak_test_', [gtest, gmock_main]) +GtestTest(env, 'gmock_link_test', [gtest, gmock_main], + ['../test/gmock_link2_test.cc']) +GtestTest(env, 'gmock_output_test_', [gtest, gmock]) +#GtestTest(env, 'gmock_stress_test', [gtest, gmock]) +GtestTest(env, 'gmock_test', [gtest, gmock_main]) +# gmock_all_test is commented to save time building and running tests. +# Uncomment if necessary. +#GtestTest(env, 'gmock_all_test', [gtest, gmock_main]) +# TODO (vladl): Add a test verifying that gmock can be built from +# testing/base/gunit.cc and testing/base/internal/gmock-all.cc after merging +# into the main branch. This is the API for Windows users. + +############################################################ +# Tests targets using custom environments. +GtestBinary(env_with_exceptions, + 'gmock-more-actions-ex_test', + [gtest_ex, gmock_main_ex], + ['../test/gmock-more-actions_test.cc']) + +GtestBinary(env_without_rtti, + 'gmock_no_rtti_test', + [gtest_no_rtti, gmock_main_no_rtti], + ['../test/gmock-spec-builders_test.cc']) + +GtestBinary(env_use_own_tuple, + 'gmock_use_own_tuple_test', + [gtest_use_own_tuple, gmock_main_use_own_tuple], + ['../test/gmock-spec-builders_test.cc']) diff --git a/scons/SConstruct b/scons/SConstruct new file mode 100644 index 00000000..71707fc7 --- /dev/null +++ b/scons/SConstruct @@ -0,0 +1,99 @@ +# -*- Python -*- +# 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: joi@google.com (Joi Sigurdsson) +# Author: vladl@google.com (Vlad Losev) +# +# Build file for Google Mock and its tests. +# +# Usage: +# cd to the directory with this file, then +# ./scons.py [OPTIONS] +# +# where frequently used command-line options include: +# -h print usage help. +# BUILD=all build all build types. +# BUILD=win-opt build the given build type. + +EnsurePythonVersion(2, 3) + +# Path to the Google Test code this Google Mock will use. +GTEST_DIR = '../gtest' + +# TODO(vladl@google.com): Factor the looping logic out for reuse. +def BuildGMockSelectedEnvironments(sconstruct_helper): + # Build using whichever environments the 'BUILD' option selected + for build_name in sconstruct_helper.env_base['BUILD']: + print 'BUILDING %s' % build_name + env = sconstruct_helper.env_dict[build_name] + + # Make sure SConscript files can refer to base build dir + env['MAIN_DIR'] = env.Dir(env['BUILD_DIR']) + + #print 'CCFLAGS: %s' % env.subst('$CCFLAGS') + #print 'LINK: %s' % env.subst('$LINK') + #print 'AR: %s' % env.subst('$AR') + #print 'CC: %s' % env.subst('$CC') + #print 'CXX: %s' % env.subst('$CXX') + #print 'LIBPATH: %s' % env.subst('$LIBPATH') + #print 'ENV:PATH: %s' % env['ENV']['PATH'] + #print 'ENV:INCLUDE: %s' % env['ENV']['INCLUDE'] + #print 'ENV:LIB: %s' % env['ENV']['LIB'] + #print 'ENV:TEMP: %s' % env['ENV']['TEMP'] + + env['GTEST_DIR'] = '#/' + GTEST_DIR + env['GTEST_BUILD_TESTS'] = False + Export('env') + # Invokes SConscript with variant_dir being build/. + # Counter-intuitively, src_dir is relative to the build dir and has + # to be '../..' to point to the scons directory. + VariantDir(env['BUILD_DIR'], '../..', duplicate=0) + gtest_exports = env.SConscript(env['BUILD_DIR'] + '/gtest/scons/SConscript') + Export('gtest_exports') + SConscript('SConscript', + src_dir='../..', + variant_dir=env['BUILD_DIR'], + duplicate=0) + +sconstruct_helper = SConscript(GTEST_DIR + '/scons/SConstruct.common') + +sconstruct_helper.Initialize(build_root_path='..', + support_multiple_win_builds=False) + +win_base = sconstruct_helper.MakeWinBaseEnvironment() + +if win_base.get('MSVS_VERSION', None) == '7.1': + sconstruct_helper.EnvCreator.WithExceptions(win_base) + +sconstruct_helper.MakeWinDebugEnvironment(win_base, 'win-dbg') +sconstruct_helper.MakeWinOptimizedEnvironment(win_base, 'win-opt') + +sconstruct_helper.ConfigureGccEnvironments() + +BuildGMockSelectedEnvironments(sconstruct_helper) -- cgit v1.2.3 From e56daa7de1d85c35d1cdc252b500ab276b5c1c9c Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 01:08:08 +0000 Subject: Tests NotNull/IsNull with testing::internal::scoped_ptr. --- test/gmock-matchers_test.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 08cbcb64..919ce651 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -122,6 +122,7 @@ using testing::internal::kInvalidInterpolation; using testing::internal::kPercentInterpolation; using testing::internal::kTupleInterpolation; using testing::internal::linked_ptr; +using testing::internal::scoped_ptr; using testing::internal::string; #ifdef GMOCK_HAS_REGEX @@ -734,6 +735,15 @@ TEST(IsNullTest, ReferenceToConstLinkedPtr) { EXPECT_FALSE(m.Matches(non_null_p)); } +TEST(IsNullTest, ReferenceToConstScopedPtr) { + const Matcher&> m = IsNull(); + const scoped_ptr null_p; + const scoped_ptr non_null_p(new double); + + EXPECT_TRUE(m.Matches(null_p)); + EXPECT_FALSE(m.Matches(non_null_p)); +} + // Tests that IsNull() describes itself properly. TEST(IsNullTest, CanDescribeSelf) { Matcher m = IsNull(); @@ -773,6 +783,15 @@ TEST(NotNullTest, ReferenceToConstLinkedPtr) { EXPECT_TRUE(m.Matches(non_null_p)); } +TEST(NotNullTest, ReferenceToConstScopedPtr) { + const Matcher&> m = NotNull(); + const scoped_ptr null_p; + const scoped_ptr non_null_p(new double); + + EXPECT_FALSE(m.Matches(null_p)); + EXPECT_TRUE(m.Matches(non_null_p)); +} + // Tests that NotNull() describes itself properly. TEST(NotNullTest, CanDescribeSelf) { Matcher m = NotNull(); -- cgit v1.2.3 From 19eb9e9e3d4d5a4f0eee786d7664ca0e45137390 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 24 Nov 2009 20:23:18 +0000 Subject: Pulls in gtest r344; improves implicit_cast (by Zhanyong Wan); makes the Python tests work on Windows (by Vlad Losev); adds run_tests.py (by Vlad Losev). --- include/gmock/internal/gmock-port.h | 40 ++++++------------ run_tests.py | 82 +++++++++++++++++++++++++++++++++++++ scripts/gmock_doctor.py | 6 +-- test/gmock-actions_test.cc | 4 -- test/gmock-port_test.cc | 10 ----- test/gmock_leak_test.py | 50 ++++++++++++---------- test/gmock_output_test.py | 67 ++++-------------------------- test/gmock_test_utils.py | 40 ++++++++++++++++-- 8 files changed, 171 insertions(+), 128 deletions(-) create mode 100755 run_tests.py diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 1bd455b2..0cff73fe 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -81,39 +81,22 @@ namespace internal { #error "At least Visual C++ 2003 (7.1) is required to compile Google Mock." #endif -// Use implicit_cast as a safe version of static_cast or const_cast -// for upcasting in the type hierarchy (i.e. casting a pointer to Foo -// to a pointer to SuperclassOfFoo or casting a pointer to Foo to -// a const pointer to Foo). -// When you use implicit_cast, the compiler checks that the cast is safe. -// Such explicit implicit_casts are necessary in surprisingly many -// situations where C++ demands an exact type match instead of an -// argument type convertable to a target type. -// -// The From type can be inferred, so the preferred syntax for using -// implicit_cast is the same as for static_cast etc.: +// Use implicit_cast as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use implicit_cast, the compiler checks that +// the cast is safe. Such explicit implicit_casts are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using implicit_cast is the same as for static_cast: // // implicit_cast(expr) // // implicit_cast would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. -template -inline To implicit_cast(const From& f) { - return f; -} -// Nokia's compiler can't tell which version of implicit_cast to use when -// the source is a const, causing the compilation to fail with the error -// "ambiguous access to overloaded function". So we only support the const -// version of implicit_cast on Symbian. -#if !GTEST_OS_SYMBIAN -// This overload is needed in case the From type has a non-const type -// conversion operator to type To. -template -inline To implicit_cast(From& f) { - return f; -} -#endif +template +inline To implicit_cast(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts @@ -139,7 +122,8 @@ inline To down_cast(From* f) { // so we only accept pointers // optimized build at run-time, as it will be optimized away // completely. if (false) { - implicit_cast(0); + const To to = NULL; + implicit_cast(to); } #if GTEST_HAS_RTTI diff --git a/run_tests.py b/run_tests.py new file mode 100755 index 00000000..42dc14bf --- /dev/null +++ b/run_tests.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# +# 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. + +"""Runs the specified tests for Google Mock. + +This script requires Python 2.3 or higher. To learn the usage, run it +with -h. +""" + +__author__ = 'vladl@google.com (Vlad Losev)' + + +import os +import sys + +SCRIPT_DIR = os.path.dirname(__file__) or '.' + +# Path to the Google Test code this Google Mock will use. We assume the +# gtest/ directory is either a subdirectory (possibly via a symbolic link) +# of gmock/ or a sibling. +# +# isdir resolves symbolic links. +if os.path.isdir(os.path.join(SCRIPT_DIR, 'gtest/test')): + RUN_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, 'gtest/test') +else: + RUN_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, '../gtest/test') + +sys.path.append(RUN_TESTS_UTIL_DIR) +import run_tests_util + +def GetGmockBuildDir(injected_os, script_dir, config): + return injected_os.path.normpath(injected_os.path.join(script_dir, + 'scons/build', + config, + 'gmock/scons')) + + +def _Main(): + """Runs all tests for Google Mock.""" + + options, args = run_tests_util.ParseArgs('gtest') + test_runner = run_tests_util.TestRunner( + script_dir=SCRIPT_DIR, + build_dir_var_name='GMOCK_BUILD_DIR', + injected_build_dir_finder=GetGmockBuildDir) + tests = test_runner.GetTestsToRun(args, + options.configurations, + options.built_configurations) + if not tests: + sys.exit(1) # Incorrect parameters given, abort execution. + + sys.exit(test_runner.RunTests(tests[0], tests[1])) + +if __name__ == '__main__': + _Main() diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index d21b9ee7..74af1083 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -340,11 +340,11 @@ def _NeedToUseReturnNullDiagnoser(msg): regex = ('instantiated from \'testing::internal::ReturnAction' '::operator testing::Action\(\) const.*\n' + _FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-port\.h.*error: invalid conversion from ' - r'\'long int\' to \'(?P.+\*)') + r'.*error: no matching function for call to \'implicit_cast\(' + r'long int&\)') diagnosis = """ You are probably calling Return(NULL) and the compiler isn't sure how to turn -NULL into a %(type)s*. Use ReturnNull() instead. +NULL into the right type. Use ReturnNull() instead. Note: the line number may be off; please fix all instances of Return(NULL).""" return _GenericDiagnoser('NRNULL', 'Need to use ReturnNull', regex, diagnosis, msg) diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index e2b1d052..1be4a16c 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -545,9 +545,6 @@ TEST(ReturnTest, ConvertsArgumentWhenConverted) { << "when performed." ; } -// We do not support non-const type conversions on Symbian. See -// definition of implicit_cast in gmock-port.h for more information. -#if !GTEST_OS_SYMBIAN class DestinationType {}; class SourceType { @@ -560,7 +557,6 @@ TEST(ReturnTest, CanConvertArgumentUsingNonConstTypeCastOperator) { SourceType s; Action action(Return(s)); } -#endif // !GTEST_OS_SYMBIAN // Tests that ReturnNull() returns NULL in a pointer-returning function. TEST(ReturnNullTest, WorksInPointerReturningFunction) { diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 3d983d52..b2afb932 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -76,10 +76,6 @@ TEST(ImplicitCastTest, CanUseInheritance) { EXPECT_EQ(derived.member(), base.member()); } -// The non-const version is not enabled for Symbian since the Nokia compiler -// cannot decide which version of the overloaded implicit_cast method to use -// when the source is a const. -#if !GTEST_OS_SYMBIAN class Castable { public: Castable(bool* converted) : converted_(converted) {} @@ -98,7 +94,6 @@ TEST(ImplicitCastTest, CanUseNonConstCastOperator) { Base base = ::testing::internal::implicit_cast(castable); EXPECT_TRUE(converted); } -#endif // !GTEST_OS_SYMBIAN class ConstCastable { public: @@ -119,10 +114,6 @@ TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { EXPECT_TRUE(converted); } -// The non-const version is not enabled for Symbian since the Nokia compiler -// cannot decide which version of the overloaded implicit_cast method to use -// when the source is a const. -#if !GTEST_OS_SYMBIAN class ConstAndNonConstCastable { public: ConstAndNonConstCastable(bool* converted, bool* const_converted) @@ -156,7 +147,6 @@ TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { EXPECT_FALSE(converted); EXPECT_TRUE(const_converted); } -#endif // !GTEST_OS_SYMBIAN class To { public: diff --git a/test/gmock_leak_test.py b/test/gmock_leak_test.py index 1337e0b0..429cc6ad 100755 --- a/test/gmock_leak_test.py +++ b/test/gmock_leak_test.py @@ -33,51 +33,59 @@ __author__ = 'wan@google.com (Zhanyong Wan)' -import gmock_test_utils import os import unittest -IS_WINDOWS = os.name == 'nt' +import gmock_test_utils -if IS_WINDOWS: - # TODO(wan@google.com): test the opt build too. We should do it - # when Vlad Losev's work on Google Test's Python test driver is - # done, such that we can reuse the work. - PROGRAM = r'..\build.dbg\gmock_leak_test_.exe' -else: - PROGRAM = 'gmock_leak_test_' -PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) -TEST_WITH_EXPECT_CALL = PROGRAM_PATH + ' --gtest_filter=*ExpectCall*' -TEST_WITH_ON_CALL = PROGRAM_PATH + ' --gtest_filter=*OnCall*' -TEST_MULTIPLE_LEAKS = PROGRAM_PATH + ' --gtest_filter=*MultipleLeaked*' +PROGRAM_PATH = gmock_test_utils.GetTestExecutablePath('gmock_leak_test_') +TEST_WITH_EXPECT_CALL = [PROGRAM_PATH, '--gtest_filter=*ExpectCall*'] +TEST_WITH_ON_CALL = [PROGRAM_PATH, '--gtest_filter=*OnCall*'] +TEST_MULTIPLE_LEAKS = [PROGRAM_PATH, '--gtest_filter=*MultipleLeaked*'] class GMockLeakTest(unittest.TestCase): def testCatchesLeakedMockByDefault(self): - self.assertNotEqual(os.system(TEST_WITH_EXPECT_CALL), 0) - self.assertNotEqual(os.system(TEST_WITH_ON_CALL), 0) + self.assertNotEqual( + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL).exit_code) + self.assertNotEqual( + 0, + gmock_test_utils.Subprocess(TEST_WITH_ON_CALL).exit_code) def testDoesNotCatchLeakedMockWhenDisabled(self): self.assertEquals( - 0, os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=0')) + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL + + ['--gmock_catch_leaked_mocks=0']).exit_code) self.assertEquals( - 0, os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks=0')) + 0, + gmock_test_utils.Subprocess(TEST_WITH_ON_CALL + + ['--gmock_catch_leaked_mocks=0']).exit_code) def testCatchesLeakedMockWhenEnabled(self): self.assertNotEqual( - os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks'), 0) + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL + + ['--gmock_catch_leaked_mocks']).exit_code) self.assertNotEqual( - os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks'), 0) + 0, + gmock_test_utils.Subprocess(TEST_WITH_ON_CALL + + ['--gmock_catch_leaked_mocks']).exit_code) def testCatchesLeakedMockWhenEnabledWithExplictFlagValue(self): self.assertNotEqual( - os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=1'), 0) + 0, + gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL + + ['--gmock_catch_leaked_mocks=1']).exit_code) def testCatchesMultipleLeakedMocks(self): self.assertNotEqual( - os.system(TEST_MULTIPLE_LEAKS + ' --gmock_catch_leaked_mocks'), 0) + 0, + gmock_test_utils.Subprocess(TEST_MULTIPLE_LEAKS + + ['--gmock_catch_leaked_mocks']).exit_code) if __name__ == '__main__': diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py index f43f7074..c5f05b34 100755 --- a/test/gmock_output_test.py +++ b/test/gmock_output_test.py @@ -40,29 +40,21 @@ SYNOPSIS __author__ = 'wan@google.com (Zhanyong Wan)' -import gmock_test_utils import os import re -import string import sys import unittest +import gmock_test_utils + # The flag for generating the golden file GENGOLDEN_FLAG = '--gengolden' -IS_WINDOWS = os.name == 'nt' - -if IS_WINDOWS: - PROGRAM = r'..\build.dbg\gmock_output_test_.exe' -else: - PROGRAM = 'gmock_output_test_' - -PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) -COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0 --gtest_print_time=0' +PROGRAM_PATH = gmock_test_utils.GetTestExecutablePath('gmock_output_test_') +COMMAND = [PROGRAM_PATH, '--gtest_stack_trace_depth=0', '--gtest_print_time=0'] GOLDEN_NAME = 'gmock_output_test_golden.txt' -GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), - GOLDEN_NAME) +GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), GOLDEN_NAME) def ToUnixLineEnding(s): @@ -144,51 +136,10 @@ def GetNormalizedOutputAndLeakyTests(output): return (RemoveTestNamesOfLeakedMocks(output), GetLeakyTests(output)) -def IterShellCommandOutput(cmd, stdin_string=None): - """Runs a command in a sub-process, and iterates the lines in its STDOUT. - - Args: - - cmd: The shell command. - stdin_string: The string to be fed to the STDIN of the sub-process; - If None, the sub-process will inherit the STDIN - from the parent process. - """ - - # Spawns cmd in a sub-process, and gets its standard I/O file objects. - stdin_file, stdout_file = os.popen2(cmd, 'b') - - # If the caller didn't specify a string for STDIN, gets it from the - # parent process. - if stdin_string is None: - stdin_string = sys.stdin.read() - - # Feeds the STDIN string to the sub-process. - stdin_file.write(stdin_string) - stdin_file.close() - - while True: - line = stdout_file.readline() - if not line: # EOF - stdout_file.close() - break - - yield line - - -def GetShellCommandOutput(cmd, stdin_string=None): - """Runs a command in a sub-process, and returns its STDOUT in a string. - - Args: - - cmd: The shell command. - stdin_string: The string to be fed to the STDIN of the sub-process; - If None, the sub-process will inherit the STDIN - from the parent process. - """ +def GetShellCommandOutput(cmd): + """Runs a command in a sub-process, and returns its STDOUT in a string.""" - lines = list(IterShellCommandOutput(cmd, stdin_string)) - return string.join(lines, '') + return gmock_test_utils.Subprocess(cmd, capture_stderr=False).output def GetNormalizedCommandOutputAndLeakyTests(cmd): @@ -200,7 +151,7 @@ def GetNormalizedCommandOutputAndLeakyTests(cmd): # Disables exception pop-ups on Windows. os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' - return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd, '')) + return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd)) class GMockOutputTest(unittest.TestCase): diff --git a/test/gmock_test_utils.py b/test/gmock_test_utils.py index 2fda138d..ae15a108 100755 --- a/test/gmock_test_utils.py +++ b/test/gmock_test_utils.py @@ -35,7 +35,19 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import os import sys -import unittest + +# Determines path to gtest_test_utils and imports it. +SCRIPT_DIR = os.path.dirname(__file__) or '.' + +# isdir resolves symbolic links. +gtest_tests_util_dir = os.path.join(SCRIPT_DIR, '../gtest/test') +if os.path.isdir(gtest_tests_util_dir): + GTEST_TESTS_UTIL_DIR = gtest_tests_util_dir +else: + GTEST_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, '../../gtest/test') + +sys.path.append(GTEST_TESTS_UTIL_DIR) +import gtest_test_utils # pylint: disable-msg=C6204 # Initially maps a flag to its default value. After @@ -96,6 +108,22 @@ def GetBuildDir(): return os.path.abspath(GetFlag('gmock_build_dir')) +def GetTestExecutablePath(executable_name): + """Returns the absolute path of the test binary given its name. + + The function will print a message and abort the program if the resulting file + doesn't exist. + + Args: + executable_name: name of the test binary that the test script runs. + + Returns: + The absolute path of the test binary. + """ + + return gtest_test_utils.GetTestExecutablePath(executable_name, GetBuildDir()) + + def GetExitStatus(exit_code): """Returns the argument to exit(), or -1 if exit() wasn't called. @@ -116,11 +144,15 @@ def GetExitStatus(exit_code): return -1 +# Exposes Subprocess from gtest_test_utils. +Subprocess = gtest_test_utils.Subprocess # pylint: disable-msg=C6409 + + def Main(): """Runs the unit test.""" # We must call _ParseAndStripGMockFlags() before calling - # unittest.main(). Otherwise the latter will be confused by the - # --gmock_* flags. + # gtest_test_utils.Main(). Otherwise unittest.main it calls will be + # confused by the --gmock_* flags. _ParseAndStripGMockFlags(sys.argv) - unittest.main() + gtest_test_utils.Main() -- cgit v1.2.3 From f6d6a22b8eea931b49a8c33de3092d4623ed0d41 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 1 Dec 2009 19:42:25 +0000 Subject: Fixes Cygwin compatibility (by Vlad Losev); Improves Python tests (by Vlad Losev); Fixes ambiguous call to implicit_cast; Uses gtest's SkipPrefix() instead gmock's own (by Vlad Losev). --- include/gmock/internal/gmock-port.h | 2 +- scons/SConscript | 3 --- src/gmock-matchers.cc | 12 ------------ test/gmock-printers_test.cc | 17 ++++++++++++++--- test/gmock_leak_test.py | 4 +--- test/gmock_output_test.py | 3 +-- test/gmock_test_utils.py | 11 ++++++++++- 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 0cff73fe..649f838f 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -123,7 +123,7 @@ inline To down_cast(From* f) { // so we only accept pointers // completely. if (false) { const To to = NULL; - implicit_cast(to); + ::testing::internal::implicit_cast(to); } #if GTEST_HAS_RTTI diff --git a/scons/SConscript b/scons/SConscript index 80891209..73c5b916 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -194,9 +194,6 @@ GtestTest(env, 'gmock_test', [gtest, gmock_main]) # gmock_all_test is commented to save time building and running tests. # Uncomment if necessary. #GtestTest(env, 'gmock_all_test', [gtest, gmock_main]) -# TODO (vladl): Add a test verifying that gmock can be built from -# testing/base/gunit.cc and testing/base/internal/gmock-all.cc after merging -# into the main branch. This is the API for Windows users. ############################################################ # Tests targets using custom environments. diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc index 79b525d3..0abca708 100644 --- a/src/gmock-matchers.cc +++ b/src/gmock-matchers.cc @@ -83,18 +83,6 @@ int GetParamIndex(const char* param_names[], const string& param_name) { return kInvalidInterpolation; } -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr) { - const size_t prefix_len = strlen(prefix); - if (strncmp(*pstr, prefix, prefix_len) == 0) { - *pstr += prefix_len; - return true; - } - return false; -} - // Helper function used by ValidateMatcherDescription() to format // error messages. string FormatMatcherDescriptionSyntaxError(const char* description, diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index c72e3d3d..e1956202 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -443,8 +443,14 @@ TEST(PrintPointerToPointerTest, IntPointerPointer) { void MyFunction(int n) {} TEST(PrintPointerTest, NonMemberFunctionPointer) { - EXPECT_EQ(PrintPointer(reinterpret_cast(&MyFunction)), - Print(&MyFunction)); + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + EXPECT_EQ( + PrintPointer(reinterpret_cast( + reinterpret_cast(&MyFunction))), + Print(&MyFunction)); int (*p)(bool) = NULL; // NOLINT EXPECT_EQ("NULL", Print(p)); } @@ -973,7 +979,12 @@ TEST(PrintReferenceTest, HandlesFunctionPointer) { void (*fp)(int n) = &MyFunction; const string fp_pointer_string = PrintPointer(reinterpret_cast(&fp)); - const string fp_string = PrintPointer(reinterpret_cast(fp)); + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + const string fp_string = PrintPointer(reinterpret_cast( + reinterpret_cast(fp))); EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, PrintByRef(fp)); } diff --git a/test/gmock_leak_test.py b/test/gmock_leak_test.py index 429cc6ad..38ff9d01 100755 --- a/test/gmock_leak_test.py +++ b/test/gmock_leak_test.py @@ -33,8 +33,6 @@ __author__ = 'wan@google.com (Zhanyong Wan)' -import os -import unittest import gmock_test_utils @@ -45,7 +43,7 @@ TEST_WITH_ON_CALL = [PROGRAM_PATH, '--gtest_filter=*OnCall*'] TEST_MULTIPLE_LEAKS = [PROGRAM_PATH, '--gtest_filter=*MultipleLeaked*'] -class GMockLeakTest(unittest.TestCase): +class GMockLeakTest(gmock_test_utils.TestCase): def testCatchesLeakedMockByDefault(self): self.assertNotEqual( diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py index c5f05b34..614a58fa 100755 --- a/test/gmock_output_test.py +++ b/test/gmock_output_test.py @@ -43,7 +43,6 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sys -import unittest import gmock_test_utils @@ -154,7 +153,7 @@ def GetNormalizedCommandOutputAndLeakyTests(cmd): return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd)) -class GMockOutputTest(unittest.TestCase): +class GMockOutputTest(gmock_test_utils.TestCase): def testOutput(self): (output, leaky_tests) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) golden_file = open(GOLDEN_PATH, 'rb') diff --git a/test/gmock_test_utils.py b/test/gmock_test_utils.py index ae15a108..fa896a47 100755 --- a/test/gmock_test_utils.py +++ b/test/gmock_test_utils.py @@ -36,6 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)' import os import sys + # Determines path to gtest_test_utils and imports it. SCRIPT_DIR = os.path.dirname(__file__) or '.' @@ -144,8 +145,16 @@ def GetExitStatus(exit_code): return -1 +# Suppresses the "Invalid const name" lint complaint +# pylint: disable-msg=C6409 + # Exposes Subprocess from gtest_test_utils. -Subprocess = gtest_test_utils.Subprocess # pylint: disable-msg=C6409 +Subprocess = gtest_test_utils.Subprocess + +# Exposes TestCase from gtest_test_utils. +TestCase = gtest_test_utils.TestCase + +# pylint: enable-msg=C6409 def Main(): -- cgit v1.2.3 From a95c6a5a695276ee33a5959aa101767023945539 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 2 Dec 2009 08:36:42 +0000 Subject: Fixes a C++-standard-compliance bug in gmock-printers.h. --- include/gmock/gmock-printers.h | 113 +++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 54 deletions(-) diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index e07d92af..9f024d0c 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -434,63 +434,10 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { // Overload for ::std::tr1::tuple. Needed for printing function // arguments, which are packed as tuples. -typedef ::std::vector Strings; - -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. - -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - *os << ", "; - UniversalPrinter::type> - ::Print(::std::tr1::get(t), os); - } - - // Tersely prints the first N fields of a tuple to a string vector, - // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base cases. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; -template <> -template -void TuplePrefixPrinter<1>::PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); -} - // Helper function for printing a tuple. T must be instantiated with // a tuple type. template -void PrintTupleTo(const T& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); - *os << ")"; -} +void PrintTupleTo(const T& t, ::std::ostream* os); // Overloaded PrintTo() for tuples of various arities. We support // tuples of up-to 10 fields. The following implementation works @@ -725,6 +672,64 @@ void UniversalPrint(const T& value, ::std::ostream* os) { UniversalPrinter::Print(value, os); } +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. + +// The inductive case. +template +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +template <> +template +void TuplePrefixPrinter<1>::PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); +} + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". -- cgit v1.2.3 From 099e3b93c5881901225549c14c8124f72bf20cdc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 9 Dec 2009 17:58:37 +0000 Subject: Makes gmock_doctor work with gcc 4.4.0. --- scripts/gmock_doctor.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 74af1083..bc814ad9 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -366,11 +366,17 @@ def _TypeInTemplatedBaseDiagnoser1(msg): type. """ - regex = (r'In member function \'int .*\n' + _FILE_LINE_RE + - r'error: a function call cannot appear in a constant-expression') + gcc_4_3_1_regex = ( + r'In member function \'int .*\n' + _FILE_LINE_RE + + r'error: a function call cannot appear in a constant-expression') + gcc_4_4_0_regex = ( + r'error: a function call cannot appear in a constant-expression' + + _FILE_LINE_RE + r'error: template argument 1 is invalid\n') diagnosis = _TTB_DIAGNOSIS % {'type': 'Foo'} - return _GenericDiagnoser('TTB', 'Type in Template Base', - regex, diagnosis, msg) + return (list(_GenericDiagnoser('TTB', 'Type in Template Base', + gcc_4_3_1_regex, diagnosis, msg)) + + list(_GenericDiagnoser('TTB', 'Type in Template Base', + gcc_4_4_0_regex, diagnosis, msg))) def _TypeInTemplatedBaseDiagnoser2(msg): @@ -380,8 +386,7 @@ def _TypeInTemplatedBaseDiagnoser2(msg): parameter type. """ - regex = (r'In member function \'int .*\n' - + _FILE_LINE_RE + + regex = (_FILE_LINE_RE + r'error: \'(?P.+)\' was not declared in this scope\n' r'.*error: template argument 1 is invalid\n') return _GenericDiagnoser('TTB', 'Type in Template Base', @@ -458,9 +463,13 @@ _DIAGNOSERS = [ def Diagnose(msg): """Generates all possible diagnoses given the gcc error message.""" + diagnoses = [] for diagnoser in _DIAGNOSERS: - for diagnosis in diagnoser(msg): - yield '[%s - %s]\n%s' % diagnosis + for diag in diagnoser(msg): + diagnosis = '[%s - %s]\n%s' % diag + if not diagnosis in diagnoses: + diagnoses.append(diagnosis) + return diagnoses def main(): @@ -474,7 +483,7 @@ def main(): print 'Waiting for compiler errors on stdin . . .' msg = sys.stdin.read().strip() - diagnoses = list(Diagnose(msg)) + diagnoses = Diagnose(msg) count = len(diagnoses) if not count: print '\nGcc complained:' -- cgit v1.2.3 From 5a3c1691a1508577a69fd3111db15e43414918e6 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 9 Dec 2009 18:21:28 +0000 Subject: Removes gmock_output_test_.vcproj. --- Makefile.am | 1 - msvc/gmock.sln | 6 -- msvc/gmock_output_test_.vcproj | 199 ----------------------------------------- 3 files changed, 206 deletions(-) delete mode 100644 msvc/gmock_output_test_.vcproj diff --git a/Makefile.am b/Makefile.am index e176bbec..3fe9da43 100644 --- a/Makefile.am +++ b/Makefile.am @@ -233,6 +233,5 @@ EXTRA_DIST += \ msvc/gmock_config.vsprops \ msvc/gmock_link_test.vcproj \ msvc/gmock_main.vcproj \ - msvc/gmock_output_test_.vcproj \ msvc/gmock-spec-builders_test.vcproj \ msvc/gmock_test.vcproj diff --git a/msvc/gmock.sln b/msvc/gmock.sln index cd1502a9..f56dda64 100644 --- a/msvc/gmock.sln +++ b/msvc/gmock.sln @@ -7,8 +7,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_link_test", "gmock_link_test.vcproj", "{ED597847-A714-4327-B569-70029D2311F0}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_output_test_", "gmock_output_test_.vcproj", "{EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock-spec-builders_test", "gmock-spec-builders_test.vcproj", "{46972604-5BE0-4493-BAE3-878DB825FDCB}" @@ -31,10 +29,6 @@ Global {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.Build.0 = Debug|Win32 {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.ActiveCfg = Release|Win32 {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.Build.0 = Release|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.ActiveCfg = Debug|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Debug|Win32.Build.0 = Debug|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.ActiveCfg = Release|Win32 - {EDCE4C87-C2C0-4D22-98AC-7B6466F89A15}.Release|Win32.Build.0 = Release|Win32 {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/msvc/gmock_output_test_.vcproj b/msvc/gmock_output_test_.vcproj deleted file mode 100644 index 8e846ec1..00000000 --- a/msvc/gmock_output_test_.vcproj +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From 39bf784f839a9ffeb5f2d943435783633c5c0a6d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Dec 2009 23:36:08 +0000 Subject: Removes uses of GTEST_HAS_STD_STRING. --- include/gmock/gmock-actions.h | 2 -- include/gmock/gmock-printers.h | 2 -- include/gmock/internal/gmock-port.h | 4 +--- src/gmock-printers.cc | 2 -- test/gmock-actions_test.cc | 4 ---- test/gmock-printers_test.cc | 2 -- 6 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 214b2912..d965e108 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -117,9 +117,7 @@ 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 -#if GTEST_HAS_STD_STRING GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); -#endif // GTEST_HAS_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'); diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 9f024d0c..cda3545a 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -409,12 +409,10 @@ inline void PrintTo(const ::string& s, ::std::ostream* os) { } #endif // GTEST_HAS_GLOBAL_STRING -#if GTEST_HAS_STD_STRING void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } -#endif // GTEST_HAS_STD_STRING // Overloads for ::wstring and ::std::wstring. #if GTEST_HAS_GLOBAL_WSTRING diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 649f838f..27b67a5c 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -198,10 +198,8 @@ struct CompileAssert { #if GTEST_HAS_GLOBAL_STRING typedef ::string string; -#elif GTEST_HAS_STD_STRING -typedef ::std::string string; #else -#error "Google Mock requires ::std::string to compile." +typedef ::std::string string; #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc index 8efba782..fd7d3055 100644 --- a/src/gmock-printers.cc +++ b/src/gmock-printers.cc @@ -296,11 +296,9 @@ void PrintStringTo(const ::string& s, ostream* os) { } #endif // GTEST_HAS_GLOBAL_STRING -#if GTEST_HAS_STD_STRING void PrintStringTo(const ::std::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } -#endif // GTEST_HAS_STD_STRING // Prints a ::wstring object. #if GTEST_HAS_GLOBAL_WSTRING diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 1be4a16c..ea3c3100 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -165,9 +165,7 @@ TEST(BuiltInDefaultValueTest, IsEmptyStringForString) { EXPECT_EQ("", BuiltInDefaultValue< ::string>::Get()); #endif // GTEST_HAS_GLOBAL_STRING -#if GTEST_HAS_STD_STRING EXPECT_EQ("", BuiltInDefaultValue< ::std::string>::Get()); -#endif // GTEST_HAS_STD_STRING } // Tests that BuiltInDefaultValue::Exists() returns true when T is a @@ -177,9 +175,7 @@ TEST(BuiltInDefaultValueTest, ExistsForString) { EXPECT_TRUE(BuiltInDefaultValue< ::string>::Exists()); #endif // GTEST_HAS_GLOBAL_STRING -#if GTEST_HAS_STD_STRING EXPECT_TRUE(BuiltInDefaultValue< ::std::string>::Exists()); -#endif // GTEST_HAS_STD_STRING } // Tests that BuiltInDefaultValue::Get() returns the same diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index e1956202..abfa923c 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -560,7 +560,6 @@ TEST(PrintStringTest, StringInGlobalNamespace) { } #endif // GTEST_HAS_GLOBAL_STRING -#if GTEST_HAS_STD_STRING // ::std::string. TEST(PrintStringTest, StringInStdNamespace) { const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; @@ -568,7 +567,6 @@ TEST(PrintStringTest, StringInStdNamespace) { EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", Print(str)); } -#endif // GTEST_HAS_STD_STRING // Tests printing ::wstring and ::std::wstring. -- cgit v1.2.3 From 284b54d3047254a8787e4f5eb9ba62a866caaabd Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 18 Dec 2009 08:00:42 +0000 Subject: Trims the autotools build script. --- Makefile.am | 179 +++++++++++++++--------------------------------------------- 1 file changed, 44 insertions(+), 135 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3fe9da43..c10d81cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,12 +19,7 @@ AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include # Build rules for libraries. lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la -lib_libgmock_la_SOURCES = src/gmock.cc \ - src/gmock-cardinalities.cc \ - src/gmock-internal-utils.cc \ - src/gmock-matchers.cc \ - src/gmock-printers.cc \ - src/gmock-spec-builders.cc +lib_libgmock_la_SOURCES = src/gmock-all.cc pkginclude_HEADERS = include/gmock/gmock.h \ include/gmock/gmock-actions.h \ @@ -54,51 +49,18 @@ lib_libgmock_main_la_LIBADD = lib/libgmock.la # check_PROGRAMS -- Programs built by "make check" but not necessarily run TESTS= -TESTS_ENVIRONMENT = GMOCK_SOURCE_DIR="$(srcdir)/test" \ - GMOCK_BUILD_DIR="$(top_builddir)/test" check_PROGRAMS= AM_LDFLAGS = $(GTEST_LDFLAGS) -TESTS += test/gmock-actions_test -check_PROGRAMS += test/gmock-actions_test -test_gmock_actions_test_SOURCES = test/gmock-actions_test.cc -test_gmock_actions_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-cardinalities_test -check_PROGRAMS += test/gmock-cardinalities_test -test_gmock_cardinalities_test_SOURCES = test/gmock-cardinalities_test.cc -test_gmock_cardinalities_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-generated-actions_test -check_PROGRAMS += test/gmock-generated-actions_test -test_gmock_generated_actions_test_SOURCES = test/gmock-generated-actions_test.cc -test_gmock_generated_actions_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-generated-function-mockers_test -check_PROGRAMS += test/gmock-generated-function-mockers_test -test_gmock_generated_function_mockers_test_SOURCES = \ - test/gmock-generated-function-mockers_test.cc -test_gmock_generated_function_mockers_test_LDADD = $(GTEST_LIBS) \ - lib/libgmock_main.la - -TESTS += test/gmock-generated-internal-utils_test -check_PROGRAMS += test/gmock-generated-internal-utils_test -test_gmock_generated_internal_utils_test_SOURCES = \ - test/gmock-generated-internal-utils_test.cc -test_gmock_generated_internal_utils_test_LDADD = $(GTEST_LIBS) \ - lib/libgmock_main.la - -TESTS += test/gmock-generated-matchers_test -check_PROGRAMS += test/gmock-generated-matchers_test -test_gmock_generated_matchers_test_SOURCES = \ - test/gmock-generated-matchers_test.cc -test_gmock_generated_matchers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-internal-utils_test -check_PROGRAMS += test/gmock-internal-utils_test -test_gmock_internal_utils_test_SOURCES = test/gmock-internal-utils_test.cc -test_gmock_internal_utils_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la +# 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 works. TESTS += test/gmock_link_test check_PROGRAMS += test/gmock_link_test test_gmock_link_test_SOURCES = test/gmock_link_test.cc \ @@ -106,99 +68,46 @@ test_gmock_link_test_SOURCES = test/gmock_link_test.cc \ test/gmock_link_test.h test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la -TESTS += test/gmock-matchers_test -check_PROGRAMS += test/gmock-matchers_test -test_gmock_matchers_test_SOURCES = test/gmock-matchers_test.cc -test_gmock_matchers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-more-actions_test -check_PROGRAMS += test/gmock-more-actions_test -test_gmock_more_actions_test_SOURCES = test/gmock-more-actions_test.cc -test_gmock_more_actions_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-nice-strict_test -check_PROGRAMS += test/gmock-nice-strict_test -test_gmock_nice_strict_test_SOURCES = test/gmock-nice-strict_test.cc -test_gmock_nice_strict_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-port_test -check_PROGRAMS += test/gmock-port_test -test_gmock_port_test_SOURCES = test/gmock-port_test.cc -test_gmock_port_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -TESTS += test/gmock-printers_test -check_PROGRAMS += test/gmock-printers_test -test_gmock_printers_test_SOURCES = test/gmock-printers_test.cc -test_gmock_printers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -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 - -TESTS += test/gmock_test -check_PROGRAMS += test/gmock_test -test_gmock_test_SOURCES = test/gmock_test.cc -test_gmock_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la - -# A sanity test for verifying that Google Mock works when RTTI is -# disabled. We pick gmock-spec-builders_test.cc as it exercises all -# components of Google Mock. -TESTS += test/gmock_no_rtti_test -check_PROGRAMS += test/gmock_no_rtti_test -test_gmock_no_rtti_test_SOURCES = test/gmock-spec-builders_test.cc \ - src/gmock-all.cc -test_gmock_no_rtti_test_CXXFLAGS = $(AM_CXXFLAGS) -fno-rtti -DGTEST_HAS_RTTI=0 -test_gmock_no_rtti_test_LDADD = $(GTEST_LIBS) - -# A sanity test for verifying that Google Mock works with Google -# Test's TR1 tuple implementation. We pick -# gmock-spec-builders_test.cc as it exercises all components of Google -# Mock. -TESTS += test/gmock_use_own_tuple_test -check_PROGRAMS += test/gmock_use_own_tuple_test -test_gmock_use_own_tuple_test_SOURCES = test/gmock-spec-builders_test.cc \ - src/gmock-all.cc -test_gmock_use_own_tuple_test_CXXFLAGS = \ - $(AM_CXXFLAGS) -DGTEST_USE_OWN_TR1_TUPLE=1 -test_gmock_use_own_tuple_test_LDADD = $(GTEST_LIBS) - -# The following tests depend on the presence of a Python installation and are -# keyed off of it. We only add them to the TESTS variable when a Python -# interpreter is available. TODO(chandlerc@google.com): While we currently only -# attempt to build and execute these tests if Autoconf has found Python v2.3 on -# the system, we don't use the PYTHON variable it specified as the valid -# interpreter. The problem is that TESTS_ENVIRONMENT is a global variable, and -# thus we cannot distinguish between C++ unit tests and Python unit tests. -dist_check_SCRIPTS = - -# Python modules used by multiple Python tests below. -dist_check_SCRIPTS += test/gmock_test_utils.py - -check_PROGRAMS += test/gmock_leak_test_ -test_gmock_leak_test__SOURCES = test/gmock_leak_test_.cc -test_gmock_leak_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la -dist_check_SCRIPTS += test/gmock_leak_test.py - -check_PROGRAMS += test/gmock_output_test_ -test_gmock_output_test__SOURCES = test/gmock_output_test_.cc -test_gmock_output_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la -dist_check_SCRIPTS += test/gmock_output_test.py -EXTRA_DIST += test/gmock_output_test_golden.txt - -# Enable all the python driven tests when we can run them. -if HAVE_PYTHON -TESTS += \ - test/gmock_leak_test.py \ - test/gmock_output_test.py -endif +# Google Mock source files that we don't compile directly. +EXTRA_DIST += \ + src/gmock.cc \ + src/gmock-cardinalities.cc \ + src/gmock-internal-utils.cc \ + src/gmock-matchers.cc \ + src/gmock-printers.cc \ + src/gmock-spec-builders.cc + +# C++ tests that we don't compile using autotools. +EXTRA_DIST += \ + test/gmock_all_test.cc \ + test/gmock-actions_test.cc \ + test/gmock-cardinalities_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-printers_test.cc \ + test/gmock_test.cc + +# Python tests, which we don't run using autotools. +EXTRA_DIST += \ + test/gmock_test_utils.py \ + test/gmock_leak_test_.cc \ + test/gmock_leak_test.py \ + test/gmock_output_test_.cc \ + test/gmock_output_test.py \ + test/gmock_output_test_golden.txt # Nonstandard package files for distribution. EXTRA_DIST += \ CHANGES \ CONTRIBUTORS \ - make/Makefile \ - src/gmock-all.cc + make/Makefile # Pump scripts for generating Google Mock headers. # TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump. -- cgit v1.2.3 From 32de5f53763125925e078498250f7e73a88de9ed Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 23 Dec 2009 00:13:23 +0000 Subject: Fixes a slew of compiler warnings and turns on "warning as error" in the scons build. --- include/gmock/gmock-actions.h | 49 +++++++++ include/gmock/gmock-generated-actions.h | 64 ++++++++++++ include/gmock/gmock-generated-actions.h.pump | 24 +++++ include/gmock/gmock-generated-function-mockers.h | 55 ++++++++++ .../gmock/gmock-generated-function-mockers.h.pump | 5 + include/gmock/gmock-generated-matchers.h | 71 ++++++++++++- include/gmock/gmock-generated-matchers.h.pump | 13 ++- include/gmock/gmock-generated-nice-strict.h | 6 ++ include/gmock/gmock-generated-nice-strict.h.pump | 6 ++ include/gmock/gmock-matchers.h | 111 ++++++++++++++++++++- include/gmock/gmock-more-actions.h | 20 ++++ include/gmock/gmock-spec-builders.h | 33 ++++-- include/gmock/internal/gmock-internal-utils.h | 8 +- scons/SConscript | 16 ++- src/gmock-internal-utils.cc | 2 +- src/gmock-spec-builders.cc | 20 ++-- test/gmock-actions_test.cc | 31 +++--- test/gmock-cardinalities_test.cc | 8 +- test/gmock-generated-actions_test.cc | 44 +++++--- test/gmock-generated-function-mockers_test.cc | 30 ++++++ test/gmock-generated-matchers_test.cc | 23 +++-- test/gmock-internal-utils_test.cc | 14 +-- test/gmock-matchers_test.cc | 31 ++++-- test/gmock-more-actions_test.cc | 20 ++-- test/gmock-nice-strict_test.cc | 11 ++ test/gmock-port_test.cc | 8 +- test/gmock-printers_test.cc | 14 +-- test/gmock-spec-builders_test.cc | 40 +++++++- test/gmock_leak_test_.cc | 5 + test/gmock_link_test.h | 21 +++- test/gmock_output_test_.cc | 5 + 31 files changed, 703 insertions(+), 105 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index d965e108..007ad9d3 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -268,6 +268,7 @@ class ActionInterface { // Returns true iff this is the DoDefault() action. bool IsDoDefault() const { return is_do_default_; } + private: template friend class internal::MonomorphicDoDefaultActionImpl; @@ -279,6 +280,8 @@ class ActionInterface { // True iff this action is DoDefault(). const bool is_do_default_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); }; // An Action is a copyable and IMMUTABLE (except by assignment) @@ -325,6 +328,7 @@ class Action { Result Perform(const ArgumentTuple& args) const { return impl_->Perform(args); } + private: template friend class internal::ActionAdaptor; @@ -362,6 +366,7 @@ class PolymorphicAction { operator Action() const { return Action(new MonomorphicImpl(impl_)); } + private: template class MonomorphicImpl : public ActionInterface { @@ -377,9 +382,13 @@ class PolymorphicAction { private: Impl impl_; + + GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); }; Impl impl_; + + GTEST_DISALLOW_ASSIGN_(PolymorphicAction); }; // Creates an Action from its implementation and returns it. The @@ -416,8 +425,11 @@ class ActionAdaptor : public ActionInterface { virtual Result Perform(const ArgumentTuple& args) { return impl_->Perform(args); } + private: const internal::linked_ptr > impl_; + + GTEST_DISALLOW_ASSIGN_(ActionAdaptor); }; // Implements the polymorphic Return(x) action, which can be used in @@ -470,6 +482,7 @@ class ReturnAction { 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 @@ -494,9 +507,13 @@ class ReturnAction { GMOCK_COMPILE_ASSERT_(!internal::is_reference::value, Result_cannot_be_a_reference_type); Result value_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; R value_; + + GTEST_DISALLOW_ASSIGN_(ReturnAction); }; // Implements the ReturnNull() action. @@ -542,6 +559,7 @@ class ReturnRefAction { 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 @@ -555,11 +573,16 @@ class ReturnRefAction { virtual Result Perform(const ArgumentTuple&) { return ref_; } + private: T& ref_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; T& ref_; + + GTEST_DISALLOW_ASSIGN_(ReturnRefAction); }; // Implements the DoDefault() action for a particular function type F. @@ -611,9 +634,12 @@ class AssignAction { void Perform(const ArgumentTuple& /* args */) const { *ptr_ = value_; } + private: T1* const ptr_; const T2 value_; + + GTEST_DISALLOW_ASSIGN_(AssignAction); }; #if !GTEST_OS_WINDOWS_MOBILE @@ -631,9 +657,12 @@ class SetErrnoAndReturnAction { errno = errno_; return result_; } + private: const int errno_; const T result_; + + GTEST_DISALLOW_ASSIGN_(SetErrnoAndReturnAction); }; #endif // !GTEST_OS_WINDOWS_MOBILE @@ -657,6 +686,8 @@ class SetArgumentPointeeAction { private: const A value_; + + GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; template @@ -675,8 +706,11 @@ class SetArgumentPointeeAction { CompileAssertTypesEqual(); ::std::tr1::get(args)->CopyFrom(*proto_); } + private: const internal::linked_ptr proto_; + + GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; // Implements the InvokeWithoutArgs(f) action. The template argument @@ -696,8 +730,11 @@ class InvokeWithoutArgsAction { // 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. @@ -711,9 +748,12 @@ class InvokeMethodWithoutArgsAction { 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. @@ -739,6 +779,7 @@ class IgnoreResultAction { return Action(new Impl(action_)); } + private: template class Impl : public ActionInterface { @@ -760,9 +801,13 @@ class IgnoreResultAction { OriginalFunction; const Action action_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; const A action_; + + GTEST_DISALLOW_ASSIGN_(IgnoreResultAction); }; // A ReferenceWrapper object represents a reference to type T, @@ -827,10 +872,14 @@ class DoBothAction { private: const Action action1_; const Action action2_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; Action1 action1_; Action2 action2_; + + GTEST_DISALLOW_ASSIGN_(DoBothAction); }; } // namespace internal diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 143a99be..2b53c7b9 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -615,6 +615,8 @@ class WithArgsAction { }; const InnerAction action_; + + GTEST_DISALLOW_ASSIGN_(WithArgsAction); }; // A macro from the ACTION* family (defined later in this file) @@ -1406,12 +1408,16 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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 \ @@ -1462,10 +1468,14 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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();\ @@ -1505,11 +1515,15 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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) {\ @@ -1554,12 +1568,16 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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, \ @@ -1606,6 +1624,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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));\ @@ -1613,6 +1633,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP3);\ };\ template \ inline name##ActionP3 name(p0##_type p0, \ @@ -1664,6 +1686,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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));\ @@ -1672,6 +1696,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP4);\ };\ template \ @@ -1729,6 +1755,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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));\ @@ -1738,6 +1766,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP5);\ };\ template \ @@ -1797,6 +1827,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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));\ @@ -1807,6 +1839,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP6);\ };\ template \ @@ -1869,6 +1903,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, 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, \ @@ -1881,6 +1917,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP7);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ @@ -1962,6 +2002,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP8);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ @@ -2048,6 +2092,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP9);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ @@ -2138,6 +2186,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ + private:\ + GTEST_DISALLOW_ASSIGN_(name##ActionP10);\ };\ template (). // // The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th @@ -2350,6 +2410,10 @@ ACTION_TEMPLATE(ReturnNew, return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 05bf3db3..75b1e7a0 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -228,6 +228,8 @@ class WithArgsAction { }; const InnerAction action_; + + GTEST_DISALLOW_ASSIGN_(WithArgsAction); }; // A macro from the ACTION* family (defined later in this file) @@ -630,12 +632,16 @@ $range k 0..n-1 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 \ @@ -712,10 +718,14 @@ $var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]] 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);\ @@ -735,6 +745,16 @@ $$ // show up in the generated code. // updated. 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 @@ -796,6 +816,10 @@ ACTION_TEMPLATE(ReturnNew, ]] +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 9f3a956c..3b2ede1e 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -794,66 +794,116 @@ class MockFunction; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD0_T(Call, R()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD1_T(Call, R(A0)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD2_T(Call, R(A0, A1)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD3_T(Call, R(A0, A1, A2)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD4_T(Call, R(A0, A1, A2, A3)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: + MockFunction() {} + MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6)); + + 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)); + + 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)); + + 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)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; } // namespace testing diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 82106eb1..619debd2 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -242,7 +242,12 @@ $range j 0..i-1 template class MockFunction { public: + MockFunction() {} + MOCK_METHOD$i[[]]_T(Call, R($for j, [[A$j]])); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index a59e457f..18420c1d 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -89,7 +89,7 @@ template class TupleFields { public: typedef ::std::tr1::tuple<> type; - static type GetSelectedFields(const Tuple& t) { + static type GetSelectedFields(const Tuple& /* t */) { using ::std::tr1::get; return type(); } @@ -271,6 +271,8 @@ class ArgsMatcherImpl : public MatcherInterface { } const MonomorphicInnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); }; template (inner_matcher_)); } + private: const InnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; // Implements ElementsAre() of 1-10 arguments. @@ -317,6 +322,8 @@ class ElementsAreMatcher1 { private: const T1& e1_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher1); }; template @@ -342,6 +349,8 @@ class ElementsAreMatcher2 { private: const T1& e1_; const T2& e2_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher2); }; template @@ -370,6 +379,8 @@ class ElementsAreMatcher3 { const T1& e1_; const T2& e2_; const T3& e3_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher3); }; template @@ -400,6 +411,8 @@ class ElementsAreMatcher4 { const T2& e2_; const T3& e3_; const T4& e4_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher4); }; template @@ -432,6 +445,8 @@ class ElementsAreMatcher5 { const T3& e3_; const T4& e4_; const T5& e5_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher5); }; template \ operator ::testing::Matcher() const {\ @@ -1023,7 +1050,9 @@ ElementsAreArray(const T (&array)[N]) { gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ gmock_param_names, ("" description ""));\ }\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##Matcher);\ };\ inline name##Matcher name() {\ return name##Matcher();\ @@ -1052,6 +1081,8 @@ ElementsAreArray(const T (&array)[N]) { }\ p0##_type p0;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1064,7 +1095,9 @@ ElementsAreArray(const T (&array)[N]) { gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP);\ };\ template \ inline name##MatcherP name(p0##_type p0) {\ @@ -1096,6 +1129,8 @@ ElementsAreArray(const T (&array)[N]) { p0##_type p0;\ p1##_type p1;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1110,7 +1145,9 @@ ElementsAreArray(const T (&array)[N]) { }\ p0##_type p0;\ p1##_type p1;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\ };\ template \ inline name##MatcherP2 name(p0##_type p0, \ @@ -1146,6 +1183,8 @@ ElementsAreArray(const T (&array)[N]) { p1##_type p1;\ p2##_type p2;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1161,7 +1200,9 @@ ElementsAreArray(const T (&array)[N]) { p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\ };\ template \ inline name##MatcherP3 name(p0##_type p0, \ @@ -1200,6 +1241,8 @@ ElementsAreArray(const T (&array)[N]) { p2##_type p2;\ p3##_type p3;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1217,7 +1260,9 @@ ElementsAreArray(const T (&array)[N]) { p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\ };\ template \ @@ -1261,6 +1306,8 @@ ElementsAreArray(const T (&array)[N]) { p3##_type p3;\ p4##_type p4;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1280,7 +1327,9 @@ ElementsAreArray(const T (&array)[N]) { p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\ };\ template \ @@ -1325,6 +1374,8 @@ ElementsAreArray(const T (&array)[N]) { p4##_type p4;\ p5##_type p5;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1345,7 +1396,9 @@ ElementsAreArray(const T (&array)[N]) { p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\ };\ template \ @@ -1396,6 +1449,8 @@ ElementsAreArray(const T (&array)[N]) { p5##_type p5;\ p6##_type p6;\ const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1419,7 +1474,9 @@ ElementsAreArray(const T (&array)[N]) { p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1500,7 +1559,9 @@ ElementsAreArray(const T (&array)[N]) { p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1584,7 +1647,9 @@ ElementsAreArray(const T (&array)[N]) { p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\ };\ template \ operator ::testing::Matcher() const {\ @@ -1673,7 +1740,9 @@ ElementsAreArray(const T (&array)[N]) { p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\ };\ template class TupleFields { public: typedef ::std::tr1::tuple<$for j, [[GMOCK_FIELD_TYPE_(Tuple, k$j)]]> type; - static type GetSelectedFields(const Tuple& t) { + static type GetSelectedFields(const Tuple& $if i==0 [[/* t */]] $else [[t]]) { using ::std::tr1::get; return type($for j, [[get(t)]]); } @@ -157,6 +157,8 @@ class ArgsMatcherImpl : public MatcherInterface { } const MonomorphicInnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); }; template @@ -170,7 +172,10 @@ class ArgsMatcher { return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); } + private: const InnerMatcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; // Implements ElementsAre() of 1-$n arguments. @@ -224,6 +229,8 @@ $for j [[ const T$j& e$j[[]]_; ]] + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher$i); }; @@ -512,6 +519,8 @@ $var param_field_decls2 = [[$for j #name, description, gmock_interp_, gmock_printed_params);\ }\$param_field_decls const ::testing::internal::Interpolations gmock_interp_;\ + private:\ + GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ @@ -523,7 +532,9 @@ $var param_field_decls2 = [[$for j gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ gmock_param_names, ("" description ""));\ }\$param_field_decls2 + private:\ ::testing::internal::Interpolations gmock_interp_;\ + GTEST_DISALLOW_ASSIGN_($class_name);\ };\$template inline $class_name$param_types name($param_types_and_names) {\ return $class_name$param_types($params);\ diff --git a/include/gmock/gmock-generated-nice-strict.h b/include/gmock/gmock-generated-nice-strict.h index fc9a81b5..435467fa 100644 --- a/include/gmock/gmock-generated-nice-strict.h +++ b/include/gmock/gmock-generated-nice-strict.h @@ -155,6 +155,9 @@ class NiceMock : public MockClass { ::testing::Mock::UnregisterCallReaction( internal::implicit_cast(this)); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); }; template @@ -246,6 +249,9 @@ class StrictMock : public MockClass { ::testing::Mock::UnregisterCallReaction( internal::implicit_cast(this)); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock); }; // The following specializations catch some (relatively more common) diff --git a/include/gmock/gmock-generated-nice-strict.h.pump b/include/gmock/gmock-generated-nice-strict.h.pump index b265c2e4..96371f57 100644 --- a/include/gmock/gmock-generated-nice-strict.h.pump +++ b/include/gmock/gmock-generated-nice-strict.h.pump @@ -100,6 +100,9 @@ $range j 1..i ::testing::Mock::UnregisterCallReaction( internal::implicit_cast(this)); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); }; template @@ -132,6 +135,9 @@ $range j 1..i ::testing::Mock::UnregisterCallReaction( internal::implicit_cast(this)); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock); }; // The following specializations catch some (relatively more common) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index deb09463..5f5a29fd 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -121,6 +121,7 @@ class MatcherBase { void ExplainMatchResultTo(T x, ::std::ostream* os) const { impl_->ExplainMatchResultTo(x, os); } + protected: MatcherBase() {} @@ -129,6 +130,7 @@ class MatcherBase { : 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 @@ -234,7 +236,7 @@ class Matcher template class PolymorphicMatcher { public: - explicit PolymorphicMatcher(const Impl& impl) : impl_(impl) {} + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} // Returns a mutable reference to the underlying matcher // implementation object. @@ -248,6 +250,7 @@ class PolymorphicMatcher { operator Matcher() const { return Matcher(new MonomorphicImpl(impl_)); } + private: template class MonomorphicImpl : public MatcherInterface { @@ -284,9 +287,13 @@ class PolymorphicMatcher { 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 @@ -522,6 +529,7 @@ class MatcherCastImpl > { static Matcher Cast(const Matcher& source_matcher) { return Matcher(new Impl(source_matcher)); } + private: class Impl : public MatcherInterface { public: @@ -544,8 +552,11 @@ class MatcherCastImpl > { virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { source_matcher_.ExplainMatchResultTo(static_cast(x), os); } + private: const Matcher source_matcher_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; }; @@ -618,8 +629,10 @@ class AnythingMatcher { } \ private: \ Rhs rhs_; \ + GTEST_DISALLOW_ASSIGN_(Impl); \ }; \ Rhs rhs_; \ + GTEST_DISALLOW_ASSIGN_(name##Matcher); \ } // Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v) @@ -697,6 +710,7 @@ class RefMatcher { // reference to a non-const reference. return MakeMatcher(new Impl(object_)); } + private: template class Impl : public MatcherInterface { @@ -721,11 +735,16 @@ class RefMatcher { ::std::ostream* os) const { *os << "is located @" << static_cast(&x); } + private: const Super& object_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; T& object_; + + GTEST_DISALLOW_ASSIGN_(RefMatcher); }; // Polymorphic helper functions for narrow and wide string matchers. @@ -795,6 +814,7 @@ class StrEqualityMatcher { void DescribeNegationTo(::std::ostream* os) const { DescribeToHelper(!expect_eq_, os); } + private: void DescribeToHelper(bool expect_eq, ::std::ostream* os) const { *os << "is "; @@ -811,6 +831,8 @@ class StrEqualityMatcher { const StringType string_; const bool expect_eq_; const bool case_sensitive_; + + GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher); }; // Implements the polymorphic HasSubstr(substring) matcher, which @@ -845,8 +867,11 @@ class HasSubstrMatcher { *os << "has no substring "; UniversalPrinter::Print(substring_, os); } + private: const StringType substring_; + + GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher); }; // Implements the polymorphic StartsWith(substring) matcher, which @@ -881,8 +906,11 @@ class StartsWithMatcher { *os << "doesn't start with "; UniversalPrinter::Print(prefix_, os); } + private: const StringType prefix_; + + GTEST_DISALLOW_ASSIGN_(StartsWithMatcher); }; // Implements the polymorphic EndsWith(substring) matcher, which @@ -916,8 +944,11 @@ class EndsWithMatcher { *os << "doesn't end with "; UniversalPrinter::Print(suffix_, os); } + private: const StringType suffix_; + + GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); }; #if GMOCK_HAS_REGEX @@ -954,9 +985,12 @@ class MatchesRegexMatcher { << " regular expression "; UniversalPrinter::Print(regex_->pattern(), os); } + private: const internal::linked_ptr regex_; const bool full_match_; + + GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); }; #endif // GMOCK_HAS_REGEX @@ -1030,8 +1064,11 @@ class NotMatcherImpl : public MatcherInterface { virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { matcher_.ExplainMatchResultTo(x, os); } + private: const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(NotMatcherImpl); }; // Implements the Not(m) matcher, which matches a value that doesn't @@ -1047,8 +1084,11 @@ class NotMatcher { 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 @@ -1108,9 +1148,12 @@ class BothOfMatcherImpl : public MatcherInterface { } } } + private: const Matcher matcher1_; const Matcher matcher2_; + + GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl); }; // Used for implementing the AllOf(m_1, ..., m_n) matcher, which @@ -1129,9 +1172,12 @@ class BothOfMatcher { return Matcher(new BothOfMatcherImpl(SafeMatcherCast(matcher1_), SafeMatcherCast(matcher2_))); } + private: Matcher1 matcher1_; Matcher2 matcher2_; + + GTEST_DISALLOW_ASSIGN_(BothOfMatcher); }; // Implements the AnyOf(m1, m2) matcher for a particular argument type @@ -1190,9 +1236,12 @@ class EitherOfMatcherImpl : public MatcherInterface { } } } + private: const Matcher matcher1_; const Matcher matcher2_; + + GTEST_DISALLOW_ASSIGN_(EitherOfMatcherImpl); }; // Used for implementing the AnyOf(m_1, ..., m_n) matcher, which @@ -1212,9 +1261,12 @@ class EitherOfMatcher { return Matcher(new EitherOfMatcherImpl( SafeMatcherCast(matcher1_), SafeMatcherCast(matcher2_))); } + private: Matcher1 matcher1_; Matcher2 matcher2_; + + GTEST_DISALLOW_ASSIGN_(EitherOfMatcher); }; // Used for implementing Truly(pred), which turns a predicate into a @@ -1248,8 +1300,11 @@ class TrulyMatcher { void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't satisfy the given predicate"; } + private: Predicate predicate_; + + GTEST_DISALLOW_ASSIGN_(TrulyMatcher); }; // Used for implementing Matches(matcher), which turns a matcher into @@ -1283,8 +1338,11 @@ class MatcherAsPredicate { // in all of the above situations. return MatcherCast(matcher_).Matches(x); } + private: M matcher_; + + GTEST_DISALLOW_ASSIGN_(MatcherAsPredicate); }; // For implementing ASSERT_THAT() and EXPECT_THAT(). The template @@ -1322,8 +1380,11 @@ class PredicateFormatterFromMatcher { return AssertionFailure(Message() << ss.str()); } } + private: const M matcher_; + + GTEST_DISALLOW_ASSIGN_(PredicateFormatterFromMatcher); }; // A helper function for converting a matcher to a predicate-formatter @@ -1405,6 +1466,8 @@ class FloatingEqMatcher { private: const FloatType rhs_; const bool nan_eq_nan_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; // The following 3 type conversion operators allow FloatEq(rhs) and @@ -1427,6 +1490,8 @@ class FloatingEqMatcher { private: const FloatType rhs_; const bool nan_eq_nan_; + + GTEST_DISALLOW_ASSIGN_(FloatingEqMatcher); }; // Implements the Pointee(m) matcher for matching a pointer whose @@ -1448,6 +1513,7 @@ class PointeeMatcher { operator Matcher() const { return MakeMatcher(new Impl(matcher_)); } + private: // The monomorphic implementation that works for a particular pointer type. template @@ -1485,11 +1551,16 @@ class PointeeMatcher { *os << "points to a value that " << s; } } + private: const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; const InnerMatcher matcher_; + + GTEST_DISALLOW_ASSIGN_(PointeeMatcher); }; // Implements the Field() matcher for matching a field (i.e. member @@ -1543,9 +1614,12 @@ class FieldMatcher { ExplainMatchResultTo(false_type(), *p, os); } } + private: const FieldType Class::*field_; const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(FieldMatcher); }; // Explains the result of matching an object or pointer against a field matcher. @@ -1613,9 +1687,12 @@ class PropertyMatcher { ExplainMatchResultTo(false_type(), *p, os); } } + private: PropertyType (Class::*property_)() const; const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(PropertyMatcher); }; // Explains the result of matching an object or pointer against a @@ -1636,7 +1713,7 @@ struct CallableTraits { typedef typename Functor::result_type ResultType; typedef Functor StorageType; - static void CheckIsValid(Functor functor) {} + static void CheckIsValid(Functor /* functor */) {} template static ResultType Invoke(Functor f, T arg) { return f(arg); } }; @@ -1709,6 +1786,7 @@ class ResultOfMatcher { if (s != "") *os << "result of the given callable " << s; } + private: // Functors often define operator() as non-const method even though // they are actualy stateless. But we need to use them even when @@ -1717,10 +1795,14 @@ class ResultOfMatcher { // how many times the callable will be invoked. mutable CallableStorageType callable_; const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(Impl); }; // class Impl const CallableStorageType callable_; const Matcher matcher_; + + GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); }; // Explains the result of matching a value against a functor matcher. @@ -1818,8 +1900,11 @@ class ContainerEqMatcher { } } } + private: const StlContainer rhs_; + + GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; template @@ -1884,6 +1969,8 @@ class ContainsMatcherImpl : public MatcherInterface { private: const Matcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ContainsMatcherImpl); }; // Implements polymorphic Contains(element_matcher). @@ -1899,6 +1986,8 @@ class ContainsMatcher { private: const M inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(ContainsMatcher); }; // Implements Key(inner_matcher) for the given argument pair type. @@ -1942,6 +2031,8 @@ class KeyMatcherImpl : public MatcherInterface { private: const Matcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(KeyMatcherImpl); }; // Implements polymorphic Key(matcher_for_key). @@ -1957,6 +2048,8 @@ class KeyMatcher { private: const M matcher_for_key_; + + GTEST_DISALLOW_ASSIGN_(KeyMatcher); }; // Implements Pair(first_matcher, second_matcher) for the given argument pair @@ -2026,6 +2119,8 @@ class PairMatcherImpl : public MatcherInterface { private: const Matcher first_matcher_; const Matcher second_matcher_; + + GTEST_DISALLOW_ASSIGN_(PairMatcherImpl); }; // Implements polymorphic Pair(first_matcher, second_matcher). @@ -2045,6 +2140,8 @@ class PairMatcher { private: const FirstMatcher first_matcher_; const SecondMatcher second_matcher_; + + GTEST_DISALLOW_ASSIGN_(PairMatcher); }; // Implements ElementsAre() and ElementsAreArray(). @@ -2060,10 +2157,10 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Constructs the matcher from a sequence of element values or // element matchers. template - ElementsAreMatcherImpl(InputIter first, size_t count) { - matchers_.reserve(count); + ElementsAreMatcherImpl(InputIter first, size_t a_count) { + matchers_.reserve(a_count); InputIter it = first; - for (size_t i = 0; i != count; ++i, ++it) { + for (size_t i = 0; i != a_count; ++i, ++it) { matchers_.push_back(MatcherCast(*it)); } } @@ -2185,6 +2282,8 @@ class ElementsAreMatcherImpl : public MatcherInterface { size_t count() const { return matchers_.size(); } std::vector > matchers_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcherImpl); }; // Implements ElementsAre() of 0 arguments. @@ -2224,6 +2323,8 @@ class ElementsAreArrayMatcher { private: const T* const first_; const size_t count_; + + GTEST_DISALLOW_ASSIGN_(ElementsAreArrayMatcher); }; // Constants denoting interpolations in a matcher description string. diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index c6fa6bbd..6226392d 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -58,8 +58,11 @@ class InvokeAction { Result Perform(const ArgumentTuple& args) { return InvokeHelper::Invoke(function_impl_, args); } + private: FunctionImpl function_impl_; + + GTEST_DISALLOW_ASSIGN_(InvokeAction); }; // Implements the Invoke(object_ptr, &Class::Method) action. @@ -74,9 +77,12 @@ class InvokeMethodAction { return InvokeHelper::InvokeMethod( obj_ptr_, method_ptr_, args); } + private: Class* const obj_ptr_; const MethodPtr method_ptr_; + + GTEST_DISALLOW_ASSIGN_(InvokeMethodAction); }; } // namespace internal @@ -122,6 +128,16 @@ WithArg(const InnerAction& action) { return internal::WithArgsAction(action); } +// 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 + // Action ReturnArg() returns the k-th argument of the mock function. ACTION_TEMPLATE(ReturnArg, HAS_1_TEMPLATE_PARAMS(int, k), @@ -185,6 +201,10 @@ ACTION_TEMPLATE(DeleteArg, ACTION_P(Throw, exception) { throw exception; } #endif // GTEST_HAS_EXCEPTIONS +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 9cb549ab..9aa0a9ee 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -142,10 +142,10 @@ class DefaultActionSpec { // Constructs a DefaultActionSpec object from the information inside // the parenthesis of an ON_CALL() statement. - DefaultActionSpec(const char* file, int line, + DefaultActionSpec(const char* a_file, int a_line, const ArgumentMatcherTuple& matchers) - : file_(file), - line_(line), + : file_(a_file), + line_(a_line), matchers_(matchers), // By default, extra_matcher_ should match anything. However, // we cannot initialize it with _ as that triggers a compiler @@ -196,6 +196,7 @@ class DefaultActionSpec { "once in an ON_CALL()."); return action_; } + private: // Gives each clause in the ON_CALL() statement a name. enum Clause { @@ -582,6 +583,7 @@ class ExpectationBase { // expectation has occurred. // L >= g_gmock_mutex virtual void DescribeCallCountTo(::std::ostream* os) const = 0; + protected: friend class ::testing::Expectation; @@ -620,8 +622,8 @@ class ExpectationBase { bool cardinality_specified() const { return cardinality_specified_; } // Sets the cardinality of this expectation spec. - void set_cardinality(const Cardinality& cardinality) { - cardinality_ = cardinality; + void set_cardinality(const Cardinality& a_cardinality) { + cardinality_ = a_cardinality; } // The following group of methods should only be called after the @@ -716,6 +718,8 @@ class ExpectationBase { // and can change as the mock function is called. int call_count_; // How many times this expectation has been invoked. bool retired_; // True iff this expectation has retired. + + GTEST_DISALLOW_ASSIGN_(ExpectationBase); }; // class ExpectationBase // Impements an expectation for the given function type. @@ -727,9 +731,9 @@ class TypedExpectation : public ExpectationBase { typedef typename Function::Result Result; TypedExpectation(FunctionMockerBase* owner, - const char* file, int line, const string& source_text, + const char* a_file, int a_line, const string& a_source_text, const ArgumentMatcherTuple& m) - : ExpectationBase(file, line, source_text), + : ExpectationBase(a_file, a_line, a_source_text), owner_(owner), matchers_(m), extra_matcher_specified_(false), @@ -769,7 +773,7 @@ class TypedExpectation : public ExpectationBase { } // Implements the .Times() clause. - TypedExpectation& Times(const Cardinality& cardinality) { + TypedExpectation& Times(const Cardinality& a_cardinality) { if (last_clause_ ==kTimes) { ExpectSpecProperty(false, ".Times() cannot appear " @@ -782,7 +786,7 @@ class TypedExpectation : public ExpectationBase { } last_clause_ = kTimes; - ExpectationBase::SpecifyCardinality(cardinality); + ExpectationBase::SpecifyCardinality(a_cardinality); return *this; } @@ -1164,6 +1168,8 @@ class TypedExpectation : public ExpectationBase { Clause last_clause_; mutable bool action_count_checked_; // Under mutex_. mutable Mutex mutex_; // Protects action_count_checked_. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TypedExpectation); }; // class TypedExpectation // A MockSpec object is used by ON_CALL() or EXPECT_CALL() for @@ -1228,6 +1234,8 @@ class MockSpec { internal::FunctionMockerBase* const function_mocker_; // The argument matchers specified in the spec. ArgumentMatcherTuple matchers_; + + GTEST_DISALLOW_ASSIGN_(MockSpec); }; // class MockSpec // MSVC warns about using 'this' in base member initializer list, so @@ -1251,7 +1259,7 @@ class MockSpec { template class ActionResultHolder { public: - explicit ActionResultHolder(T value) : value_(value) {} + explicit ActionResultHolder(T a_value) : value_(a_value) {} // The compiler-generated copy constructor and assignment operator // are exactly what we need, so we don't need to define them. @@ -1285,6 +1293,9 @@ class ActionResultHolder { private: T value_; + + // T could be a reference type, so = isn't supported. + GTEST_DISALLOW_ASSIGN_(ActionResultHolder); }; // Specialization for T = void. @@ -1433,6 +1444,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { } return name; } + protected: template friend class MockSpec; @@ -1477,6 +1489,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // The current spec (either default action spec or expectation spec) // being described on this function mocker. MockSpec& current_spec() { return current_spec_; } + private: template friend class TypedExpectation; diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 7b173350..0c33fdd0 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -640,15 +640,15 @@ class NativeArray { // Initializes this object; makes a copy of the input array if // 'relation' is kCopy. - void Init(const Element* array, size_t size, RelationToSource relation) { + void Init(const Element* array, size_t a_size, RelationToSource relation) { if (relation == kReference) { array_ = array; } else { - Element* const copy = new Element[size]; - CopyArray(array, size, copy); + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); array_ = copy; } - size_ = size; + size_ = a_size; relation_to_source_ = relation; } diff --git a/scons/SConscript b/scons/SConscript index 73c5b916..7c2bfbf6 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -105,9 +105,19 @@ GtestTest = gtest_exports['GtestTest'] gtest_common_exports = SConscript(GTEST_DIR + '/scons/SConscript.common') EnvCreator = gtest_common_exports['EnvCreator'] -# TODO(vladl@google.com): restore warnings as errors once all warnings are fixed -# in gMock. -env = EnvCreator.Create(env, EnvCreator.WarningOk) +env = env.Clone() +if env['PLATFORM'] == 'win32': + env.Append(CCFLAGS=[ + '-wd4127', # Disables warning "conditional expression is constant", + # triggered by VC 8.0's own STL header . + '-wd4702', # Disables warning "unreachable code", triggered by VC + # 7.1's own STL header . + '-wd4675', # Disables warning "resolved overload was found by + # argument-dependent lookup" generated by VC 7.1. + # It just says that VC 7.1 fixed a bug in earlier + # versions of VC so the code behavior will be + # different than compiled with VC 6.0, for example. + ]) # Note: The relative paths in SConscript files are relative to the location # of the SConscript file itself. To make a path relative to the location of diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 196ec74b..4c51ec00 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -64,7 +64,7 @@ string ConvertIdentifierNameToWords(const char* id_name) { if (isalnum(*p)) { if (starts_new_word && result != "") result += ' '; - result += tolower(*p); + result += static_cast(tolower(*p)); } } return result; diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index edd60fec..02a3227f 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -56,12 +56,12 @@ namespace internal { Mutex g_gmock_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); // Constructs an ExpectationBase object. -ExpectationBase::ExpectationBase(const char* file, - int line, - const string& source_text) - : file_(file), - line_(line), - source_text_(source_text), +ExpectationBase::ExpectationBase(const char* a_file, + int a_line, + const string& a_source_text) + : file_(a_file), + line_(a_line), + source_text_(a_source_text), cardinality_specified_(false), cardinality_(Exactly(1)), call_count_(0), @@ -73,9 +73,9 @@ ExpectationBase::~ExpectationBase() {} // Explicitly specifies the cardinality of this expectation. Used by // the subclasses to implement the .Times() clause. -void ExpectationBase::SpecifyCardinality(const Cardinality& cardinality) { +void ExpectationBase::SpecifyCardinality(const Cardinality& a_cardinality) { cardinality_specified_ = true; - cardinality_ = cardinality; + cardinality_ = a_cardinality; } // Retires all pre-requisites of this expectation. @@ -427,8 +427,8 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj) { Expectation::Expectation() {} Expectation::Expectation( - const internal::linked_ptr& expectation_base) - : expectation_base_(expectation_base) {} + const internal::linked_ptr& an_expectation_base) + : expectation_base_(an_expectation_base) {} Expectation::~Expectation() {} diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index ea3c3100..a2c6fe11 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -95,26 +95,26 @@ TEST(BuiltInDefaultValueTest, ExistsForPointerTypes) { // Tests that BuiltInDefaultValue::Get() returns 0 when T is a // built-in numeric type. TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { - EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0U, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); #if GMOCK_HAS_SIGNED_WCHAR_T_ - EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0U, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); #endif #if GMOCK_WCHAR_T_IS_NATIVE_ EXPECT_EQ(0, BuiltInDefaultValue::Get()); #endif - EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0U, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT - EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0U, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); - EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT + EXPECT_EQ(0U, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT - EXPECT_EQ(0, BuiltInDefaultValue::Get()); + EXPECT_EQ(0U, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); @@ -517,11 +517,13 @@ TEST(ReturnTest, IsCovariant) { // gmock-actions.h for more information. class FromType { public: - FromType(bool* converted) : converted_(converted) {} + FromType(bool* is_converted) : converted_(is_converted) {} bool* converted() const { return converted_; } private: bool* const converted_; + + GTEST_DISALLOW_ASSIGN_(FromType); }; class ToType { @@ -588,8 +590,13 @@ class MyClass {}; class MockClass { public: + MockClass() {} + MOCK_METHOD1(IntFunc, int(bool flag)); // NOLINT MOCK_METHOD0(Foo, MyClass()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockClass); }; // Tests that DoDefault() returns the built-in default value for the @@ -615,7 +622,7 @@ TEST(DoDefaultDeathTest, DiesForUnknowType) { // Tests that using DoDefault() inside a composite action leads to a // run-time error. -void VoidFunc(bool flag) {} +void VoidFunc(bool /* flag */) {} TEST(DoDefaultDeathTest, DiesIfUsedInCompositeAction) { MockClass mock; @@ -801,7 +808,7 @@ bool Unary(int x) { return x < 0; } const char* Plus1(const char* s) { return s + 1; } -void VoidUnary(int n) { g_done = true; } +void VoidUnary(int /* n */) { g_done = true; } bool ByConstRef(const std::string& s) { return s == "Hi"; } @@ -870,7 +877,7 @@ TEST(InvokeWithoutArgsTest, Function) { EXPECT_EQ(1, a.Perform(make_tuple(2))); // As an action that takes two arguments. - Action a2 = InvokeWithoutArgs(Nullary); // NOLINT + Action a2 = InvokeWithoutArgs(Nullary); // NOLINT EXPECT_EQ(1, a2.Perform(make_tuple(2, 3.5))); // As an action that returns void. @@ -887,7 +894,7 @@ TEST(InvokeWithoutArgsTest, Functor) { EXPECT_EQ(2, a.Perform(make_tuple())); // As an action that takes three arguments. - Action a2 = // NOLINT + Action a2 = // NOLINT InvokeWithoutArgs(NullaryFunctor()); EXPECT_EQ(2, a2.Perform(make_tuple(3, 3.5, 'a'))); @@ -928,7 +935,7 @@ TEST(IgnoreResultTest, MonomorphicAction) { // Tests using IgnoreResult() on an action that returns a class type. -MyClass ReturnMyClass(double x) { +MyClass ReturnMyClass(double /* x */) { g_done = true; return MyClass(); } diff --git a/test/gmock-cardinalities_test.cc b/test/gmock-cardinalities_test.cc index f3f1e106..f6a94916 100644 --- a/test/gmock-cardinalities_test.cc +++ b/test/gmock-cardinalities_test.cc @@ -52,7 +52,11 @@ using testing::MakeCardinality; class MockFoo { public: + MockFoo() {} MOCK_METHOD0(Bar, int()); // NOLINT + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); }; // Tests that Cardinality objects can be default constructed. @@ -398,7 +402,9 @@ class EvenCardinality : public CardinalityInterface { } // Returns true iff call_count calls will saturate this cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const { return false; } + virtual bool IsSaturatedByCallCount(int /* call_count */) const { + return false; + } // Describes self to an ostream. virtual void DescribeTo(::std::ostream* ss) const { diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 2e6fa0b6..3c076d7c 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -63,6 +63,10 @@ using testing::StaticAssertTypeEq; using testing::Unused; using testing::WithArgs; +// For suppressing compiler warnings on conversion possibly losing precision. +inline short Short(short n) { return n; } // NOLINT +inline char Char(char ch) { return ch; } + // Sample functions and functors for testing various actions. int Nullary() { return 1; } @@ -242,7 +246,7 @@ TEST(InvokeArgumentTest, Function10) { // Tests using InvokeArgument with a function that takes a pointer argument. TEST(InvokeArgumentTest, ByPointerFunction) { Action a = // NOLINT - InvokeArgument<0>(static_cast("Hi"), 1); + InvokeArgument<0>(static_cast("Hi"), Short(1)); EXPECT_STREQ("i", a.Perform(make_tuple(&Binary))); } @@ -250,7 +254,7 @@ TEST(InvokeArgumentTest, ByPointerFunction) { // by passing it a C-string literal. TEST(InvokeArgumentTest, FunctionWithCStringLiteral) { Action a = // NOLINT - InvokeArgument<0>("Hi", 1); + InvokeArgument<0>("Hi", Short(1)); EXPECT_STREQ("i", a.Perform(make_tuple(&Binary))); } @@ -286,17 +290,17 @@ TEST(WithArgsTest, OneArg) { // Tests using WithArgs with an action that takes 2 arguments. TEST(WithArgsTest, TwoArgs) { - Action a = + Action a = WithArgs<0, 2>(Invoke(Binary)); const char s[] = "Hello"; - EXPECT_EQ(s + 2, a.Perform(make_tuple(CharPtr(s), 0.5, 2))); + EXPECT_EQ(s + 2, a.Perform(make_tuple(CharPtr(s), 0.5, Short(2)))); } // Tests using WithArgs with an action that takes 3 arguments. TEST(WithArgsTest, ThreeArgs) { Action a = // NOLINT WithArgs<0, 2, 3>(Invoke(Ternary)); - EXPECT_EQ(123, a.Perform(make_tuple(100, 6.5, 20, 3))); + EXPECT_EQ(123, a.Perform(make_tuple(100, 6.5, Char(20), Short(3)))); } // Tests using WithArgs with an action that takes 4 arguments. @@ -379,7 +383,7 @@ TEST(WithArgsTest, NonInvokeAction) { TEST(WithArgsTest, Identity) { Action a = // NOLINT WithArgs<0, 1, 2>(Invoke(Ternary)); - EXPECT_EQ(123, a.Perform(make_tuple(100, 20, 3))); + EXPECT_EQ(123, a.Perform(make_tuple(100, Char(20), Short(3)))); } // Tests using WithArgs with repeated arguments. @@ -394,14 +398,14 @@ TEST(WithArgsTest, ReversedArgumentOrder) { Action a = // NOLINT WithArgs<1, 0>(Invoke(Binary)); const char s[] = "Hello"; - EXPECT_EQ(s + 2, a.Perform(make_tuple(2, CharPtr(s)))); + EXPECT_EQ(s + 2, a.Perform(make_tuple(Short(2), CharPtr(s)))); } // Tests using WithArgs with compatible, but not identical, argument types. TEST(WithArgsTest, ArgsOfCompatibleTypes) { - Action a = // NOLINT + Action a = // NOLINT WithArgs<0, 1, 3>(Invoke(Ternary)); - EXPECT_EQ(123, a.Perform(make_tuple(100, 20, 5.6, 3))); + EXPECT_EQ(123, a.Perform(make_tuple(Short(100), Char(20), 5.6, Char(3)))); } // Tests using WithArgs with an action that returns void. @@ -583,6 +587,16 @@ TEST(DoAllTest, TenActions) { EXPECT_EQ('g', g); } +// 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 + // Tests the ACTION*() macro family. // Tests that ACTION() can define an action that doesn't reference the @@ -633,7 +647,7 @@ ACTION(Sum2) { TEST(ActionMacroTest, CanReferenceArgumentTuple) { Action a1 = Sum2(); int dummy = 0; - EXPECT_EQ(11, a1.Perform(make_tuple(5, static_cast(6), &dummy))); + EXPECT_EQ(11, a1.Perform(make_tuple(5, Char(6), &dummy))); } // Tests that the body of ACTION() can reference the mock function @@ -731,7 +745,7 @@ ACTION_P(TypedPlus, n) { TEST(ActionPMacroTest, CanReferenceArgumentAndParameterTypes) { Action a1 = TypedPlus(9); - EXPECT_EQ(10, a1.Perform(make_tuple(static_cast(1), true))); + EXPECT_EQ(10, a1.Perform(make_tuple(Char(1), true))); } // Tests that a parameterized action can be used in any mock function @@ -851,7 +865,7 @@ TEST(ActionPnMacroTest, WorksFor10Parameters) { ACTION_P2(PadArgument, prefix, suffix) { // The following lines promote the two parameters to desired types. std::string prefix_str(prefix); - char suffix_char(suffix); + char suffix_char = static_cast(suffix); return prefix_str + arg0 + suffix_char; } @@ -1078,7 +1092,7 @@ class BoolResetter { explicit BoolResetter(bool* value) : value_(value) {} ~BoolResetter() { *value_ = false; } private: - bool* const value_; + bool* value_; }; TEST(ActionTemplateTest, WorksForIntegralTemplateParams) { @@ -1190,5 +1204,9 @@ TEST(ActionTemplateTest, CanBeOverloadedOnNumberOfValueParameters) { EXPECT_EQ(12345, a4.Perform(make_tuple())); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace gmock_generated_actions_test } // namespace testing diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index 1ce8c451..5d839c41 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -114,6 +114,8 @@ class FooInterface { class MockFoo : public FooInterface { public: + MockFoo() {} + // Makes sure that a mock function parameter can be named. MOCK_METHOD1(VoidReturning, void(int n)); // NOLINT @@ -149,6 +151,9 @@ class MockFoo : public FooInterface { const string& k)); MOCK_CONST_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, CTConst, char(int)); #endif // GTEST_OS_WINDOWS + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); }; class FunctionMockerTest : public testing::Test { @@ -305,7 +310,12 @@ TEST_F(FunctionMockerTest, MocksFunctionsConstFunctionWithCallType) { class MockB { public: + MockB() {} + MOCK_METHOD0(DoB, void()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockB); }; // Tests that functions with no EXPECT_CALL() ruls can be called any @@ -345,10 +355,15 @@ class StackInterface { template class MockStack : public StackInterface { public: + MockStack() {} + MOCK_METHOD1_T(Push, void(const T& elem)); MOCK_METHOD0_T(Pop, void()); MOCK_CONST_METHOD0_T(GetSize, int()); // NOLINT MOCK_CONST_METHOD0_T(GetTop, const T&()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockStack); }; // Tests that template mock works. @@ -393,10 +408,15 @@ class StackInterfaceWithCallType { template class MockStackWithCallType : public StackInterfaceWithCallType { public: + MockStackWithCallType() {} + MOCK_METHOD1_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Push, void(const T& elem)); MOCK_METHOD0_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Pop, void()); MOCK_CONST_METHOD0_T_WITH_CALLTYPE(STDMETHODCALLTYPE, GetSize, int()); MOCK_CONST_METHOD0_T_WITH_CALLTYPE(STDMETHODCALLTYPE, GetTop, const T&()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockStackWithCallType); }; // Tests that template mock with calltype works. @@ -430,7 +450,12 @@ TEST(TemplateMockTestWithCallType, Works) { class MockOverloadedOnArgNumber { public: + MockOverloadedOnArgNumber() {} + MY_MOCK_METHODS1_; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockOverloadedOnArgNumber); }; TEST(OverloadedMockMethodTest, CanOverloadOnArgNumberInMacroBody) { @@ -450,7 +475,12 @@ TEST(OverloadedMockMethodTest, CanOverloadOnArgNumberInMacroBody) { class MockOverloadedOnConstness { public: + MockOverloadedOnConstness() {} + MY_MOCK_METHODS2_; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockOverloadedOnConstness); }; TEST(OverloadedMockMethodTest, CanOverloadOnConstnessInMacroBody) { diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 19024d0d..41413055 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -223,8 +223,9 @@ class GreaterThanMatcher : public MatcherInterface { *os << "is " << -diff << " less than " << rhs_; } } + private: - const int rhs_; + int rhs_; }; Matcher GreaterThan(int n) { @@ -411,7 +412,7 @@ TEST(ElementsAreTest, WorksForNestedContainer) { }; vector > nested; - for (int i = 0; i < GMOCK_ARRAY_SIZE_(strings); i++) { + for (size_t i = 0; i < GMOCK_ARRAY_SIZE_(strings); i++) { nested.push_back(list(strings[i], strings[i] + strlen(strings[i]))); } @@ -446,7 +447,12 @@ TEST(ElementsAreTest, WorksWithNativeArrayPassedByReference) { class NativeArrayPassedAsPointerAndSize { public: + NativeArrayPassedAsPointerAndSize() {} + MOCK_METHOD2(Helper, void(int* array, int size)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NativeArrayPassedAsPointerAndSize); }; TEST(ElementsAreTest, WorksWithNativeArrayPassedAsPointerAndSize) { @@ -550,7 +556,10 @@ TEST(MatcherMacroTest, Works) { // Tests that the description string supplied to MATCHER() must be // valid. -MATCHER(HasBadDescription, "Invalid%") { return true; } +MATCHER(HasBadDescription, "Invalid%") { + // Uses arg to suppress "unused parameter" warning. + return arg==arg; +} TEST(MatcherMacroTest, CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { @@ -560,7 +569,7 @@ TEST(MatcherMacroTest, "use \"%%\" instead of \"%\" to print \"%\"."); } -MATCHER(HasGoodDescription, "good") { return true; } +MATCHER(HasGoodDescription, "good") { return arg==arg; } TEST(MatcherMacroTest, AcceptsValidDescription) { const Matcher m = HasGoodDescription(); @@ -642,7 +651,7 @@ TEST(MatcherPMacroTest, } -MATCHER_P(HasGoodDescription1, n, "good %(n)s") { return true; } +MATCHER_P(HasGoodDescription1, n, "good %(n)s") { return arg==arg; } TEST(MatcherPMacroTest, AcceptsValidDescription) { const Matcher m = HasGoodDescription1(5); @@ -709,7 +718,7 @@ TEST(MatcherPnMacroTest, MATCHER_P2(HasComplexDescription, foo, bar, "is as complex as %(foo)s %(bar)s (i.e. %(*)s or %%%(foo)s!)") { - return true; + return arg==arg; } TEST(MatcherPnMacroTest, AcceptsValidDescription) { @@ -861,7 +870,7 @@ TEST(MatcherPnMacroTest, WorksForDifferentParameterTypes) { MATCHER_P2(EqConcat, prefix, suffix, "") { // The following lines promote the two parameters to desired types. std::string prefix_str(prefix); - char suffix_char(suffix); + char suffix_char = static_cast(suffix); return arg == prefix_str + suffix_char; } diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index ac3b2dd2..7dd83115 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -819,7 +819,7 @@ TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { TEST(NativeArrayTest, ConstructorFromArrayWorks) { const int a[3] = { 0, 1, 2 }; NativeArray na(a, 3, kReference); - EXPECT_EQ(3, na.size()); + EXPECT_EQ(3U, na.size()); EXPECT_EQ(a, na.begin()); } @@ -849,7 +849,7 @@ TEST(NativeArrayTest, TypeMembersAreCorrect) { TEST(NativeArrayTest, MethodsWork) { const int a[3] = { 0, 1, 2 }; NativeArray na(a, 3, kCopy); - ASSERT_EQ(3, na.size()); + ASSERT_EQ(3U, na.size()); EXPECT_EQ(3, na.end() - na.begin()); NativeArray::const_iterator it = na.begin(); @@ -875,7 +875,7 @@ TEST(NativeArrayTest, MethodsWork) { TEST(NativeArrayTest, WorksForTwoDimensionalArray) { const char a[2][3] = { "hi", "lo" }; NativeArray na(a, 2, kReference); - ASSERT_EQ(2, na.size()); + ASSERT_EQ(2U, na.size()); EXPECT_EQ(a, na.begin()); } @@ -910,11 +910,11 @@ TEST(StlContainerViewTest, WorksForStaticNativeArray) { int a1[3] = { 0, 1, 2 }; NativeArray a2 = StlContainerView::ConstReference(a1); - EXPECT_EQ(3, a2.size()); + EXPECT_EQ(3U, a2.size()); EXPECT_EQ(a1, a2.begin()); const NativeArray a3 = StlContainerView::Copy(a1); - ASSERT_EQ(3, a3.size()); + ASSERT_EQ(3U, a3.size()); EXPECT_EQ(0, a3.begin()[0]); EXPECT_EQ(1, a3.begin()[1]); EXPECT_EQ(2, a3.begin()[2]); @@ -937,12 +937,12 @@ TEST(StlContainerViewTest, WorksForDynamicNativeArray) { const int* const p1 = a1; NativeArray a2 = StlContainerView >:: ConstReference(make_tuple(p1, 3)); - EXPECT_EQ(3, a2.size()); + EXPECT_EQ(3U, a2.size()); EXPECT_EQ(a1, a2.begin()); const NativeArray a3 = StlContainerView >:: Copy(make_tuple(static_cast(a1), 3)); - ASSERT_EQ(3, a3.size()); + ASSERT_EQ(3U, a3.size()); EXPECT_EQ(0, a3.begin()[0]); EXPECT_EQ(1, a3.begin()[1]); EXPECT_EQ(2, a3.begin()[2]); diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 919ce651..907749d1 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -152,8 +152,9 @@ class GreaterThanMatcher : public MatcherInterface { *os << "is " << -diff << " less than " << rhs_; } } + private: - const int rhs_; + int rhs_; }; Matcher GreaterThan(int n) { @@ -335,7 +336,7 @@ class IntValue { public: // An int can be statically (although not implicitly) cast to a // IntValue. - explicit IntValue(int value) : value_(value) {} + explicit IntValue(int a_value) : value_(a_value) {} int value() const { return value_; } private: @@ -560,7 +561,7 @@ class Unprintable { public: Unprintable() : c_('a') {} - bool operator==(const Unprintable& rhs) { return true; } + bool operator==(const Unprintable& /* rhs */) { return true; } private: char c_; }; @@ -606,7 +607,7 @@ TEST(TypedEqTest, CanDescribeSelf) { // "undefined referece". template struct Type { - static bool IsTypeOf(const T& v) { return true; } + static bool IsTypeOf(const T& /* v */) { return true; } template static void IsTypeOf(T2 v); @@ -1861,8 +1862,9 @@ class IsGreaterThan { explicit IsGreaterThan(int threshold) : threshold_(threshold) {} bool operator()(int n) const { return n > threshold_; } + private: - const int threshold_; + int threshold_; }; // For testing Truly(). @@ -1959,7 +1961,12 @@ TEST(AllArgsTest, WorksForNonTuple) { class AllArgsHelper { public: + AllArgsHelper() {} + MOCK_METHOD2(Helper, int(char x, int y)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AllArgsHelper); }; TEST(AllArgsTest, WorksInWithClause) { @@ -2384,7 +2391,7 @@ TEST(PointeeTest, CanExplainMatchResult) { // An uncopyable class. class Uncopyable { public: - explicit Uncopyable(int value) : value_(value) {} + explicit Uncopyable(int a_value) : value_(a_value) {} int value() const { return value_; } private: @@ -2405,11 +2412,17 @@ struct AStruct { const double y; // A const field. Uncopyable z; // An uncopyable field. const char* p; // A pointer field. + + private: + GTEST_DISALLOW_ASSIGN_(AStruct); }; // A derived struct for testing Field(). struct DerivedStruct : public AStruct { char ch; + + private: + GTEST_DISALLOW_ASSIGN_(DerivedStruct); }; // Tests that Field(&Foo::field, ...) works when field is non-const. @@ -2943,7 +2956,7 @@ TEST(ResultOfTest, WorksForReferencingCallables) { class DivisibleByImpl { public: - explicit DivisibleByImpl(int divider) : divider_(divider) {} + explicit DivisibleByImpl(int a_divider) : divider_(a_divider) {} template bool Matches(const T& n) const { @@ -2958,7 +2971,7 @@ class DivisibleByImpl { *os << "is not divisible by " << divider_; } - void set_divider(int divider) { divider_ = divider; } + void set_divider(int a_divider) { divider_ = a_divider; } int divider() const { return divider_; } private: @@ -3021,7 +3034,7 @@ TEST(ExplainmatcherResultTest, MonomorphicMatcher) { class NotCopyable { public: - explicit NotCopyable(int value) : value_(value) {} + explicit NotCopyable(int a_value) : value_(a_value) {} int value() const { return value_; } diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index f5dab5bf..b3b17d33 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -65,6 +65,10 @@ using testing::Unused; using testing::WithArg; using testing::WithoutArgs; +// For suppressing compiler warnings on conversion possibly losing precision. +inline short Short(short n) { return n; } // NOLINT +inline char Char(char ch) { return ch; } + // Sample functions and functors for testing Invoke() and etc. int Nullary() { return 1; } @@ -85,7 +89,7 @@ bool Unary(int x) { return x < 0; } const char* Plus1(const char* s) { return s + 1; } -void VoidUnary(int n) { g_done = true; } +void VoidUnary(int /* n */) { g_done = true; } bool ByConstRef(const string& s) { return s == "Hi"; } @@ -239,13 +243,13 @@ TEST(InvokeTest, Unary) { TEST(InvokeTest, Binary) { Action a = Invoke(Binary); // NOLINT const char* p = "Hello"; - EXPECT_EQ(p + 2, a.Perform(make_tuple(p, 2))); + EXPECT_EQ(p + 2, a.Perform(make_tuple(p, Short(2)))); } // Tests using Invoke() with a ternary function. TEST(InvokeTest, Ternary) { Action a = Invoke(Ternary); // NOLINT - EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', 3))); + EXPECT_EQ(6, a.Perform(make_tuple(1, '\2', Short(3)))); } // Tests using Invoke() with a 4-argument function. @@ -340,14 +344,14 @@ TEST(InvokeTest, MethodWithUnusedParameters) { // Tests using Invoke() with a functor. TEST(InvokeTest, Functor) { - Action a = Invoke(plus()); // NOLINT - EXPECT_EQ(3, a.Perform(make_tuple(1, 2))); + Action a = Invoke(plus()); // NOLINT + EXPECT_EQ(3L, a.Perform(make_tuple(1, 2))); } // Tests using Invoke(f) as an action of a compatible type. TEST(InvokeTest, FunctionWithCompatibleType) { Action a = Invoke(SumOf4); // NOLINT - EXPECT_EQ(4321, a.Perform(make_tuple(4000, 300, 20, true))); + EXPECT_EQ(4321, a.Perform(make_tuple(4000, Short(300), Char(20), true))); } // Tests using Invoke() with an object pointer and a method pointer. @@ -378,7 +382,7 @@ TEST(InvokeMethodTest, Binary) { TEST(InvokeMethodTest, Ternary) { Foo foo; Action a = Invoke(&foo, &Foo::Ternary); // NOLINT - EXPECT_EQ(1124, a.Perform(make_tuple(1000, true, 1))); + EXPECT_EQ(1124, a.Perform(make_tuple(1000, true, Char(1)))); } // Tests using Invoke() with a 4-argument method. @@ -457,7 +461,7 @@ TEST(InvokeMethodTest, MethodWithCompatibleType) { Foo foo; Action a = // NOLINT Invoke(&foo, &Foo::SumOf4); - EXPECT_EQ(4444, a.Perform(make_tuple(4000, 300, 20, true))); + EXPECT_EQ(4444, a.Perform(make_tuple(4000, Short(300), Char(20), true))); } // Tests using WithoutArgs with an action that takes no argument. diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index faf0145b..1d36e03e 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -40,7 +40,12 @@ // clash with ::testing::Mock. class Mock { public: + Mock() {} + MOCK_METHOD0(DoThis, void()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mock); }; namespace testing { @@ -64,10 +69,14 @@ class Foo { class MockFoo : public Foo { public: + MockFoo() {} void Delete() { delete this; } MOCK_METHOD0(DoThis, void()); MOCK_METHOD1(DoThat, int(bool flag)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); }; class MockBar { @@ -89,6 +98,8 @@ class MockBar { private: string str_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockBar); }; // TODO(wan@google.com): find a way to re-enable these tests. diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index b2afb932..054313b7 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -85,7 +85,7 @@ class Castable { } private: - bool* const converted_; + bool* converted_; }; TEST(ImplicitCastTest, CanUseNonConstCastOperator) { @@ -104,7 +104,7 @@ class ConstCastable { } private: - bool* const converted_; + bool* converted_; }; TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { @@ -128,8 +128,8 @@ class ConstAndNonConstCastable { } private: - bool* const converted_; - bool* const const_converted_; + bool* converted_; + bool* const_converted_; }; TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index abfa923c..0553e9ce 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -77,7 +77,7 @@ class StreamableInGlobal { virtual ~StreamableInGlobal() {} }; -inline void operator<<(::std::ostream& os, const StreamableInGlobal& x) { +inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { os << "StreamableInGlobal"; } @@ -107,7 +107,7 @@ void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { template class PrintableViaPrintToTemplate { public: - explicit PrintableViaPrintToTemplate(const T& value) : value_(value) {} + explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} const T& value() const { return value_; } private: @@ -440,7 +440,7 @@ TEST(PrintPointerToPointerTest, IntPointerPointer) { // Tests printing (non-member) function pointers. -void MyFunction(int n) {} +void MyFunction(int /* n */) {} TEST(PrintPointerTest, NonMemberFunctionPointer) { // We cannot directly cast &MyFunction to const void* because the @@ -464,7 +464,7 @@ struct Foo { public: virtual ~Foo() {} int MyMethod(char x) { return x + 1; } - virtual char MyVirtualMethod(int n) { return 'a'; } + virtual char MyVirtualMethod(int /* n */) { return 'a'; } int value; }; @@ -603,7 +603,7 @@ class AllowsGenericStreaming {}; template std::basic_ostream& operator<<( std::basic_ostream& os, - const AllowsGenericStreaming& a) { + const AllowsGenericStreaming& /* a */) { return os << "AllowsGenericStreaming"; } @@ -620,7 +620,7 @@ class AllowsGenericStreamingTemplate {}; template std::basic_ostream& operator<<( std::basic_ostream& os, - const AllowsGenericStreamingTemplate& a) { + const AllowsGenericStreamingTemplate& /* a */) { return os << "AllowsGenericStreamingTemplate"; } @@ -641,7 +641,7 @@ class AllowsGenericStreamingAndImplicitConversionTemplate { template std::basic_ostream& operator<<( std::basic_ostream& os, - const AllowsGenericStreamingAndImplicitConversionTemplate& a) { + const AllowsGenericStreamingAndImplicitConversionTemplate& /* a */) { return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 5fd97112..c1e77381 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -97,16 +97,26 @@ class Result {}; class MockA { public: + MockA() {} + MOCK_METHOD1(DoA, void(int n)); // NOLINT MOCK_METHOD1(ReturnResult, Result(int n)); // NOLINT MOCK_METHOD2(Binary, bool(int x, int y)); // NOLINT MOCK_METHOD2(ReturnInt, int(int x, int y)); // NOLINT + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockA); }; class MockB { public: + MockB() {} + MOCK_CONST_METHOD0(DoB, int()); // NOLINT MOCK_METHOD1(DoB, int(int n)); // NOLINT + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockB); }; // Tests that EXPECT_CALL and ON_CALL compile in a presence of macro @@ -123,7 +133,12 @@ class CC { }; class MockCC : public CC { public: + MockCC() {} + MOCK_METHOD0(Method, int()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockCC); }; // Tests that a method with expanded name compiles. @@ -1617,8 +1632,19 @@ TEST(DeletingMockEarlyTest, Success2) { // Tests that it's OK to delete a mock object itself in its action. +// Suppresses warning on unreferenced formal parameter in MSVC with +// -W4. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif + ACTION_P(Delete, ptr) { delete ptr; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + TEST(DeletingMockEarlyTest, CanDeleteSelfInActionReturningVoid) { MockA* const a = new MockA; EXPECT_CALL(*a, DoA(_)).WillOnce(Delete(a)); @@ -1691,7 +1717,9 @@ class EvenNumberCardinality : public CardinalityInterface { } // Returns true iff call_count calls will saturate this cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const { return false; } + virtual bool IsSaturatedByCallCount(int /* call_count */) const { + return false; + } // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const { @@ -1740,9 +1768,14 @@ struct Unprintable { class MockC { public: + MockC() {} + MOCK_METHOD6(VoidMethod, void(bool cond, int n, string s, void* p, const Printable& x, Unprintable y)); MOCK_METHOD0(NonVoidMethod, int()); // NOLINT + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockC); }; // TODO(wan@google.com): find a way to re-enable these tests. @@ -1935,7 +1968,12 @@ void PrintTo(PrintMeNot /* dummy */, ::std::ostream* /* os */) { class LogTestHelper { public: + LogTestHelper() {} + MOCK_METHOD1(Foo, PrintMeNot(PrintMeNot)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(LogTestHelper); }; class GMockLogTest : public ::testing::Test { diff --git a/test/gmock_leak_test_.cc b/test/gmock_leak_test_.cc index 157bd7ec..24dfc1ff 100644 --- a/test/gmock_leak_test_.cc +++ b/test/gmock_leak_test_.cc @@ -48,7 +48,12 @@ class FooInterface { class MockFoo : public FooInterface { public: + MockFoo() {} + MOCK_METHOD0(DoThis, void()); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); }; TEST(LeakTest, LeakedMockWithExpectCallCausesFailureWhenLeakCheckingIsEnabled) { diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index 40554bfe..d9635907 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -206,6 +206,8 @@ class Interface { class Mock: public Interface { public: + Mock() {} + MOCK_METHOD1(VoidFromString, void(char* str)); MOCK_METHOD1(StringFromString, char*(char* str)); MOCK_METHOD1(IntFromString, int(char* str)); @@ -215,6 +217,9 @@ class Mock: public Interface { MOCK_METHOD1(VoidFromFloat, void(float n)); MOCK_METHOD1(VoidFromDouble, void(double n)); MOCK_METHOD1(VoidFromVector, void(const std::vector& v)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mock); }; class InvokeHelper { @@ -229,7 +234,7 @@ class InvokeHelper { class FieldHelper { public: - FieldHelper(int field) : field_(field) {} + FieldHelper(int a_field) : field_(a_field) {} int field() const { return field_; } int field_; // NOLINT -- need external access to field_ to test // the Field matcher. @@ -410,6 +415,16 @@ TEST(LinkTest, TestThrow) { } #endif // GTEST_HAS_EXCEPTIONS +// 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 + // Tests the linkage of actions created using ACTION macro. namespace { ACTION(Return1) { return 1; } @@ -441,6 +456,10 @@ ACTION_P2(ReturnEqualsEitherOf, first, second) { } } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + TEST(LinkTest, TestActionP2Macro) { Mock mock; char ch = 'x'; diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index c33dc6fb..24c9b383 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -49,9 +49,14 @@ using testing::Sequence; class MockFoo { public: + MockFoo() {} + MOCK_METHOD3(Bar, char(const std::string& s, int i, double x)); MOCK_METHOD2(Bar2, bool(int x, int y)); MOCK_METHOD2(Bar3, void(int x, int y)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); }; class GMockOutputTest : public testing::Test { -- cgit v1.2.3 From 7f8eb725b5f9f17b3d4dcc236e521674780726dc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 23 Dec 2009 20:48:53 +0000 Subject: Removes support for MSVC 7.1 from the scons scripts. --- scons/SConscript | 7 ------- scons/SConstruct | 9 +++------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/scons/SConscript b/scons/SConscript index 7c2bfbf6..764cd7bc 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -110,13 +110,6 @@ if env['PLATFORM'] == 'win32': env.Append(CCFLAGS=[ '-wd4127', # Disables warning "conditional expression is constant", # triggered by VC 8.0's own STL header . - '-wd4702', # Disables warning "unreachable code", triggered by VC - # 7.1's own STL header . - '-wd4675', # Disables warning "resolved overload was found by - # argument-dependent lookup" generated by VC 7.1. - # It just says that VC 7.1 fixed a bug in earlier - # versions of VC so the code behavior will be - # different than compiled with VC 6.0, for example. ]) # Note: The relative paths in SConscript files are relative to the location diff --git a/scons/SConstruct b/scons/SConstruct index 71707fc7..8f67d704 100644 --- a/scons/SConstruct +++ b/scons/SConstruct @@ -39,7 +39,7 @@ # where frequently used command-line options include: # -h print usage help. # BUILD=all build all build types. -# BUILD=win-opt build the given build type. +# BUILD=win-opt8 build the given build type. EnsurePythonVersion(2, 3) @@ -88,11 +88,8 @@ sconstruct_helper.Initialize(build_root_path='..', win_base = sconstruct_helper.MakeWinBaseEnvironment() -if win_base.get('MSVS_VERSION', None) == '7.1': - sconstruct_helper.EnvCreator.WithExceptions(win_base) - -sconstruct_helper.MakeWinDebugEnvironment(win_base, 'win-dbg') -sconstruct_helper.MakeWinOptimizedEnvironment(win_base, 'win-opt') +sconstruct_helper.MakeWinDebugEnvironment(win_base, 'win-dbg8') +sconstruct_helper.MakeWinOptimizedEnvironment(win_base, 'win-opt8') sconstruct_helper.ConfigureGccEnvironments() -- cgit v1.2.3 From 821133180ccdb9eb062548d964929ba3b354eb84 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 8 Jan 2010 21:55:40 +0000 Subject: Implements the new matcher API. --- include/gmock/gmock-generated-matchers.h | 189 ++++--- include/gmock/gmock-generated-matchers.h.pump | 92 +++- include/gmock/gmock-matchers.h | 704 ++++++++++++++------------ include/gmock/gmock-spec-builders.h | 6 +- test/gmock-generated-matchers_test.cc | 52 ++ test/gmock-matchers_test.cc | 145 +++++- 6 files changed, 763 insertions(+), 425 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 18420c1d..731ad7df 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -229,8 +229,9 @@ class ArgsMatcherImpl : public MatcherInterface { explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) : inner_matcher_(SafeMatcherCast(inner_matcher)) {} - virtual bool Matches(ArgsTuple args) const { - return inner_matcher_.Matches(GetSelectedArgs(args)); + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(GetSelectedArgs(args), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -243,11 +244,6 @@ class ArgsMatcherImpl : public MatcherInterface { inner_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(ArgsTuple args, - ::std::ostream* os) const { - inner_matcher_.ExplainMatchResultTo(GetSelectedArgs(args), os); - } - private: static SelectedArgs GetSelectedArgs(ArgsTuple args) { return TupleFields\ - bool name##Matcher::\ - gmock_Impl::Matches(arg_type arg) const + bool name##Matcher::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P(name, p0, description)\ template \ @@ -1071,7 +1109,8 @@ ElementsAreArray(const T (&array)[N]) { explicit gmock_Impl(p0##_type gmock_p0, \ const ::testing::internal::Interpolations& gmock_interp)\ : p0(gmock_p0), gmock_interp_(gmock_interp) {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -1105,8 +1144,10 @@ ElementsAreArray(const T (&array)[N]) { }\ template \ template \ - bool name##MatcherP::\ - gmock_Impl::Matches(arg_type arg) const + 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 \ @@ -1118,7 +1159,8 @@ ElementsAreArray(const T (&array)[N]) { gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ const ::testing::internal::Interpolations& gmock_interp)\ : p0(gmock_p0), p1(gmock_p1), gmock_interp_(gmock_interp) {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -1156,8 +1198,11 @@ ElementsAreArray(const T (&array)[N]) { }\ template \ template \ - bool name##MatcherP2::\ - gmock_Impl::Matches(arg_type arg) const + 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 \ @@ -1170,7 +1215,8 @@ ElementsAreArray(const T (&array)[N]) { const ::testing::internal::Interpolations& gmock_interp)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ gmock_interp_(gmock_interp) {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -1211,8 +1257,11 @@ ElementsAreArray(const T (&array)[N]) { }\ template \ template \ - bool name##MatcherP3::\ - gmock_Impl::Matches(arg_type arg) const + 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 \ template \ - bool name##MatcherP4::\ - gmock_Impl::Matches(arg_type arg) const + 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 \ template \ - bool name##MatcherP5::\ - gmock_Impl::Matches(arg_type arg) const + 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 \ template \ bool name##MatcherP6::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type>::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 \ template \ bool name##MatcherP7::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type, p6##_type>::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 \ template \ bool name##MatcherP8::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type, p6##_type, \ + p7##_type>::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 \ template \ bool name##MatcherP9::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type, p6##_type, p7##_type, \ + p8##_type>::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 \ template \ bool name##MatcherP10::\ - gmock_Impl::Matches(arg_type arg) const + p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \ + p9##_type>::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/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 8abbc0cb..fb2bc358 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -116,8 +116,9 @@ class ArgsMatcherImpl : public MatcherInterface { explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) : inner_matcher_(SafeMatcherCast(inner_matcher)) {} - virtual bool Matches(ArgsTuple args) const { - return inner_matcher_.Matches(GetSelectedArgs(args)); + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(GetSelectedArgs(args), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -130,11 +131,6 @@ class ArgsMatcherImpl : public MatcherInterface { inner_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(ArgsTuple args, - ::std::ostream* os) const { - inner_matcher_.ExplainMatchResultTo(GetSelectedArgs(args), os); - } - private: static SelectedArgs GetSelectedArgs(ArgsTuple args) { return TupleFields::GetSelectedFields(args); @@ -301,14 +297,19 @@ $$ // show up in the generated code. // The MATCHER* family of macros can be used in a namespace scope to -// define custom matchers easily. The syntax: +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// 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'. +// 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 @@ -341,6 +342,9 @@ $$ // show up in the generated code. // 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 @@ -351,6 +355,9 @@ $$ // show up in the generated code. // 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: // @@ -381,6 +388,9 @@ $$ // show up in the generated code. // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to // support multi-parameter matchers. // +// Describing Parameterized Matchers +// ================================= +// // When defining a parameterized matcher, you can use Python-style // interpolations in the description string to refer to the parameter // values. We support the following syntax currently: @@ -413,6 +423,9 @@ $$ // show up in the generated code. // // Expected: in closed range (4, 6) // +// Types of Matcher Parameters +// =========================== +// // For the purpose of typing, you can view // // MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } @@ -440,23 +453,44 @@ $$ // show up in the generated code. // 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) { ... } // -// 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, -// 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). +// Caveats +// ======= // -// CAVEAT: +// 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 @@ -464,7 +498,8 @@ $$ // show up in the generated code. // Once that's done, we'll consider supporting using MATCHER*() inside // a function. // -// MORE INFORMATION: +// More Information +// ================ // // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. @@ -510,7 +545,8 @@ $var param_field_decls2 = [[$for j public:\ [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ $impl_inits {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -540,8 +576,10 @@ $var param_field_decls2 = [[$for j return $class_name$param_types($params);\ }\$template template \ - bool $class_name$param_types::\ - gmock_Impl::Matches(arg_type arg) const + bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const ]] diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 5f5a29fd..b1689d6e 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -64,14 +64,74 @@ namespace testing { // 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. + 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_; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + // The implementation of a matcher. template class MatcherInterface { public: virtual ~MatcherInterface() {} + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + // + // You should override this method when defining a new matcher. For + // backward compatibility, we provide a default implementation that + // just forwards to the old, deprecated matcher API (Matches() and + // ExplainMatchResultTo()). + // + // 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 { + const bool match = Matches(x); + if (listener->stream() != NULL) { + ExplainMatchResultTo(x, listener->stream()); + } + return match; + } + + // DEPRECATED. This method will be removed. Override + // MatchAndExplain() instead. + // // Returns true iff the matcher matches x. - virtual bool Matches(T x) const = 0; + virtual bool Matches(T /* x */) const { return false; } // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; @@ -88,6 +148,9 @@ class MatcherInterface { *os << ")"; } + // DEPRECATED. This method will be removed. Override + // MatchAndExplain() instead. + // // Explains why x matches, or doesn't match, the matcher. Override // this to provide any additional information that helps a user // understand the match result. @@ -100,14 +163,58 @@ class MatcherInterface { namespace internal { +// 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); +}; + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation heard so far. + internal::string str() const { return ss_.str(); } + + private: + ::std::stringstream ss_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); +}; + // 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 { return impl_->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); } @@ -119,7 +226,8 @@ class MatcherBase { // Explains why x matches, or doesn't match, the matcher. void ExplainMatchResultTo(T x, ::std::ostream* os) const { - impl_->ExplainMatchResultTo(x, os); + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); } protected: @@ -156,6 +264,27 @@ inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, // prints the value of x elsewhere. } +// The default implementation of MatchAndExplain() for polymorphic +// matchers. +template +inline bool MatchAndExplain(const PolymorphicMatcherImpl& impl, + const T& x, + MatchResultListener* listener) { + const bool match = impl.Matches(x); + + ::std::ostream* const os = listener->stream(); + if (os != NULL) { + using ::testing::internal::ExplainMatchResultTo; + // When resolving the following call, both + // ::testing::internal::ExplainMatchResultTo() and + // foo::ExplainMatchResultTo() are considered, where foo is the + // namespace where class PolymorphicMatcherImpl is defined. + ExplainMatchResultTo(impl, x, os); + } + + return match; +} + } // namespace internal // A Matcher is a copyable and IMMUTABLE (except by assignment) @@ -220,19 +349,31 @@ class Matcher // 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 first provides a Impl class -// that has a Matches() method, a DescribeTo() method, and a -// DescribeNegationTo() method. The Matches() method is usually a -// method template (such that it works with multiple types). Then the -// user creates the polymorphic matcher using -// MakePolymorphicMatcher(). To provide additional explanation to the -// match result, define a FREE function (or function template) +// To define a polymorphic matcher in the old, deprecated way, a user +// first provides an Impl class that has a Matches() method, a +// DescribeTo() method, and a DescribeNegationTo() method. The +// Matches() method is usually a method template (such that it works +// with multiple types). Then the user creates the polymorphic +// matcher using MakePolymorphicMatcher(). To provide additional +// explanation to the match result, define a FREE function (or +// function template) // // void ExplainMatchResultTo(const Impl& matcher, const Value& value, // ::std::ostream* os); // -// in the SAME NAME SPACE where Impl is defined. See the definition -// of NotNull() for a complete example. +// in the SAME NAME SPACE where Impl is defined. +// +// The new, recommended way to define a polymorphic matcher is to +// provide an Impl class that has a DescribeTo() method and a +// DescribeNegationTo() method, and define a FREE function (or +// function template) +// +// bool MatchAndExplain(const Impl& matcher, const Value& value, +// MatchResultListener* listener); +// +// in the SAME NAME SPACE where Impl is defined. +// +// See the definition of NotNull() for a complete example. template class PolymorphicMatcher { public: @@ -257,8 +398,6 @@ class PolymorphicMatcher { public: explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - virtual bool Matches(T x) const { return impl_.Matches(x); } - virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } @@ -267,22 +406,15 @@ class PolymorphicMatcher { impl_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - using ::testing::internal::ExplainMatchResultTo; - + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { // C++ uses Argument-Dependent Look-up (aka Koenig Look-up) to - // resolve the call to ExplainMatchResultTo() here. This - // means that if there's a ExplainMatchResultTo() function - // defined in the name space where class Impl is defined, it - // will be picked by the compiler as the better match. - // Otherwise the default implementation of it in - // ::testing::internal will be picked. - // - // This look-up rule lets a writer of a polymorphic matcher - // customize the behavior of ExplainMatchResultTo() when he - // cares to. Nothing needs to be done by the writer if he - // doesn't need to customize it. - ExplainMatchResultTo(impl_, x, os); + // resolve the call to MatchAndExplain() here. This means that + // if there's a MatchAndExplain() function defined in the name + // space where class Impl is defined, it will be picked by the + // compiler as the better match. Otherwise the default + // implementation of it in ::testing::internal will be picked. + using ::testing::internal::MatchAndExplain; + return MatchAndExplain(impl_, x, listener); } private: @@ -390,16 +522,12 @@ Matcher A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { -// Appends the explanation on the result of matcher.Matches(value) to -// os iff the explanation is not empty. -template -void ExplainMatchResultAsNeededTo(const Matcher& matcher, T value, - ::std::ostream* os) { - ::std::stringstream reason; - matcher.ExplainMatchResultTo(value, &reason); - const internal::string s = reason.str(); - if (s != "") { - *os << " (" << s << ")"; +// If the given string is not empty and os is not NULL, wraps the +// string inside a pair of parentheses and streams the result to os. +inline void StreamInParensAsNeeded(const internal::string& str, + ::std::ostream* os) { + if (!str.empty() && os != NULL) { + *os << " (" << str << ")"; } } @@ -439,7 +567,8 @@ class TuplePrefix { get(matchers); typedef typename tuple_element::type Value; Value value = get(values); - if (!matcher.Matches(value)) { + 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 << ": "; @@ -452,7 +581,8 @@ class TuplePrefix { // the address is interesting. internal::UniversalPrinter:: Print(value, os); - ExplainMatchResultAsNeededTo(matcher, value, os); + + StreamInParensAsNeeded(listener.str(), os); *os << "\n"; } } @@ -537,8 +667,8 @@ class MatcherCastImpl > { : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. - virtual bool Matches(T x) const { - return source_matcher_.Matches(static_cast(x)); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return source_matcher_.MatchAndExplain(static_cast(x), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -549,10 +679,6 @@ class MatcherCastImpl > { source_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - source_matcher_.ExplainMatchResultTo(static_cast(x), os); - } - private: const Matcher source_matcher_; @@ -572,7 +698,8 @@ class MatcherCastImpl > { template class AnyMatcherImpl : public MatcherInterface { public: - virtual bool Matches(T /* x */) const { return true; } + 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 @@ -618,7 +745,10 @@ class AnythingMatcher { class Impl : public MatcherInterface { \ public: \ explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \ - virtual bool Matches(Lhs lhs) const { return lhs op rhs_; } \ + virtual bool MatchAndExplain(\ + Lhs lhs, MatchResultListener* /* listener */) const { \ + return lhs op rhs_; \ + } \ virtual void DescribeTo(::std::ostream* os) const { \ *os << "is " relation " "; \ UniversalPrinter::Print(rhs_, os); \ @@ -719,7 +849,11 @@ class RefMatcher { // Matches() takes a Super& (as opposed to const Super&) in // order to match the interface MatcherInterface. - virtual bool Matches(Super& x) const { return &x == &object_; } // NOLINT + virtual bool MatchAndExplain( + Super& x, MatchResultListener* listener) const { + *listener << "is located @" << static_cast(&x); + return &x == &object_; + } virtual void DescribeTo(::std::ostream* os) const { *os << "references the variable "; @@ -731,11 +865,6 @@ class RefMatcher { UniversalPrinter::Print(object_, os); } - virtual void ExplainMatchResultTo(Super& x, // NOLINT - ::std::ostream* os) const { - *os << "is located @" << static_cast(&x); - } - private: const Super& object_; @@ -1017,7 +1146,9 @@ class MatchesRegexMatcher { template \ class Impl : public MatcherInterface&> { \ public: \ - virtual bool Matches(const ::std::tr1::tuple& args) const { \ + virtual bool MatchAndExplain( \ + const ::std::tr1::tuple& args, \ + MatchResultListener* /* listener */) const { \ return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ } \ virtual void DescribeTo(::std::ostream* os) const { \ @@ -1049,8 +1180,8 @@ class NotMatcherImpl : public MatcherInterface { explicit NotMatcherImpl(const Matcher& matcher) : matcher_(matcher) {} - virtual bool Matches(T x) const { - return !matcher_.Matches(x); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return !matcher_.MatchAndExplain(x, listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -1061,10 +1192,6 @@ class NotMatcherImpl : public MatcherInterface { matcher_.DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - matcher_.ExplainMatchResultTo(x, os); - } - private: const Matcher matcher_; @@ -1101,10 +1228,6 @@ class BothOfMatcherImpl : public MatcherInterface { BothOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} - virtual bool Matches(T x) const { - return matcher1_.Matches(x) && matcher2_.Matches(x); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); @@ -1118,35 +1241,34 @@ class BothOfMatcherImpl : public MatcherInterface { DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - if (Matches(x)) { - // When both matcher1_ and matcher2_ match x, we need to - // explain why *both* of them match. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); + 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; + } - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); + // Otherwise we need to explain why *both* of them match. + const internal::string s1 = listener1.str(); + const internal::string s2 = listener2.str(); - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } - } + if (s1 == "") { + *listener << s2; } else { - // Otherwise we only need to explain why *one* of them fails - // to match. - if (!matcher1_.Matches(x)) { - matcher1_.ExplainMatchResultTo(x, os); - } else { - matcher2_.ExplainMatchResultTo(x, os); + *listener << s1; + if (s2 != "") { + *listener << "; " << s2; } } + return true; } private: @@ -1190,10 +1312,6 @@ class EitherOfMatcherImpl : public MatcherInterface { EitherOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} - virtual bool Matches(T x) const { - return matcher1_.Matches(x) || matcher2_.Matches(x); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); @@ -1207,34 +1325,34 @@ class EitherOfMatcherImpl : public MatcherInterface { DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - if (Matches(x)) { - // If either matcher1_ or matcher2_ matches x, we just need - // to explain why *one* of them matches. - if (matcher1_.Matches(x)) { - matcher1_.ExplainMatchResultTo(x, os); - } else { - matcher2_.ExplainMatchResultTo(x, os); - } - } else { - // Otherwise we need to explain why *neither* matches. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + // If either matcher1_ or matcher2_ matches x, we just need to + // explain why *one* of them matches. + StringMatchResultListener listener1; + if (matcher1_.MatchAndExplain(x, &listener1)) { + *listener << listener1.str(); + return true; + } - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); + StringMatchResultListener listener2; + if (matcher2_.MatchAndExplain(x, &listener2)) { + *listener << listener2.str(); + return true; + } - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } + // Otherwise we need to explain why *both* of them fail. + const internal::string s1 = listener1.str(); + const internal::string s2 = listener2.str(); + + if (s1 == "") { + *listener << s2; + } else { + *listener << s1; + if (s2 != "") { + *listener << "; " << s2; } } + return false; } private: @@ -1367,7 +1485,8 @@ class PredicateFormatterFromMatcher { // Matcher(matcher_), as the latter won't compile when // matcher_ has type Matcher (e.g. An()). const Matcher matcher = MatcherCast(matcher_); - if (matcher.Matches(x)) { + StringMatchResultListener listener; + if (matcher.MatchAndExplain(x, &listener)) { return AssertionSuccess(); } else { ::std::stringstream ss; @@ -1376,7 +1495,7 @@ class PredicateFormatterFromMatcher { matcher.DescribeTo(&ss); ss << "\n Actual: "; UniversalPrinter::Print(x, &ss); - ExplainMatchResultAsNeededTo(matcher, x, &ss); + StreamInParensAsNeeded(listener.str(), &ss); return AssertionFailure(Message() << ss.str()); } } @@ -1417,7 +1536,8 @@ class FloatingEqMatcher { Impl(FloatType rhs, bool nan_eq_nan) : rhs_(rhs), nan_eq_nan_(nan_eq_nan) {} - virtual bool Matches(T value) const { + virtual bool MatchAndExplain(T value, + MatchResultListener* /* listener */) const { const FloatingPoint lhs(value), rhs(rhs_); // Compares NaNs first, if nan_eq_nan_ is true. @@ -1525,10 +1645,6 @@ class PointeeMatcher { explicit Impl(const InnerMatcher& matcher) : matcher_(MatcherCast(matcher)) {} - virtual bool Matches(Pointer p) const { - return GetRawPointer(p) != NULL && matcher_.Matches(*p); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "points to a value that "; matcher_.DescribeTo(os); @@ -1539,17 +1655,18 @@ class PointeeMatcher { matcher_.DescribeTo(os); } - virtual void ExplainMatchResultTo(Pointer pointer, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Pointer pointer, + MatchResultListener* listener) const { if (GetRawPointer(pointer) == NULL) - return; + return false; - ::std::stringstream ss; - matcher_.ExplainMatchResultTo(*pointer, &ss); - const internal::string s = ss.str(); + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(*pointer, &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "points to a value that " << s; + *listener << "points to a value that " << s; } + return match; } private: @@ -1572,16 +1689,6 @@ class FieldMatcher { const Matcher& matcher) : field_(field), matcher_(matcher) {} - // Returns true iff the inner matcher matches obj.field. - bool Matches(const Class& obj) const { - return matcher_.Matches(obj.*field_); - } - - // Returns true iff the inner matcher matches obj->field. - bool Matches(const Class* p) const { - return (p != NULL) && matcher_.Matches(p->*field_); - } - void DescribeTo(::std::ostream* os) const { *os << "the given field "; matcher_.DescribeTo(os); @@ -1592,27 +1699,29 @@ class FieldMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of ExplainMatchResultTo() is needed to help + // The first argument of MatchAndExplain() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Field() matcher is used to match a pointer. - void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, - ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo(obj.*field_, &ss); - const internal::string s = ss.str(); + bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "the given field " << s; + *listener << "the given field " << s; } + return match; } - void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, - ::std::ostream* os) const { - if (p != NULL) { - // Since *p has a field, it must be a class/struct/union type - // and thus cannot be a pointer. Therefore we pass false_type() - // as the first argument. - ExplainMatchResultTo(false_type(), *p, os); - } + bool MatchAndExplain(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { + if (p == NULL) + return false; + + // Since *p has a field, it must be a class/struct/union type and + // thus cannot be a pointer. Therefore we pass false_type() as + // the first argument. + return MatchAndExplain(false_type(), *p, listener); } private: @@ -1622,12 +1731,11 @@ class FieldMatcher { GTEST_DISALLOW_ASSIGN_(FieldMatcher); }; -// Explains the result of matching an object or pointer against a field matcher. template -void ExplainMatchResultTo(const FieldMatcher& matcher, - const T& value, ::std::ostream* os) { - matcher.ExplainMatchResultTo( - typename ::testing::internal::is_pointer::type(), value, os); +bool MatchAndExplain(const FieldMatcher& matcher, + const T& value, MatchResultListener* listener) { + return matcher.MatchAndExplain( + typename ::testing::internal::is_pointer::type(), value, listener); } // Implements the Property() matcher for matching a property @@ -1645,16 +1753,6 @@ class PropertyMatcher { const Matcher& matcher) : property_(property), matcher_(matcher) {} - // Returns true iff obj.property() matches the inner matcher. - bool Matches(const Class& obj) const { - return matcher_.Matches((obj.*property_)()); - } - - // Returns true iff p->property() matches the inner matcher. - bool Matches(const Class* p) const { - return (p != NULL) && matcher_.Matches((p->*property_)()); - } - void DescribeTo(::std::ostream* os) const { *os << "the given property "; matcher_.DescribeTo(os); @@ -1665,27 +1763,30 @@ class PropertyMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of ExplainMatchResultTo() is needed to help + // The first argument of MatchAndExplain() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Property() matcher is used to match a pointer. - void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, - ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo((obj.*property_)(), &ss); - const internal::string s = ss.str(); + bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain((obj.*property_)(), + &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "the given property " << s; + *listener << "the given property " << s; } + return match; } - void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, - ::std::ostream* os) const { - if (p != NULL) { - // Since *p has a property method, it must be a - // class/struct/union type and thus cannot be a pointer. - // Therefore we pass false_type() as the first argument. - ExplainMatchResultTo(false_type(), *p, os); - } + bool MatchAndExplain(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { + if (p == NULL) + return false; + + // Since *p has a property method, it must be a class/struct/union + // type and thus cannot be a pointer. Therefore we pass + // false_type() as the first argument. + return MatchAndExplain(false_type(), *p, listener); } private: @@ -1695,13 +1796,11 @@ class PropertyMatcher { GTEST_DISALLOW_ASSIGN_(PropertyMatcher); }; -// Explains the result of matching an object or pointer against a -// property matcher. -template -void ExplainMatchResultTo(const PropertyMatcher& matcher, - const T& value, ::std::ostream* os) { - matcher.ExplainMatchResultTo( - typename ::testing::internal::is_pointer::type(), value, os); +template +bool MatchAndExplain(const PropertyMatcher& matcher, + const T& value, MatchResultListener* listener) { + return matcher.MatchAndExplain( + typename ::testing::internal::is_pointer::type(), value, listener); } // Type traits specifying various features of different functors for ResultOf. @@ -1759,13 +1858,6 @@ class ResultOfMatcher { public: Impl(CallableStorageType callable, const Matcher& matcher) : callable_(callable), matcher_(matcher) {} - // Returns true iff callable_(obj) matches the inner matcher. - // The calling syntax is different for different types of callables - // so we abstract it in CallableTraits::Invoke(). - virtual bool Matches(T obj) const { - return matcher_.Matches( - CallableTraits::template Invoke(callable_, obj)); - } virtual void DescribeTo(::std::ostream* os) const { *os << "result of the given callable "; @@ -1777,14 +1869,17 @@ class ResultOfMatcher { matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T obj, ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo( + virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain( CallableTraits::template Invoke(callable_, obj), - &ss); - const internal::string s = ss.str(); + &inner_listener); + + const internal::string s = inner_listener.str(); if (s != "") - *os << "result of the given callable " << s; + *listener << "result of the given callable " << s; + + return match; } private: @@ -1929,17 +2024,6 @@ class ContainsMatcherImpl : public MatcherInterface { : inner_matcher_( testing::SafeMatcherCast(inner_matcher)) {} - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - for (typename StlContainer::const_iterator it = stl_container.begin(); - it != stl_container.end(); ++it) { - if (inner_matcher_.Matches(*it)) - return true; - } - return false; - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "contains at least one element that "; @@ -1952,19 +2036,18 @@ class ContainsMatcherImpl : public MatcherInterface { inner_matcher_.DescribeTo(os); } - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); - - // We need to explain which (if any) element matches inner_matcher_. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; it != stl_container.end(); ++it, ++i) { + size_t i = 0; + for (typename StlContainer::const_iterator it = stl_container.begin(); + it != stl_container.end(); ++it, ++i) { if (inner_matcher_.Matches(*it)) { - *os << "element " << i << " matches"; - return; + *listener << "element " << i << " matches"; + return true; } } + return false; } private: @@ -2007,8 +2090,9 @@ class KeyMatcherImpl : public MatcherInterface { } // Returns true iff 'key_value.first' (the key) matches the inner matcher. - virtual bool Matches(PairType key_value) const { - return inner_matcher_.Matches(key_value.first); + virtual bool MatchAndExplain(PairType key_value, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(key_value.first, listener); } // Describes what this matcher does. @@ -2023,12 +2107,6 @@ class KeyMatcherImpl : public MatcherInterface { inner_matcher_.DescribeTo(os); } - // Explains why 'key_value' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(PairType key_value, - ::std::ostream* os) const { - inner_matcher_.ExplainMatchResultTo(key_value.first, os); - } - private: const Matcher inner_matcher_; @@ -2069,13 +2147,6 @@ class PairMatcherImpl : public MatcherInterface { testing::SafeMatcherCast(second_matcher)) { } - // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' - // matches second_matcher. - virtual bool Matches(PairType a_pair) const { - return first_matcher_.Matches(a_pair.first) && - second_matcher_.Matches(a_pair.second); - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "has a first field that "; @@ -2092,28 +2163,40 @@ class PairMatcherImpl : public MatcherInterface { second_matcher_.DescribeNegationTo(os); } - // Explains why 'a_pair' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(PairType a_pair, - ::std::ostream* os) const { - ::std::stringstream ss1; - first_matcher_.ExplainMatchResultTo(a_pair.first, &ss1); - internal::string s1 = ss1.str(); + // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' + // matches second_matcher. + virtual bool MatchAndExplain(PairType a_pair, + MatchResultListener* listener) const { + StringMatchResultListener listener1; + const bool match1 = first_matcher_.MatchAndExplain(a_pair.first, + &listener1); + internal::string s1 = listener1.str(); if (s1 != "") { - s1 = "the first field " + s1; + s1 = "the first field " + s1; + } + if (!match1) { + *listener << s1; + return false; } - ::std::stringstream ss2; - second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2); - internal::string s2 = ss2.str(); + StringMatchResultListener listener2; + const bool match2 = second_matcher_.MatchAndExplain(a_pair.second, + &listener2); + internal::string s2 = listener2.str(); if (s2 != "") { - s2 = "the second field " + s2; + s2 = "the second field " + s2; + } + if (!match2) { + *listener << s2; + return false; } - *os << s1; + *listener << s1; if (s1 != "" && s2 != "") { - *os << ", and "; + *listener << ", and "; } - *os << s2; + *listener << s2; + return true; } private: @@ -2165,21 +2248,6 @@ class ElementsAreMatcherImpl : public MatcherInterface { } } - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - if (stl_container.size() != count()) - return false; - - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (!matchers_[i].Matches(*it)) - return false; - } - - return true; - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { if (count() == 0) { @@ -2216,63 +2284,54 @@ class ElementsAreMatcherImpl : public MatcherInterface { } } - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); - if (Matches(container)) { - // We need to explain why *each* element matches (the obvious - // ones can be skipped). - - bool reason_printed = false; - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - - const string s = ss.str(); - if (!s.empty()) { - if (reason_printed) { - *os << ",\n"; - } - *os << "element " << i << " " << s; - reason_printed = true; - } - } - } else { - // We need to explain why the container doesn't match. - const size_t actual_count = stl_container.size(); - if (actual_count != count()) { - // The element count doesn't match. If the container is - // empty, there's no need to explain anything as Google Mock - // already prints the empty container. Otherwise we just need - // to show how many elements there actually are. - if (actual_count != 0) { - *os << "has " << Elements(actual_count); - } - return; + const size_t actual_count = stl_container.size(); + if (actual_count != count()) { + // The element count doesn't match. If the container is empty, + // there's no need to explain anything as Google Mock already + // prints the empty container. Otherwise we just need to show + // how many elements there actually are. + if (actual_count != 0) { + *listener << "has " << Elements(actual_count); } + return false; + } - // The container has the right size but at least one element - // doesn't match expectation. We need to find this element and - // explain why it doesn't match. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (matchers_[i].Matches(*it)) { - continue; - } + typename StlContainer::const_iterator it = stl_container.begin(); + // explanations[i] is the explanation of the element at index i. + std::vector explanations(count()); + for (size_t i = 0; i != count(); ++it, ++i) { + StringMatchResultListener s; + if (matchers_[i].MatchAndExplain(*it, &s)) { + explanations[i] = s.str(); + } else { + // The container has the right size but the i-th element + // doesn't match its expectation. + *listener << "element " << i << " doesn't match"; + + StreamInParensAsNeeded(s.str(), listener->stream()); + return false; + } + } - *os << "element " << i << " doesn't match"; + // Every element matches its expectation. We need to explain why + // (the obvious ones can be skipped). - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - const string s = ss.str(); - if (!s.empty()) { - *os << " (" << s << ")"; + bool reason_printed = false; + for (size_t i = 0; i != count(); ++i) { + const internal::string& s = explanations[i]; + if (!s.empty()) { + if (reason_printed) { + *listener << ",\n"; } - return; + *listener << "element " << i << " " << s; + reason_printed = true; } } + + return true; } private: @@ -2811,13 +2870,14 @@ Truly(Predicate pred) { // values that are included in one container but not the other. (Duplicate // values and order differences are not explained.) template -inline PolymorphicMatcher > ContainerEq(const Container& rhs) { // This following line is for working around a bug in MSVC 8.0, // which causes Container to be a const type sometimes. typedef GMOCK_REMOVE_CONST_(Container) RawContainer; - return MakePolymorphicMatcher(internal::ContainerEqMatcher(rhs)); + return MakePolymorphicMatcher( + internal::ContainerEqMatcher(rhs)); } // Matches an STL-style container or a native array that contains at diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 9aa0a9ee..d8d4749a 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1004,13 +1004,13 @@ class TypedExpectation : public ExpectationBase { if (!TupleMatches(matchers_, args)) { DescribeMatchFailureTupleTo(matchers_, args, os); } - if (!extra_matcher_.Matches(args)) { + StringMatchResultListener listener; + if (!extra_matcher_.MatchAndExplain(args, &listener)) { *os << " Expected args: "; extra_matcher_.DescribeTo(os); *os << "\n Actual: don't match"; - internal::ExplainMatchResultAsNeededTo( - extra_matcher_, args, os); + internal::StreamInParensAsNeeded(listener.str(), os); *os << "\n"; } } else if (!AllPrerequisitesAreSatisfied()) { diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 41413055..40c2367c 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -136,6 +136,16 @@ TEST(ArgsTest, AcceptsDecreasingTemplateArgs) { EXPECT_THAT(t, Not(Args<2, 1>(Lt()))); } +// The MATCHER*() 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 + MATCHER(SumIsZero, "") { return get<0>(arg) + get<1>(arg) + get<2>(arg) == 0; } @@ -553,6 +563,44 @@ TEST(MatcherMacroTest, Works) { EXPECT_EQ("", Explain(m, 7)); } +// Tests explaining match result in a MATCHER* macro. + +MATCHER(IsEven2, "is even") { + if ((arg % 2) == 0) { + // Verifies that we can stream to result_listener, a listener + // supplied by the MATCHER macro implicitly. + *result_listener << "OK"; + return true; + } else { + *result_listener << "% 2 == " << (arg % 2); + return false; + } +} + +MATCHER_P2(EqSumOf, x, y, "") { + if (arg == (x + y)) { + *result_listener << "OK"; + return true; + } else { + // Verifies that we can stream to the underlying stream of + // result_listener. + if (result_listener->stream() != NULL) { + *result_listener->stream() << "diff == " << (x + y - arg); + } + return false; + } +} + +TEST(MatcherMacroTest, CanExplainMatchResult) { + const Matcher m1 = IsEven2(); + EXPECT_EQ("OK", Explain(m1, 4)); + EXPECT_EQ("% 2 == 1", Explain(m1, 5)); + + const Matcher m2 = EqSumOf(1, 2); + EXPECT_EQ("OK", Explain(m2, 3)); + EXPECT_EQ("diff == -1", Explain(m2, 4)); +} + // Tests that the description string supplied to MATCHER() must be // valid. @@ -1052,4 +1100,8 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { EXPECT_THAT(a, Contains(Not(Contains(5)))); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 907749d1..e69844fa 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -88,6 +88,7 @@ using testing::Matcher; using testing::MatcherCast; using testing::MatcherInterface; using testing::Matches; +using testing::MatchResultListener; using testing::NanSensitiveDoubleEq; using testing::NanSensitiveFloatEq; using testing::Ne; @@ -200,10 +201,39 @@ class EvenMatcherImpl : public MatcherInterface { // two methods is optional. }; -TEST(MatcherInterfaceTest, CanBeImplemented) { +TEST(MatcherInterfaceTest, CanBeImplementedUsingDeprecatedAPI) { EvenMatcherImpl m; } +// Tests implementing a monomorphic matcher using MatchAndExplain(). + +class NewEvenMatcherImpl : public MatcherInterface { + public: + virtual bool MatchAndExplain(int x, MatchResultListener* listener) const { + const bool match = x % 2 == 0; + // Verifies that we can stream to a listener directly. + *listener << "value % " << 2; + if (listener->stream() != NULL) { + // Verifies that we can stream to a listener's underlying stream + // too. + *listener->stream() << " == " << (x % 2); + } + return match; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is an even number"; + } +}; + +TEST(MatcherInterfaceTest, CanBeImplementedUsingNewAPI) { + Matcher m = MakeMatcher(new NewEvenMatcherImpl); + EXPECT_TRUE(m.Matches(2)); + EXPECT_FALSE(m.Matches(3)); + EXPECT_EQ("value % 2 == 0", Explain(m, 2)); + EXPECT_EQ("value % 2 == 1", Explain(m, 3)); +} + // Tests default-constructing a matcher. TEST(MatcherTest, CanBeDefaultConstructed) { Matcher m; @@ -252,6 +282,18 @@ TEST(MatcherTest, CanDescribeItself) { Describe(Matcher(new EvenMatcherImpl))); } +// Tests Matcher::MatchAndExplain(). +TEST(MatcherTest, MatchAndExplain) { + Matcher m = GreaterThan(0); + ::testing::internal::StringMatchResultListener listener1; + EXPECT_TRUE(m.MatchAndExplain(42, &listener1)); + EXPECT_EQ("is 42 more than 0", listener1.str()); + + ::testing::internal::StringMatchResultListener listener2; + EXPECT_FALSE(m.MatchAndExplain(-9, &listener2)); + EXPECT_EQ("is 9 less than 0", listener2.str()); +} + // Tests that a C-string literal can be implicitly converted to a // Matcher or Matcher. TEST(StringMatcherTest, CanBeImplicitlyConstructedFromCStringLiteral) { @@ -284,8 +326,8 @@ TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) { Matcher m = MakeMatcher(dummy_impl); } -// Tests that MakePolymorphicMatcher() constructs a polymorphic -// matcher from its implementation. +// Tests that MakePolymorphicMatcher() can construct a polymorphic +// matcher from its implementation using the old API. const int bar = 1; class ReferencesBarOrIsZeroImpl { public: @@ -308,7 +350,7 @@ PolymorphicMatcher ReferencesBarOrIsZero() { return MakePolymorphicMatcher(ReferencesBarOrIsZeroImpl()); } -TEST(MakePolymorphicMatcherTest, ConstructsMatcherFromImpl) { +TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) { // Using a polymorphic matcher to match a reference type. Matcher m1 = ReferencesBarOrIsZero(); EXPECT_TRUE(m1.Matches(0)); @@ -324,6 +366,58 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherFromImpl) { EXPECT_EQ("bar or zero", Describe(m2)); } +// Tests implementing a polymorphic matcher using MatchAndExplain(). + +class PolymorphicIsEvenImpl { + public: + void DescribeTo(::std::ostream* os) const { *os << "is even"; } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "is odd"; + } +}; + +template +bool MatchAndExplain(const PolymorphicIsEvenImpl& /* impl */, + T x, MatchResultListener* listener) { + // Verifies that we can stream to the listener directly. + *listener << "% " << 2; + if (listener->stream() != NULL) { + // Verifies that we can stream to the listener's underlying stream + // too. + *listener->stream() << " == " << (x % 2); + } + return (x % 2) == 0; +} + +PolymorphicMatcher PolymorphicIsEven() { + return MakePolymorphicMatcher(PolymorphicIsEvenImpl()); +} + +TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingNewAPI) { + // Using PolymorphicIsEven() as a Matcher. + const Matcher m1 = PolymorphicIsEven(); + EXPECT_TRUE(m1.Matches(42)); + EXPECT_FALSE(m1.Matches(43)); + EXPECT_EQ("is even", Describe(m1)); + + const Matcher not_m1 = Not(m1); + EXPECT_EQ("is odd", Describe(not_m1)); + + EXPECT_EQ("% 2 == 0", Explain(m1, 42)); + + // Using PolymorphicIsEven() as a Matcher. + const Matcher m2 = PolymorphicIsEven(); + EXPECT_TRUE(m2.Matches('\x42')); + EXPECT_FALSE(m2.Matches('\x43')); + EXPECT_EQ("is even", Describe(m2)); + + const Matcher not_m2 = Not(m2); + EXPECT_EQ("is odd", Describe(not_m2)); + + EXPECT_EQ("% 2 == 0", Explain(m2, '\x42')); +} + // Tests that MatcherCast(m) works when m is a polymorphic matcher. TEST(MatcherCastTest, FromPolymorphicMatcher) { Matcher m = MatcherCast(Eq(5)); @@ -1050,21 +1144,26 @@ TEST(PairTest, CanDescribeSelf) { } TEST(PairTest, CanExplainMatchResultTo) { - const Matcher > m0 = Pair(0, 0); - EXPECT_EQ("", Explain(m0, std::make_pair(25, 42))); + // If neither field matches, Pair() should explain about the first + // field. + const Matcher > m = Pair(GreaterThan(0), GreaterThan(0)); + EXPECT_EQ("the first field is 1 less than 0", + Explain(m, std::make_pair(-1, -2))); - const Matcher > m1 = Pair(GreaterThan(0), 0); - EXPECT_EQ("the first field is 25 more than 0", - Explain(m1, std::make_pair(25, 42))); + // If the first field matches but the second doesn't, Pair() should + // explain about the second field. + EXPECT_EQ("the second field is 2 less than 0", + Explain(m, std::make_pair(1, -2))); - const Matcher > m2 = Pair(0, GreaterThan(0)); - EXPECT_EQ("the second field is 42 more than 0", - Explain(m2, std::make_pair(25, 42))); + // If the first field doesn't match but the second does, Pair() + // should explain about the first field. + EXPECT_EQ("the first field is 1 less than 0", + Explain(m, std::make_pair(-1, 2))); - const Matcher > m3 = Pair(GreaterThan(0), GreaterThan(0)); - EXPECT_EQ("the first field is 25 more than 0" - ", and the second field is 42 more than 0", - Explain(m3, std::make_pair(25, 42))); + // If both fields match, Pair() should explain about them both. + EXPECT_EQ("the first field is 1 more than 0" + ", and the second field is 2 more than 0", + Explain(m, std::make_pair(1, 2))); } TEST(PairTest, MatchesCorrectly) { @@ -3335,6 +3434,16 @@ TEST(ValidateMatcherDescriptionTest, ElementsAre()); } +// The MATCHER*() 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 + // We use MATCHER_P3() to define a matcher for testing // ValidateMatcherDescription(); otherwise we'll end up with much // plumbing code. This is not circular as @@ -3345,6 +3454,10 @@ MATCHER_P3(EqInterpolation, start, end, index, "equals Interpolation%(*)s") { arg.param_index == index; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + TEST(ValidateMatcherDescriptionTest, AcceptsPercentInterpolation) { const char* params[] = { "foo", NULL }; const char* const desc = "one %%"; -- cgit v1.2.3 From e122e457a6e890faac399c1f86d87cc8d3177ac2 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 12 Jan 2010 09:03:52 +0000 Subject: Converts more matchers to the new API; fixes MatchAndExplain() for polymorphic matchers to allow non-const reference arguments. --- include/gmock/gmock-matchers.h | 139 +++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 46 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index b1689d6e..09e469e5 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -265,10 +265,11 @@ inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, } // The default implementation of MatchAndExplain() for polymorphic -// matchers. +// matchers. The type of argument x cannot be const T&, in case +// impl.Matches() takes a non-const reference. template inline bool MatchAndExplain(const PolymorphicMatcherImpl& impl, - const T& x, + T& x, MatchResultListener* listener) { const bool match = impl.Matches(x); @@ -789,6 +790,12 @@ class IsNullMatcher { } }; +template +bool MatchAndExplain(const IsNullMatcher& impl, Pointer& p, + MatchResultListener* /* listener */) { + return impl.Matches(p); +} + // Implements the polymorphic NotNull() matcher, which matches any raw or smart // pointer that is not NULL. class NotNullMatcher { @@ -802,6 +809,12 @@ class NotNullMatcher { } }; +template +bool MatchAndExplain(const NotNullMatcher& impl, Pointer& p, + MatchResultListener* /* listener */) { + return impl.Matches(p); +} + // 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'. @@ -964,6 +977,12 @@ class StrEqualityMatcher { GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher); }; +template +bool MatchAndExplain(const StrEqualityMatcher& impl, T& s, + MatchResultListener* /* listener */) { + return impl.Matches(s); +} + // Implements the polymorphic HasSubstr(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. @@ -1003,6 +1022,12 @@ class HasSubstrMatcher { GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher); }; +template +bool MatchAndExplain(const HasSubstrMatcher& impl, T& s, + MatchResultListener* /* listener */) { + return impl.Matches(s); +} + // Implements the polymorphic StartsWith(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. @@ -1042,6 +1067,12 @@ class StartsWithMatcher { GTEST_DISALLOW_ASSIGN_(StartsWithMatcher); }; +template +bool MatchAndExplain(const StartsWithMatcher& impl, T& s, + MatchResultListener* /* listener */) { + return impl.Matches(s); +} + // Implements the polymorphic EndsWith(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. @@ -1080,6 +1111,12 @@ class EndsWithMatcher { GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); }; +template +bool MatchAndExplain(const EndsWithMatcher& impl, T& s, + MatchResultListener* /* listener */) { + return impl.Matches(s); +} + #if GMOCK_HAS_REGEX // Implements polymorphic matchers MatchesRegex(regex) and @@ -1122,6 +1159,12 @@ class MatchesRegexMatcher { GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); }; +template +bool MatchAndExplain(const MatchesRegexMatcher& impl, T& s, + MatchResultListener* /* listener */) { + return impl.Matches(s); +} + #endif // GMOCK_HAS_REGEX // Implements a matcher that compares the two fields of a 2-tuple @@ -1425,6 +1468,12 @@ class TrulyMatcher { GTEST_DISALLOW_ASSIGN_(TrulyMatcher); }; +template +bool MatchAndExplain(const TrulyMatcher& impl, T& x, + MatchResultListener* /* listener */) { + return impl.Matches(x); +} + // Used for implementing Matches(matcher), which turns a matcher into // a predicate. template @@ -1733,7 +1782,7 @@ class FieldMatcher { template bool MatchAndExplain(const FieldMatcher& matcher, - const T& value, MatchResultListener* listener) { + T& value, MatchResultListener* listener) { return matcher.MatchAndExplain( typename ::testing::internal::is_pointer::type(), value, listener); } @@ -1798,7 +1847,7 @@ class PropertyMatcher { template bool MatchAndExplain(const PropertyMatcher& matcher, - const T& value, MatchResultListener* listener) { + T& value, MatchResultListener* listener) { return matcher.MatchAndExplain( typename ::testing::internal::is_pointer::type(), value, listener); } @@ -1933,15 +1982,6 @@ class ContainerEqMatcher { GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))>(); } - template - bool Matches(const LhsContainer& lhs) const { - // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug - // that causes LhsContainer to be a const type sometimes. - typedef internal::StlContainerView - LhsView; - StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); - return lhs_stl_container == rhs_; - } void DescribeTo(::std::ostream* os) const { *os << "equals "; UniversalPrinter::Print(rhs_, os); @@ -1952,48 +1992,55 @@ class ContainerEqMatcher { } template - void ExplainMatchResultTo(const LhsContainer& lhs, - ::std::ostream* os) const { + bool MatchAndExplain(const LhsContainer& lhs, + MatchResultListener* listener) const { // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug // that causes LhsContainer to be a const type sometimes. typedef internal::StlContainerView LhsView; typedef typename LhsView::type LhsStlContainer; StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + if (lhs_stl_container == rhs_) + return true; - // Something is different. Check for missing values first. - bool printed_header = false; - for (typename LhsStlContainer::const_iterator it = - lhs_stl_container.begin(); - it != lhs_stl_container.end(); ++it) { - if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) == - rhs_.end()) { - if (printed_header) { - *os << ", "; - } else { - *os << "Only in actual: "; - printed_header = true; + ::std::ostream* const os = listener->stream(); + if (os != NULL) { + // Something is different. Check for missing values first. + bool printed_header = false; + for (typename LhsStlContainer::const_iterator it = + lhs_stl_container.begin(); + it != lhs_stl_container.end(); ++it) { + if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) == + rhs_.end()) { + if (printed_header) { + *os << ", "; + } else { + *os << "Only in actual: "; + printed_header = true; + } + UniversalPrinter::Print(*it, os); } - UniversalPrinter::Print(*it, os); } - } - // Now check for extra values. - bool printed_header2 = false; - for (typename StlContainer::const_iterator it = rhs_.begin(); - it != rhs_.end(); ++it) { - if (internal::ArrayAwareFind( - lhs_stl_container.begin(), lhs_stl_container.end(), *it) == - lhs_stl_container.end()) { - if (printed_header2) { - *os << ", "; - } else { - *os << (printed_header ? "; not" : "Not") << " in actual: "; - printed_header2 = true; + // Now check for extra values. + bool printed_header2 = false; + for (typename StlContainer::const_iterator it = rhs_.begin(); + it != rhs_.end(); ++it) { + if (internal::ArrayAwareFind( + lhs_stl_container.begin(), lhs_stl_container.end(), *it) == + lhs_stl_container.end()) { + if (printed_header2) { + *os << ", "; + } else { + *os << (printed_header ? "; not" : "Not") << " in actual: "; + printed_header2 = true; + } + UniversalPrinter::Print(*it, os); } - UniversalPrinter::Print(*it, os); } } + + return false; } private: @@ -2003,10 +2050,10 @@ class ContainerEqMatcher { }; template -void ExplainMatchResultTo(const ContainerEqMatcher& matcher, - const LhsContainer& lhs, - ::std::ostream* os) { - matcher.ExplainMatchResultTo(lhs, os); +bool MatchAndExplain(const ContainerEqMatcher& matcher, + LhsContainer& lhs, + MatchResultListener* listener) { + return matcher.MatchAndExplain(lhs, listener); } // Implements Contains(element_matcher) for the given argument type Container. -- cgit v1.2.3 From 6953a725fc2151eff18078f8315d92811cd4d90e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 13 Jan 2010 05:15:07 +0000 Subject: Allows Field() and Property() to work when the matcher argument is a pointer passed by reference. --- include/gmock/gmock-matchers.h | 9 ++++++--- test/gmock-matchers_test.cc | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 09e469e5..f6e877d2 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1784,7 +1784,8 @@ template bool MatchAndExplain(const FieldMatcher& matcher, T& value, MatchResultListener* listener) { return matcher.MatchAndExplain( - typename ::testing::internal::is_pointer::type(), value, listener); + typename ::testing::internal::is_pointer::type(), + value, listener); } // Implements the Property() matcher for matching a property @@ -1849,7 +1850,8 @@ template bool MatchAndExplain(const PropertyMatcher& matcher, T& value, MatchResultListener* listener) { return matcher.MatchAndExplain( - typename ::testing::internal::is_pointer::type(), value, listener); + typename ::testing::internal::is_pointer::type(), + value, listener); } // Type traits specifying various features of different functors for ResultOf. @@ -2018,7 +2020,8 @@ class ContainerEqMatcher { *os << "Only in actual: "; printed_header = true; } - UniversalPrinter::Print(*it, os); + UniversalPrinter:: + Print(*it, os); } } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index e69844fa..e10b7275 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -2648,6 +2648,16 @@ TEST(FieldForPointerTest, WorksForPointerToNonConst) { EXPECT_FALSE(m.Matches(&a)); } +// Tests that Field() works when the argument is a reference to a const pointer. +TEST(FieldForPointerTest, WorksForReferenceToConstPointer) { + Matcher m = Field(&AStruct::x, Ge(0)); + + AStruct a; + EXPECT_TRUE(m.Matches(&a)); + a.x = -1; + EXPECT_FALSE(m.Matches(&a)); +} + // Tests that Field() does not match the NULL pointer. TEST(FieldForPointerTest, DoesNotMatchNull) { Matcher m = Field(&AStruct::x, _); @@ -2846,6 +2856,19 @@ TEST(PropertyForPointerTest, WorksForPointerToNonConst) { EXPECT_FALSE(m.Matches(&a)); } +// Tests that Property() works when the argument is a reference to a +// const pointer. +TEST(PropertyForPointerTest, WorksForReferenceToConstPointer) { + Matcher m = Property(&AClass::s, StartsWith("hi")); + + AClass a; + a.set_s("hill"); + EXPECT_TRUE(m.Matches(&a)); + + a.set_s("hole"); + EXPECT_FALSE(m.Matches(&a)); +} + // Tests that Property() does not match the NULL pointer. TEST(PropertyForPointerTest, WorksForReferenceToNonConstProperty) { Matcher m = Property(&AClass::x, _); -- cgit v1.2.3 From d14aaed74b2a8a1222d60d8fa3afcfc93a21c321 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 Jan 2010 05:36:32 +0000 Subject: Enables regex matchers on all platforms. --- include/gmock/gmock-matchers.h | 8 -------- include/gmock/internal/gmock-port.h | 18 ------------------ test/gmock-matchers_test.cc | 13 ++++--------- test/gmock-spec-builders_test.cc | 27 ++++++++++++++------------- test/gmock_link_test.h | 4 ---- 5 files changed, 18 insertions(+), 52 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index f6e877d2..9c457730 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1117,8 +1117,6 @@ bool MatchAndExplain(const EndsWithMatcher& impl, T& s, return impl.Matches(s); } -#if GMOCK_HAS_REGEX - // 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. @@ -1165,8 +1163,6 @@ bool MatchAndExplain(const MatchesRegexMatcher& impl, T& s, return impl.Matches(s); } -#endif // GMOCK_HAS_REGEX - // 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. @@ -2718,8 +2714,6 @@ inline PolymorphicMatcher > suffix)); } -#ifdef GMOCK_HAS_REGEX - // Matches a string that fully matches regular expression 'regex'. // The matcher takes ownership of 'regex'. inline PolymorphicMatcher MatchesRegex( @@ -2742,8 +2736,6 @@ inline PolymorphicMatcher ContainsRegex( return ContainsRegex(new internal::RE(regex)); } -#endif // GMOCK_HAS_REGEX - #if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING // Wide string matchers. diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 27b67a5c..30115f23 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -52,26 +52,8 @@ #if GTEST_OS_LINUX -// On some platforms, needs someone to define size_t, and -// won't compile otherwise. We can #include it here as we already -// included , which is guaranteed to define size_t through -// . -#include // NOLINT - -// Defines this iff Google Mock uses the enhanced POSIX regular -// expression syntax. This is public as it affects how a user uses -// regular expression matchers. -#define GMOCK_USES_POSIX_RE 1 - #endif // GTEST_OS_LINUX -#if defined(GMOCK_USES_PCRE) || defined(GMOCK_USES_POSIX_RE) -// Defines this iff regular expression matchers are supported. This -// is public as it tells a user whether he can use regular expression -// matchers. -#define GMOCK_HAS_REGEX 1 -#endif // defined(GMOCK_USES_PCRE) || defined(GMOCK_USES_POSIX_RE) - namespace testing { namespace internal { diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index e10b7275..555cc228 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -126,11 +126,9 @@ using testing::internal::linked_ptr; using testing::internal::scoped_ptr; using testing::internal::string; -#ifdef GMOCK_HAS_REGEX using testing::ContainsRegex; using testing::MatchesRegex; using testing::internal::RE; -#endif // GMOCK_HAS_REGEX // For testing ExplainMatchResultTo(). class GreaterThanMatcher : public MatcherInterface { @@ -1249,8 +1247,6 @@ TEST(EndsWithTest, CanDescribeSelf) { EXPECT_EQ("ends with \"Hi\"", Describe(m)); } -#ifdef GMOCK_HAS_REGEX - // Tests MatchesRegex(). TEST(MatchesRegexTest, MatchesStringMatchingGivenRegex) { @@ -1269,8 +1265,8 @@ TEST(MatchesRegexTest, CanDescribeSelf) { Matcher m1 = MatchesRegex(string("Hi.*")); EXPECT_EQ("matches regular expression \"Hi.*\"", Describe(m1)); - Matcher m2 = MatchesRegex(new RE("[a-z].*")); - EXPECT_EQ("matches regular expression \"[a-z].*\"", Describe(m2)); + Matcher m2 = MatchesRegex(new RE("a.*")); + EXPECT_EQ("matches regular expression \"a.*\"", Describe(m2)); } // Tests ContainsRegex(). @@ -1291,10 +1287,9 @@ TEST(ContainsRegexTest, CanDescribeSelf) { Matcher m1 = ContainsRegex("Hi.*"); EXPECT_EQ("contains regular expression \"Hi.*\"", Describe(m1)); - Matcher m2 = ContainsRegex(new RE("[a-z].*")); - EXPECT_EQ("contains regular expression \"[a-z].*\"", Describe(m2)); + Matcher m2 = ContainsRegex(new RE("a.*")); + EXPECT_EQ("contains regular expression \"a.*\"", Describe(m2)); } -#endif // GMOCK_HAS_REGEX // Tests for wide strings. #if GTEST_HAS_STD_WSTRING diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index c1e77381..3a7b4189 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -68,6 +68,7 @@ using testing::AtMost; using testing::Between; using testing::Cardinality; using testing::CardinalityInterface; +using testing::ContainsRegex; using testing::Const; using testing::DoAll; using testing::DoDefault; @@ -978,8 +979,6 @@ TEST(UnexpectedCallTest, UnmatchedArguments) { b.DoB(1); } -#ifdef GMOCK_HAS_REGEX - // Tests that Google Mock explains that an expectation with // unsatisfied pre-requisites doesn't match the call. TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { @@ -1010,31 +1009,33 @@ TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { // Verifies that the failure message contains the two unsatisfied // pre-requisites but not the satisfied one. - const char* const pattern = -#if GMOCK_USES_PCRE +#if GTEST_USES_PCRE + EXPECT_THAT(r.message(), ContainsRegex( // PCRE has trouble using (.|\n) to match any character, but // supports the (?s) prefix for using . to match any character. "(?s)the following immediate pre-requisites are not satisfied:\n" ".*: pre-requisite #0\n" - ".*: pre-requisite #1"; -#else + ".*: pre-requisite #1")); +#elif GTEST_USES_POSIX_RE + EXPECT_THAT(r.message(), ContainsRegex( // POSIX RE doesn't understand the (?s) prefix, but has no trouble // with (.|\n). "the following immediate pre-requisites are not satisfied:\n" "(.|\n)*: pre-requisite #0\n" - "(.|\n)*: pre-requisite #1"; -#endif // GMOCK_USES_PCRE + "(.|\n)*: pre-requisite #1")); +#else + // We can only use Google Test's own simple regex. + EXPECT_THAT(r.message(), ContainsRegex( + "the following immediate pre-requisites are not satisfied:")); + EXPECT_THAT(r.message(), ContainsRegex(": pre-requisite #0")); + EXPECT_THAT(r.message(), ContainsRegex(": pre-requisite #1")); +#endif // GTEST_USES_PCRE - EXPECT_TRUE( - ::testing::internal::RE::PartialMatch(r.message(), pattern)) - << " where the message is " << r.message(); b.DoB(1); b.DoB(3); b.DoB(4); } -#endif // GMOCK_HAS_REGEX - TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) { MockA a; // TODO(wan@google.com): We should really verify the output message, diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index d9635907..aa9aab3a 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -185,10 +185,8 @@ using testing::SetErrnoAndReturn; using testing::Throw; #endif -#if GMOCK_HAS_REGEX using testing::ContainsRegex; using testing::MatchesRegex; -#endif class Interface { public: @@ -547,7 +545,6 @@ TEST(LinkTest, TestMatchersFloatingPoint) { .WillByDefault(Return()); } -#if GMOCK_HAS_REGEX // Tests the linkage of the ContainsRegex matcher. TEST(LinkTest, TestMatcherContainsRegex) { Mock mock; @@ -561,7 +558,6 @@ TEST(LinkTest, TestMatcherMatchesRegex) { ON_CALL(mock, VoidFromString(MatchesRegex(".*"))).WillByDefault(Return()); } -#endif // GMOCK_HAS_REGEX // Tests the linkage of the StartsWith, EndsWith, and HasSubstr matchers. TEST(LinkTest, TestMatchersSubstrings) { -- cgit v1.2.3 From 99643d2d1fb3e632955b34c453ac6f731285e379 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sun, 17 Jan 2010 08:42:48 +0000 Subject: Removes 'make install' instructions from README. --- README | 66 ------------------------------------------------------------------ 1 file changed, 66 deletions(-) diff --git a/README b/README index 9cbda5d5..4b3efd82 100644 --- a/README +++ b/README @@ -177,78 +177,12 @@ directory otherwise. ${SRCDIR}/configure # Standard GNU configure script, --help for more info -The default behavior of the configure script with respect to locating and using -Google Test is to first search for a 'gtest-config' in the system path, and -lacking this, build an internal copy of Google Test. You may optionally specify -a custom Google Test you wish to build Google Mock against, provided it is -a new enough version. - - # Configure against an installation in '/opt' with '/opt/bin/gtest-config'. - ${SRCDIR}/configure --with-gtest=/opt - -This can also be used to specify a Google Test which hasn't yet been installed. -However, it must have been configured and built as described in the Google Test -README before you configure Google Mock. To enable this feature, simply pass -the directory where you configured and built Google Test (which is not -necessarily its source directory) to Google Mock's configure script. - - # Configure against a build of Google Test in an arbitrary directory. - ${SRCDIR}/configure --with-gtest=../../my_gtest_build - -Finally, if you have a version of Google Test installed but for some reason -wish to forcibly prevent it from being used, we provide a special option. -Typically this is not needed as we fall back to the internal Google Test -packaged with Google Mock if an installed version is either unavailable or too -old to build Google Mock. When using the internally packaged Google Test, the -user does *not* need to configure or build it, that is automatically handled by -Google Mock's build system. - - # Force the use of the internally packaged Google Test, despite - # 'gtest-config' being in your PATH. - ${SRCDIR}/configure --disable-external-gtest - 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 -Other programs will only be able to use Google Mock's functionality if you -install it in a location which they can access, in Linux this is typically -under '/usr/local'. The following command will install all of the Google Mock -libraries, public headers, and utilities necessary for other programs and -libraries to leverage it. Note that if Google Mock was unable to find an -external Google Test to build against, it will also install the internally -packaged Google Test in order to allow the installed Google Mock to function -properly. This Google Test install will be fully functional, and if installed -will also be uninstalled by uninstalling Google Mock. - - sudo make install # Not necessary, but allows use by other programs - -Should you need to remove Google Mock from your system after having installed -it, run the following command, and it will back out its changes. However, note -carefully that you must run this command on the *same* Google Mock build that -you ran the install from, or the results are not predictable. If you install -Google Mock on your system, and are working from a VCS checkout, make sure you -run this *before* updating your checkout of the source in order to uninstall -the same version which you installed. - - sudo make uninstall # Must be run against the exact same build as "install" - -Your project can build against Google Mock and Google Test simply by leveraging -the 'gmock-config' script. This script can be invoked directly out of the -'scripts' subdirectory of the build tree, and it will be installed in the -binary directory specified during the 'configure'. Here are some examples of -its use, see 'gmock-config --help' for more detailed information. - - gmock-config --min-version=1.0 || echo "Insufficient Google Mock version." - - g++ $(gmock-config --cppflags --cxxflags) -o foo.o -c foo.cpp - g++ $(gmock-config --ldflags --libs) -o foo foo.o - - # When using a built but not installed Google Mock: - g++ $(../../my_gmock_build/scripts/gmock-config ...) ... - 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. -- cgit v1.2.3 From db22c227826b82e1ad05d6c47facfef73c99e057 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 28 Jan 2010 21:52:29 +0000 Subject: BREAKING CHANGE: drops the old matcher API. See http://code.google.com/p/googlemock/wiki/FrequentlyAskedQuestions for details. --- include/gmock/gmock-matchers.h | 280 +++++++++------------------------- test/gmock-generated-matchers_test.cc | 14 +- test/gmock-matchers_test.cc | 61 ++++---- 3 files changed, 114 insertions(+), 241 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 9c457730..ae7e131d 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -108,10 +108,7 @@ class MatcherInterface { // Returns true iff the matcher matches x; also explains the match // result to 'listener'. // - // You should override this method when defining a new matcher. For - // backward compatibility, we provide a default implementation that - // just forwards to the old, deprecated matcher API (Matches() and - // ExplainMatchResultTo()). + // 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 @@ -119,19 +116,7 @@ class MatcherInterface { // 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 { - const bool match = Matches(x); - if (listener->stream() != NULL) { - ExplainMatchResultTo(x, listener->stream()); - } - return match; - } - - // DEPRECATED. This method will be removed. Override - // MatchAndExplain() instead. - // - // Returns true iff the matcher matches x. - virtual bool Matches(T /* x */) const { return false; } + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; @@ -147,18 +132,6 @@ class MatcherInterface { DescribeTo(os); *os << ")"; } - - // DEPRECATED. This method will be removed. Override - // MatchAndExplain() instead. - // - // Explains why x matches, or doesn't match, the matcher. Override - // this to provide any additional information that helps a user - // understand the match result. - virtual void ExplainMatchResultTo(T /* x */, ::std::ostream* /* os */) const { - // By default, nothing more needs to be explained, as Google Mock - // has already printed the value of x when this function is - // called. - } }; namespace internal { @@ -254,38 +227,6 @@ class MatcherBase { ::testing::internal::linked_ptr > impl_; }; -// The default implementation of ExplainMatchResultTo() for -// polymorphic matchers. -template -inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, - const T& /* x */, - ::std::ostream* /* os */) { - // By default, nothing more needs to be said, as Google Mock already - // prints the value of x elsewhere. -} - -// The default implementation of MatchAndExplain() for polymorphic -// matchers. The type of argument x cannot be const T&, in case -// impl.Matches() takes a non-const reference. -template -inline bool MatchAndExplain(const PolymorphicMatcherImpl& impl, - T& x, - MatchResultListener* listener) { - const bool match = impl.Matches(x); - - ::std::ostream* const os = listener->stream(); - if (os != NULL) { - using ::testing::internal::ExplainMatchResultTo; - // When resolving the following call, both - // ::testing::internal::ExplainMatchResultTo() and - // foo::ExplainMatchResultTo() are considered, where foo is the - // namespace where class PolymorphicMatcherImpl is defined. - ExplainMatchResultTo(impl, x, os); - } - - return match; -} - } // namespace internal // A Matcher is a copyable and IMMUTABLE (except by assignment) @@ -350,29 +291,12 @@ class Matcher // 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 in the old, deprecated way, a user -// first provides an Impl class that has a Matches() method, a -// DescribeTo() method, and a DescribeNegationTo() method. The -// Matches() method is usually a method template (such that it works -// with multiple types). Then the user creates the polymorphic -// matcher using MakePolymorphicMatcher(). To provide additional -// explanation to the match result, define a FREE function (or -// function template) -// -// void ExplainMatchResultTo(const Impl& matcher, const Value& value, -// ::std::ostream* os); -// -// in the SAME NAME SPACE where Impl is defined. -// -// The new, recommended way to define a polymorphic matcher is to -// provide an Impl class that has a DescribeTo() method and a -// DescribeNegationTo() method, and define a FREE function (or -// function template) +// 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 Impl& matcher, const Value& value, -// MatchResultListener* listener); -// -// in the SAME NAME SPACE where Impl is defined. +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; // // See the definition of NotNull() for a complete example. template @@ -408,14 +332,7 @@ class PolymorphicMatcher { } virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { - // C++ uses Argument-Dependent Look-up (aka Koenig Look-up) to - // resolve the call to MatchAndExplain() here. This means that - // if there's a MatchAndExplain() function defined in the name - // space where class Impl is defined, it will be picked by the - // compiler as the better match. Otherwise the default - // implementation of it in ::testing::internal will be picked. - using ::testing::internal::MatchAndExplain; - return MatchAndExplain(impl_, x, listener); + return impl_.MatchAndExplain(x, listener); } private: @@ -578,7 +495,7 @@ class TuplePrefix { // 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 ExplainMatchResultTo() method handles the case when + // matcher's MatchAndExplain() method handles the case when // the address is interesting. internal::UniversalPrinter:: Print(value, os); @@ -782,7 +699,10 @@ GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "not equal to"); class IsNullMatcher { public: template - bool Matches(const Pointer& p) const { return GetRawPointer(p) == NULL; } + bool MatchAndExplain(const Pointer& p, + MatchResultListener* /* listener */) const { + return GetRawPointer(p) == NULL; + } void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } void DescribeNegationTo(::std::ostream* os) const { @@ -790,18 +710,15 @@ class IsNullMatcher { } }; -template -bool MatchAndExplain(const IsNullMatcher& impl, Pointer& p, - MatchResultListener* /* listener */) { - return impl.Matches(p); -} - // Implements the polymorphic NotNull() matcher, which matches any raw or smart // pointer that is not NULL. class NotNullMatcher { public: template - bool Matches(const Pointer& p) const { return GetRawPointer(p) != NULL; } + bool MatchAndExplain(const Pointer& p, + MatchResultListener* /* listener */) const { + return GetRawPointer(p) != NULL; + } void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } void DescribeNegationTo(::std::ostream* os) const { @@ -809,12 +726,6 @@ class NotNullMatcher { } }; -template -bool MatchAndExplain(const NotNullMatcher& impl, Pointer& p, - MatchResultListener* /* listener */) { - return impl.Matches(p); -} - // 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'. @@ -860,8 +771,8 @@ class RefMatcher { public: explicit Impl(Super& x) : object_(x) {} // NOLINT - // Matches() takes a Super& (as opposed to const Super&) in - // order to match the interface MatcherInterface. + // 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 << "is located @" << static_cast(&x); @@ -936,14 +847,16 @@ class StrEqualityMatcher { // When expect_eq_ is true, returns true iff s is equal to string_; // otherwise returns true iff s is not equal to string_. - bool Matches(ConstCharPointer s) const { + bool MatchAndExplain(ConstCharPointer s, + MatchResultListener* listener) const { if (s == NULL) { return !expect_eq_; } - return Matches(StringType(s)); + return MatchAndExplain(StringType(s), listener); } - bool Matches(const StringType& s) const { + bool MatchAndExplain(const StringType& s, + MatchResultListener* /* listener */) const { const bool eq = case_sensitive_ ? s == string_ : CaseInsensitiveStringEquals(s, string_); return expect_eq_ == eq; @@ -977,12 +890,6 @@ class StrEqualityMatcher { GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher); }; -template -bool MatchAndExplain(const StrEqualityMatcher& impl, T& s, - MatchResultListener* /* listener */) { - return impl.Matches(s); -} - // Implements the polymorphic HasSubstr(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. @@ -997,11 +904,13 @@ class HasSubstrMatcher { // These overloaded methods allow HasSubstr(substring) to be used as a // Matcher as long as T can be converted to string. Returns true // iff s contains substring_ as a substring. - bool Matches(ConstCharPointer s) const { - return s != NULL && Matches(StringType(s)); + bool MatchAndExplain(ConstCharPointer s, + MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); } - bool Matches(const StringType& s) const { + bool MatchAndExplain(const StringType& s, + MatchResultListener* /* listener */) const { return s.find(substring_) != StringType::npos; } @@ -1022,12 +931,6 @@ class HasSubstrMatcher { GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher); }; -template -bool MatchAndExplain(const HasSubstrMatcher& impl, T& s, - MatchResultListener* /* listener */) { - return impl.Matches(s); -} - // Implements the polymorphic StartsWith(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. @@ -1042,11 +945,13 @@ class StartsWithMatcher { // These overloaded methods allow StartsWith(prefix) to be used as a // Matcher as long as T can be converted to string. Returns true // iff s starts with prefix_. - bool Matches(ConstCharPointer s) const { - return s != NULL && Matches(StringType(s)); + bool MatchAndExplain(ConstCharPointer s, + MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); } - bool Matches(const StringType& s) const { + bool MatchAndExplain(const StringType& s, + MatchResultListener* /* listener */) const { return s.length() >= prefix_.length() && s.substr(0, prefix_.length()) == prefix_; } @@ -1067,12 +972,6 @@ class StartsWithMatcher { GTEST_DISALLOW_ASSIGN_(StartsWithMatcher); }; -template -bool MatchAndExplain(const StartsWithMatcher& impl, T& s, - MatchResultListener* /* listener */) { - return impl.Matches(s); -} - // Implements the polymorphic EndsWith(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. @@ -1086,11 +985,13 @@ class EndsWithMatcher { // These overloaded methods allow EndsWith(suffix) to be used as a // Matcher as long as T can be converted to string. Returns true // iff s ends with suffix_. - bool Matches(ConstCharPointer s) const { - return s != NULL && Matches(StringType(s)); + bool MatchAndExplain(ConstCharPointer s, + MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(StringType(s), listener); } - bool Matches(const StringType& s) const { + bool MatchAndExplain(const StringType& s, + MatchResultListener* /* listener */) const { return s.length() >= suffix_.length() && s.substr(s.length() - suffix_.length()) == suffix_; } @@ -1111,12 +1012,6 @@ class EndsWithMatcher { GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); }; -template -bool MatchAndExplain(const EndsWithMatcher& impl, T& s, - MatchResultListener* /* listener */) { - return impl.Matches(s); -} - // 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. @@ -1129,11 +1024,13 @@ class MatchesRegexMatcher { // a Matcher as long as T can be converted to string. Returns // true iff s matches regular expression regex. When full_match_ is // true, a full match is done; otherwise a partial match is done. - bool Matches(const char* s) const { - return s != NULL && Matches(internal::string(s)); + bool MatchAndExplain(const char* s, + MatchResultListener* listener) const { + return s != NULL && MatchAndExplain(internal::string(s), listener); } - bool Matches(const internal::string& s) const { + bool MatchAndExplain(const internal::string& s, + MatchResultListener* /* listener */) const { return full_match_ ? RE::FullMatch(s, *regex_) : RE::PartialMatch(s, *regex_); } @@ -1157,12 +1054,6 @@ class MatchesRegexMatcher { GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); }; -template -bool MatchAndExplain(const MatchesRegexMatcher& impl, T& s, - MatchResultListener* /* listener */) { - return impl.Matches(s); -} - // 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. @@ -1438,7 +1329,8 @@ class TrulyMatcher { // argument is passed by reference as the predicate may be // interested in the address of the argument. template - bool Matches(T& x) const { // NOLINT + bool MatchAndExplain(T& x, // NOLINT + MatchResultListener* /* listener */) const { #if GTEST_OS_WINDOWS // MSVC warns about converting a value into bool (warning 4800). #pragma warning(push) // Saves the current warning state. @@ -1464,12 +1356,6 @@ class TrulyMatcher { GTEST_DISALLOW_ASSIGN_(TrulyMatcher); }; -template -bool MatchAndExplain(const TrulyMatcher& impl, T& x, - MatchResultListener* /* listener */) { - return impl.Matches(x); -} - // Used for implementing Matches(matcher), which turns a matcher into // a predicate. template @@ -1744,11 +1630,20 @@ class FieldMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of MatchAndExplain() is needed to help + template + bool MatchAndExplain(const T& value, MatchResultListener* listener) const { + return MatchAndExplainImpl( + typename ::testing::internal:: + is_pointer::type(), + value, listener); + } + + private: + // The first argument of MatchAndExplainImpl() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Field() matcher is used to match a pointer. - bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, - MatchResultListener* listener) const { + bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { StringMatchResultListener inner_listener; const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener); const internal::string s = inner_listener.str(); @@ -1758,32 +1653,23 @@ class FieldMatcher { return match; } - bool MatchAndExplain(true_type /* is_pointer */, const Class* p, - MatchResultListener* listener) const { + bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { if (p == NULL) return false; // Since *p has a field, it must be a class/struct/union type and // thus cannot be a pointer. Therefore we pass false_type() as // the first argument. - return MatchAndExplain(false_type(), *p, listener); + return MatchAndExplainImpl(false_type(), *p, listener); } - private: const FieldType Class::*field_; const Matcher matcher_; GTEST_DISALLOW_ASSIGN_(FieldMatcher); }; -template -bool MatchAndExplain(const FieldMatcher& matcher, - T& value, MatchResultListener* listener) { - return matcher.MatchAndExplain( - typename ::testing::internal::is_pointer::type(), - value, listener); -} - // Implements the Property() matcher for matching a property // (i.e. return value of a getter method) of an object. template @@ -1809,11 +1695,20 @@ class PropertyMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of MatchAndExplain() is needed to help + template + bool MatchAndExplain(const T&value, MatchResultListener* listener) const { + return MatchAndExplainImpl( + typename ::testing::internal:: + is_pointer::type(), + value, listener); + } + + private: + // The first argument of MatchAndExplainImpl() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Property() matcher is used to match a pointer. - bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, - MatchResultListener* listener) const { + bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { StringMatchResultListener inner_listener; const bool match = matcher_.MatchAndExplain((obj.*property_)(), &inner_listener); @@ -1824,32 +1719,23 @@ class PropertyMatcher { return match; } - bool MatchAndExplain(true_type /* is_pointer */, const Class* p, - MatchResultListener* listener) const { + bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { if (p == NULL) return false; // Since *p has a property method, it must be a class/struct/union // type and thus cannot be a pointer. Therefore we pass // false_type() as the first argument. - return MatchAndExplain(false_type(), *p, listener); + return MatchAndExplainImpl(false_type(), *p, listener); } - private: PropertyType (Class::*property_)() const; const Matcher matcher_; GTEST_DISALLOW_ASSIGN_(PropertyMatcher); }; -template -bool MatchAndExplain(const PropertyMatcher& matcher, - T& value, MatchResultListener* listener) { - return matcher.MatchAndExplain( - typename ::testing::internal::is_pointer::type(), - value, listener); -} - // Type traits specifying various features of different functors for ResultOf. // The default template specifies features for functor objects. // Functor classes have to typedef argument_type and result_type @@ -1947,13 +1833,6 @@ class ResultOfMatcher { GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); }; -// Explains the result of matching a value against a functor matcher. -template -void ExplainMatchResultTo(const ResultOfMatcher& matcher, - T obj, ::std::ostream* os) { - matcher.ExplainMatchResultTo(obj, os); -} - // Implements an equality matcher for any STL-style container whose elements // support ==. This matcher is like Eq(), but its failure explanations provide // more detailed information that is useful when the container is used as a set. @@ -2048,13 +1927,6 @@ class ContainerEqMatcher { GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; -template -bool MatchAndExplain(const ContainerEqMatcher& matcher, - LhsContainer& lhs, - MatchResultListener* listener) { - return matcher.MatchAndExplain(lhs, listener); -} - // Implements Contains(element_matcher) for the given argument type Container. template class ContainsMatcherImpl : public MatcherInterface { diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 40c2367c..5e14c42a 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -68,6 +68,7 @@ using testing::Lt; using testing::MakeMatcher; using testing::Matcher; using testing::MatcherInterface; +using testing::MatchResultListener; using testing::Ne; using testing::Not; using testing::Pointee; @@ -217,21 +218,22 @@ class GreaterThanMatcher : public MatcherInterface { public: explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - virtual bool Matches(int lhs) const { return lhs > rhs_; } - virtual void DescribeTo(::std::ostream* os) const { *os << "is greater than " << rhs_; } - virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { + virtual bool MatchAndExplain(int lhs, + MatchResultListener* listener) const { const int diff = lhs - rhs_; if (diff > 0) { - *os << "is " << diff << " more than " << rhs_; + *listener << "is " << diff << " more than " << rhs_; } else if (diff == 0) { - *os << "is the same as " << rhs_; + *listener << "is the same as " << rhs_; } else { - *os << "is " << -diff << " less than " << rhs_; + *listener << "is " << -diff << " less than " << rhs_; } + + return lhs > rhs_; } private: diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 555cc228..b674cd8a 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -135,21 +135,22 @@ class GreaterThanMatcher : public MatcherInterface { public: explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - virtual bool Matches(int lhs) const { return lhs > rhs_; } - virtual void DescribeTo(::std::ostream* os) const { *os << "is greater than " << rhs_; } - virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { + virtual bool MatchAndExplain(int lhs, + MatchResultListener* listener) const { const int diff = lhs - rhs_; if (diff > 0) { - *os << "is " << diff << " more than " << rhs_; + *listener << "is " << diff << " more than " << rhs_; } else if (diff == 0) { - *os << "is the same as " << rhs_; + *listener << "is the same as " << rhs_; } else { - *os << "is " << -diff << " less than " << rhs_; + *listener << "is " << -diff << " less than " << rhs_; } + + return lhs > rhs_; } private: @@ -188,7 +189,10 @@ string Explain(const MatcherType& m, const Value& x) { // change. class EvenMatcherImpl : public MatcherInterface { public: - virtual bool Matches(int x) const { return x % 2 == 0; } + virtual bool MatchAndExplain(int x, + MatchResultListener* /* listener */) const { + return x % 2 == 0; + } virtual void DescribeTo(::std::ostream* os) const { *os << "is an even number"; @@ -330,7 +334,8 @@ const int bar = 1; class ReferencesBarOrIsZeroImpl { public: template - bool Matches(const T& x) const { + bool MatchAndExplain(const T& x, + MatchResultListener* /* listener */) const { const void* p = &x; return p == &bar || x == 0; } @@ -373,20 +378,19 @@ class PolymorphicIsEvenImpl { void DescribeNegationTo(::std::ostream* os) const { *os << "is odd"; } -}; -template -bool MatchAndExplain(const PolymorphicIsEvenImpl& /* impl */, - T x, MatchResultListener* listener) { - // Verifies that we can stream to the listener directly. - *listener << "% " << 2; - if (listener->stream() != NULL) { - // Verifies that we can stream to the listener's underlying stream - // too. - *listener->stream() << " == " << (x % 2); + template + bool MatchAndExplain(const T& x, MatchResultListener* listener) const { + // Verifies that we can stream to the listener directly. + *listener << "% " << 2; + if (listener->stream() != NULL) { + // Verifies that we can stream to the listener's underlying stream + // too. + *listener->stream() << " == " << (x % 2); + } + return (x % 2) == 0; } - return (x % 2) == 0; -} +}; PolymorphicMatcher PolymorphicIsEven() { return MakePolymorphicMatcher(PolymorphicIsEvenImpl()); @@ -2135,8 +2139,8 @@ TEST(MatcherAssertionTest, WorksForByRefArguments) { // ASSERT_THAT("hello", starts_with_he) fails to compile with Nokia's // Symbian compiler: it tries to compile // template class MatcherCastImpl { ... -// virtual bool Matches(T x) const { -// return source_matcher_.Matches(static_cast(x)); +// virtual bool MatchAndExplain(T x, ...) const { +// return source_matcher_.MatchAndExplain(static_cast(x), ...); // with U == string and T == const char* // With ASSERT_THAT("hello"...) changed to ASSERT_THAT(string("hello") ... ) // the compiler silently crashes with no output. @@ -3075,8 +3079,11 @@ class DivisibleByImpl { public: explicit DivisibleByImpl(int a_divider) : divider_(a_divider) {} + // For testing using ExplainMatchResultTo() with polymorphic matchers. template - bool Matches(const T& n) const { + bool MatchAndExplain(const T& n, MatchResultListener* listener) const { + *listener << "is " << (n % divider_) << " modulo " + << divider_; return (n % divider_) == 0; } @@ -3095,14 +3102,6 @@ class DivisibleByImpl { int divider_; }; -// For testing using ExplainMatchResultTo() with polymorphic matchers. -template -void ExplainMatchResultTo(const DivisibleByImpl& impl, const T& n, - ::std::ostream* os) { - *os << "is " << (n % impl.divider()) << " modulo " - << impl.divider(); -} - PolymorphicMatcher DivisibleBy(int n) { return MakePolymorphicMatcher(DivisibleByImpl(n)); } -- cgit v1.2.3 From 470df42bad6a78531f0ec51e43a194f3e26c4f4d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 2 Feb 2010 22:34:58 +0000 Subject: Enables tests depending on stdout capturing (by Vlad Losev). --- test/gmock-internal-utils_test.cc | 56 +++++++------- test/gmock-nice-strict_test.cc | 26 ++++--- test/gmock-spec-builders_test.cc | 159 ++++++++++++++++++++------------------ 3 files changed, 124 insertions(+), 117 deletions(-) diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 7dd83115..fc5d9e55 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -538,8 +538,7 @@ TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) { EXPECT_TRUE(LogIsVisible(WARNING)); } -// TODO(wan@google.com): find a way to re-enable these tests. -#if 0 +#if GTEST_HAS_STREAM_REDIRECTION_ // Tests the Log() function. @@ -549,16 +548,16 @@ void TestLogWithSeverity(const string& verbosity, LogSeverity severity, bool should_print) { const string old_flag = GMOCK_FLAG(verbose); GMOCK_FLAG(verbose) = verbosity; - CaptureTestStdout(); + CaptureStdout(); Log(severity, "Test log.\n", 0); if (should_print) { - EXPECT_PRED2(RE::FullMatch, - GetCapturedTestStdout(), - severity == WARNING ? - "\nGMOCK WARNING:\nTest log\\.\nStack trace:\n[\\s\\S]*" : - "\nTest log\\.\nStack trace:\n[\\s\\S]*"); + EXPECT_THAT(GetCapturedStdout().c_str(), + ContainsRegex( + severity == WARNING ? + "^\nGMOCK WARNING:\nTest log\\.\nStack trace:\n" : + "^\nTest log\\.\nStack trace:\n")); } else { - EXPECT_EQ("", GetCapturedTestStdout()); + EXPECT_STREQ("", GetCapturedStdout().c_str()); } GMOCK_FLAG(verbose) = old_flag; } @@ -567,18 +566,18 @@ void TestLogWithSeverity(const string& verbosity, LogSeverity severity, // Log() doesn't include the stack trace in the output. TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { GMOCK_FLAG(verbose) = kInfoVerbosity; - CaptureTestStdout(); + CaptureStdout(); Log(INFO, "Test log.\n", -1); - EXPECT_EQ("\nTest log.\n", GetCapturedTestStdout()); + EXPECT_STREQ("\nTest log.\n", GetCapturedStdout().c_str()); } // Tests that in opt mode, a positive stack_frames_to_skip argument is // treated as 0. TEST(LogTest, NoSkippingStackFrameInOptMode) { - CaptureTestStdout(); + CaptureStdout(); Log(WARNING, "Test log.\n", 100); - const string log = GetCapturedTestStdout(); -#ifdef NDEBUG + const String log = GetCapturedStdout(); +#if defined(NDEBUG) && GTEST_GOOGLE3_MODE_ // In opt mode, no stack frame should be skipped. EXPECT_THAT(log, ContainsRegex("\nGMOCK WARNING:\n" "Test log\\.\n" @@ -586,10 +585,10 @@ TEST(LogTest, NoSkippingStackFrameInOptMode) { ".+")); #else // In dbg mode, the stack frames should be skipped. - EXPECT_EQ("\nGMOCK WARNING:\n" - "Test log.\n" - "Stack trace:\n", log); -#endif // NDEBUG + EXPECT_STREQ("\nGMOCK WARNING:\n" + "Test log.\n" + "Stack trace:\n", log.c_str()); +#endif } // Tests that all logs are printed when the value of the @@ -620,7 +619,7 @@ TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsInvalid) { TestLogWithSeverity("invalid", WARNING, true); } -#endif // 0 +#endif // GTEST_HAS_STREAM_REDIRECTION_ TEST(TypeTraitsTest, true_type) { EXPECT_TRUE(true_type::value); @@ -657,18 +656,17 @@ TEST(TypeTraitsTest, remove_reference) { EXPECT_TRUE((type_equals::type>::value)); } -// TODO(wan@google.com): find a way to re-enable these tests. -#if 0 +#if GTEST_HAS_STREAM_REDIRECTION_ // Verifies that Log() behaves correctly for the given verbosity level // and log severity. -string GrabOutput(void(*logger)(), const char* verbosity) { +String GrabOutput(void(*logger)(), const char* verbosity) { const string saved_flag = GMOCK_FLAG(verbose); GMOCK_FLAG(verbose) = verbosity; - CaptureTestStdout(); + CaptureStdout(); logger(); GMOCK_FLAG(verbose) = saved_flag; - return GetCapturedTestStdout(); + return GetCapturedStdout(); } class DummyMock { @@ -692,13 +690,13 @@ TEST(ExpectCallTest, LogsWhenVerbosityIsInfo) { // Verifies that EXPECT_CALL doesn't log // if the --gmock_verbose flag is set to "warning". TEST(ExpectCallTest, DoesNotLogWhenVerbosityIsWarning) { - EXPECT_EQ("", GrabOutput(ExpectCallLogger, kWarningVerbosity)); + EXPECT_STREQ("", GrabOutput(ExpectCallLogger, kWarningVerbosity).c_str()); } // Verifies that EXPECT_CALL doesn't log // if the --gmock_verbose flag is set to "error". TEST(ExpectCallTest, DoesNotLogWhenVerbosityIsError) { - EXPECT_EQ("", GrabOutput(ExpectCallLogger, kErrorVerbosity)); + EXPECT_STREQ("", GrabOutput(ExpectCallLogger, kErrorVerbosity).c_str()); } void OnCallLogger() { @@ -715,13 +713,13 @@ TEST(OnCallTest, LogsWhenVerbosityIsInfo) { // Verifies that ON_CALL doesn't log // if the --gmock_verbose flag is set to "warning". TEST(OnCallTest, DoesNotLogWhenVerbosityIsWarning) { - EXPECT_EQ("", GrabOutput(OnCallLogger, kWarningVerbosity)); + EXPECT_STREQ("", GrabOutput(OnCallLogger, kWarningVerbosity).c_str()); } // Verifies that ON_CALL doesn't log if // the --gmock_verbose flag is set to "error". TEST(OnCallTest, DoesNotLogWhenVerbosityIsError) { - EXPECT_EQ("", GrabOutput(OnCallLogger, kErrorVerbosity)); + EXPECT_STREQ("", GrabOutput(OnCallLogger, kErrorVerbosity).c_str()); } void OnCallAnyArgumentLogger() { @@ -735,7 +733,7 @@ TEST(OnCallTest, LogsAnythingArgument) { HasSubstr("ON_CALL(mock, TestMethodArg(_)")); } -#endif // 0 +#endif // GTEST_HAS_STREAM_REDIRECTION_ // Tests ArrayEq(). diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 1d36e03e..f6f278e8 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -57,6 +57,11 @@ using testing::HasSubstr; using testing::NiceMock; using testing::StrictMock; +#if GTEST_HAS_STREAM_REDIRECTION_ +using testing::internal::CaptureStdout; +using testing::internal::GetCapturedStdout; +#endif // GTEST_HAS_STREAM_REDIRECTION_ + // Defines some mock classes needed by the tests. class Foo { @@ -102,17 +107,16 @@ class MockBar { GTEST_DISALLOW_COPY_AND_ASSIGN_(MockBar); }; -// TODO(wan@google.com): find a way to re-enable these tests. -#if 0 +#if GTEST_HAS_STREAM_REDIRECTION_ // Tests that a nice mock generates no warning for uninteresting calls. TEST(NiceMockTest, NoWarningForUninterestingCall) { NiceMock nice_foo; - CaptureTestStdout(); + CaptureStdout(); nice_foo.DoThis(); nice_foo.DoThat(true); - EXPECT_EQ("", GetCapturedTestStdout()); + EXPECT_STREQ("", GetCapturedStdout().c_str()); } // Tests that a nice mock generates no warning for uninteresting calls @@ -123,9 +127,9 @@ TEST(NiceMockTest, NoWarningForUninterestingCallAfterDeath) { ON_CALL(*nice_foo, DoThis()) .WillByDefault(Invoke(nice_foo, &MockFoo::Delete)); - CaptureTestStdout(); + CaptureStdout(); nice_foo->DoThis(); - EXPECT_EQ("", GetCapturedTestStdout()); + EXPECT_STREQ("", GetCapturedStdout().c_str()); } // Tests that a nice mock generates informational logs for @@ -134,18 +138,18 @@ TEST(NiceMockTest, InfoForUninterestingCall) { NiceMock nice_foo; GMOCK_FLAG(verbose) = "info"; - CaptureTestStdout(); + CaptureStdout(); nice_foo.DoThis(); - EXPECT_THAT(GetCapturedTestStdout(), + EXPECT_THAT(GetCapturedStdout(), HasSubstr("Uninteresting mock function call")); - CaptureTestStdout(); + CaptureStdout(); nice_foo.DoThat(true); - EXPECT_THAT(GetCapturedTestStdout(), + EXPECT_THAT(GetCapturedStdout(), HasSubstr("Uninteresting mock function call")); } -#endif // 0 +#endif // GTEST_HAS_STREAM_REDIRECTION_ // Tests that a nice mock allows expected calls. TEST(NiceMockTest, AllowsExpectedCall) { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 3a7b4189..e5fc2ec9 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -87,13 +87,20 @@ using testing::Mock; using testing::Ne; using testing::Return; using testing::Sequence; +using testing::internal::ExpectationTester; using testing::internal::g_gmock_mutex; using testing::internal::kErrorVerbosity; using testing::internal::kInfoVerbosity; using testing::internal::kWarningVerbosity; -using testing::internal::ExpectationTester; +using testing::internal::String; using testing::internal::string; +#if GTEST_HAS_STREAM_REDIRECTION_ +using testing::HasSubstr; +using testing::internal::CaptureStdout; +using testing::internal::GetCapturedStdout; +#endif // GTEST_HAS_STREAM_REDIRECTION_ + class Result {}; class MockA { @@ -511,13 +518,12 @@ TEST(ExpectCallSyntaxTest, DefaultCardinalityIsOnce) { }, "to be called once"); } -// TODO(wan@google.com): find a way to re-enable these tests. -#if 0 +#if GTEST_HAS_STREAM_REDIRECTION_ // Tests that Google Mock doesn't print a warning when the number of // WillOnce() is adequate. TEST(ExpectCallSyntaxTest, DoesNotWarnOnAdequateActionCount) { - CaptureTestStdout(); + CaptureStdout(); { MockB b; @@ -547,14 +553,13 @@ TEST(ExpectCallSyntaxTest, DoesNotWarnOnAdequateActionCount) { b.DoB(2); b.DoB(3); } - const string& output = GetCapturedTestStdout(); - EXPECT_EQ("", output); + EXPECT_STREQ("", GetCapturedStdout().c_str()); } // Tests that Google Mock warns on having too many actions in an // expectation compared to its cardinality. TEST(ExpectCallSyntaxTest, WarnsOnTooManyActions) { - CaptureTestStdout(); + CaptureStdout(); { MockB b; @@ -586,7 +591,7 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooManyActions) { b.DoB(1); b.DoB(2); } - const string& output = GetCapturedTestStdout(); + const String output = GetCapturedStdout(); EXPECT_PRED_FORMAT2( IsSubstring, "Too many actions specified in EXPECT_CALL(b, DoB())...\n" @@ -626,9 +631,9 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooFewActions) { .Times(Between(2, 3)) .WillOnce(Return(1)); - CaptureTestStdout(); + CaptureStdout(); b.DoB(); - const string& output = GetCapturedTestStdout(); + const String output = GetCapturedStdout(); EXPECT_PRED_FORMAT2( IsSubstring, "Too few actions specified in EXPECT_CALL(b, DoB())...\n" @@ -638,7 +643,7 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooFewActions) { b.DoB(); } -#endif // 0 +#endif // GTEST_HAS_STREAM_REDIRECTION_ // Tests the semantics of ON_CALL(). @@ -792,8 +797,7 @@ TEST(ExpectCallTest, NthMatchTakesNthAction) { EXPECT_EQ(3, b.DoB()); } -// TODO(wan@google.com): find a way to re-enable these tests. -#if 0 +#if GTEST_HAS_STREAM_REDIRECTION_ // Tests that the default action is taken when the WillOnce(...) list is // exhausted and there is no WillRepeatedly(). @@ -806,29 +810,29 @@ TEST(ExpectCallTest, TakesDefaultActionWhenWillListIsExhausted) { .WillOnce(Return(1)) .WillOnce(Return(2)); - CaptureTestStdout(); + CaptureStdout(); EXPECT_EQ(0, b.DoB(1)); // Shouldn't generate a warning as the // expectation has no action clause at all. EXPECT_EQ(1, b.DoB()); EXPECT_EQ(2, b.DoB()); - const string& output1 = GetCapturedTestStdout(); - EXPECT_EQ("", output1); + const String output1 = GetCapturedStdout(); + EXPECT_STREQ("", output1.c_str()); - CaptureTestStdout(); + CaptureStdout(); EXPECT_EQ(0, b.DoB()); EXPECT_EQ(0, b.DoB()); - const string& output2 = GetCapturedTestStdout(); - EXPECT_PRED2(RE::PartialMatch, output2, - "Actions ran out\\.\n" - "Called 3 times, but only 2 WillOnce\\(\\)s are specified - " - "returning default value\\."); - EXPECT_PRED2(RE::PartialMatch, output2, - "Actions ran out\\.\n" - "Called 4 times, but only 2 WillOnce\\(\\)s are specified - " - "returning default value\\."); + const String output2 = GetCapturedStdout(); + EXPECT_THAT(output2.c_str(), + HasSubstr("Actions ran out in EXPECT_CALL(b, DoB())...\n" + "Called 3 times, but only 2 WillOnce()s are specified" + " - returning default value.")); + EXPECT_THAT(output2.c_str(), + HasSubstr("Actions ran out in EXPECT_CALL(b, DoB())...\n" + "Called 4 times, but only 2 WillOnce()s are specified" + " - returning default value.")); } -#endif // 0 +#endif // GTEST_HAS_STREAM_REDIRECTION_ // Tests that the WillRepeatedly() action is taken when the WillOnce(...) // list is exhausted. @@ -1779,16 +1783,15 @@ class MockC { GTEST_DISALLOW_COPY_AND_ASSIGN_(MockC); }; -// TODO(wan@google.com): find a way to re-enable these tests. -#if 0 +#if GTEST_HAS_STREAM_REDIRECTION_ // Tests that an uninteresting mock function call generates a warning // containing the stack trace. TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { MockC c; - CaptureTestStdout(); + CaptureStdout(); c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); - const string& output = GetCapturedTestStdout(); + const String output = GetCapturedStdout(); EXPECT_PRED_FORMAT2(IsSubstring, "GMOCK WARNING", output); EXPECT_PRED_FORMAT2(IsSubstring, "Stack trace:", output); #ifndef NDEBUG @@ -1797,14 +1800,14 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { // Verifies that a void mock function's name appears in the stack // trace. - EXPECT_PRED_FORMAT2(IsSubstring, "::MockC::VoidMethod(", output); + EXPECT_PRED_FORMAT2(IsSubstring, "VoidMethod(", output); // Verifies that a non-void mock function's name appears in the // stack trace. - CaptureTestStdout(); + CaptureStdout(); c.NonVoidMethod(); - const string& output2 = GetCapturedTestStdout(); - EXPECT_PRED_FORMAT2(IsSubstring, "::MockC::NonVoidMethod(", output2); + const String output2 = GetCapturedStdout(); + EXPECT_PRED_FORMAT2(IsSubstring, "NonVoidMethod(", output2); #endif // NDEBUG } @@ -1813,26 +1816,27 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { // A non-void mock function. MockB b; - CaptureTestStdout(); + CaptureStdout(); b.DoB(); - const string& output1 = GetCapturedTestStdout(); + const String output1 = GetCapturedStdout(); EXPECT_PRED_FORMAT2( IsSubstring, "Uninteresting mock function call - returning default value.\n" " Function call: DoB()\n" - " Returns: 0\n", output1); + " Returns: 0\n", output1.c_str()); // Makes sure the return value is printed. // A void mock function. MockC c; - CaptureTestStdout(); + CaptureStdout(); c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); - const string& output2 = GetCapturedTestStdout(); - EXPECT_PRED2(RE::PartialMatch, output2, - "Uninteresting mock function call - returning directly\\.\n" - " Function call: VoidMethod" - "\\(false, 5, \"Hi\", NULL, @0x\\w+ " - "Printable, 4-byte object <0000 0000>\\)"); + const String output2 = GetCapturedStdout(); + EXPECT_THAT(output2.c_str(), + ContainsRegex( + "Uninteresting mock function call - returning directly\\.\n" + " Function call: VoidMethod" + "\\(false, 5, \"Hi\", NULL, @.+ " + "Printable, 4-byte object <0000 0000>\\)")); // A void function has no return value to print. } @@ -1844,18 +1848,21 @@ class GMockVerboseFlagTest : public testing::Test { // should_print is true, the output should match the given regex and // contain the given function name in the stack trace. When it's // false, the output should be empty.) - void VerifyOutput(const string& output, bool should_print, - const string& regex, + void VerifyOutput(const String& output, bool should_print, + const string& expected_substring, const string& function_name) { if (should_print) { - EXPECT_PRED2(RE::PartialMatch, output, regex); + EXPECT_THAT(output.c_str(), HasSubstr(expected_substring)); #ifndef NDEBUG // We check the stack trace content in dbg-mode only, as opt-mode // may inline the call we are interested in seeing. - EXPECT_PRED_FORMAT2(IsSubstring, function_name, output); + EXPECT_THAT(output.c_str(), HasSubstr(function_name)); +#else + // Suppresses 'unused function parameter' warnings. + static_cast(function_name); #endif // NDEBUG } else { - EXPECT_EQ("", output); + EXPECT_STREQ("", output.c_str()); } } @@ -1867,27 +1874,27 @@ class GMockVerboseFlagTest : public testing::Test { .WillOnce(Return(true)); // A void-returning function. - CaptureTestStdout(); + CaptureStdout(); a.DoA(5); VerifyOutput( - GetCapturedTestStdout(), + GetCapturedStdout(), should_print, - "Expected mock function call\\.\n" - " Function call: DoA\\(5\\)\n" - "Stack trace:", - "MockA::DoA"); + "Mock function call matches EXPECT_CALL(a, DoA(5))...\n" + " Function call: DoA(5)\n" + "Stack trace:\n", + "DoA"); // A non-void-returning function. - CaptureTestStdout(); + CaptureStdout(); a.Binary(2, 1); VerifyOutput( - GetCapturedTestStdout(), + GetCapturedStdout(), should_print, - "Expected mock function call\\.\n" - " Function call: Binary\\(2, 1\\)\n" + "Mock function call matches EXPECT_CALL(a, Binary(_, 1))...\n" + " Function call: Binary(2, 1)\n" " Returns: true\n" - "Stack trace:", - "MockA::Binary"); + "Stack trace:\n", + "Binary"); } // Tests how the flag affects uninteresting calls. @@ -1895,31 +1902,29 @@ class GMockVerboseFlagTest : public testing::Test { MockA a; // A void-returning function. - CaptureTestStdout(); + CaptureStdout(); a.DoA(5); VerifyOutput( - GetCapturedTestStdout(), + GetCapturedStdout(), should_print, "\nGMOCK WARNING:\n" - "Uninteresting mock function call - returning directly\\.\n" - " Function call: DoA\\(5\\)\n" - "Stack trace:\n" - "[\\s\\S]*", - "MockA::DoA"); + "Uninteresting mock function call - returning directly.\n" + " Function call: DoA(5)\n" + "Stack trace:\n", + "DoA"); // A non-void-returning function. - CaptureTestStdout(); + CaptureStdout(); a.Binary(2, 1); VerifyOutput( - GetCapturedTestStdout(), + GetCapturedStdout(), should_print, "\nGMOCK WARNING:\n" - "Uninteresting mock function call - returning default value\\.\n" - " Function call: Binary\\(2, 1\\)\n" + "Uninteresting mock function call - returning default value.\n" + " Function call: Binary(2, 1)\n" " Returns: false\n" - "Stack trace:\n" - "[\\s\\S]*", - "MockA::Binary"); + "Stack trace:\n", + "Binary"); } }; @@ -1955,7 +1960,7 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { TestUninterestingCall(true); } -#endif // 0 +#endif // GTEST_HAS_STREAM_REDIRECTION_ // A helper class that generates a failure when printed. We use it to // ensure that Google Mock doesn't print a value (even to an internal -- cgit v1.2.3 From 5905ba00fe78e522f7253e837ded3ddb5b946934 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Feb 2010 17:21:37 +0000 Subject: Adds threading support (by Vlad Losev); updates the version number (by Zhanyong Wan); adds release notes for 1.5.0 (by Vlad Losev). --- CHANGES | 24 ++++++++++++++++++++++++ Makefile.am | 8 ++++++++ configure.ac | 25 +++++++++++++++++++++++-- include/gmock/gmock-spec-builders.h | 2 +- src/gmock-internal-utils.cc | 2 +- src/gmock-spec-builders.cc | 2 +- 6 files changed, 58 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index f703ac2e..16fc85d8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,27 @@ +Changes for 1.5.0: + + * Support for use in multi-threaded tests on platforms having pthreads + (by virtue of the Google Test thread change) + * The new matcher API lets user-defined matchers generate custom + explanations more directly and efficiently. + * Better expectation failure messages. + * 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 matching 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): diff --git a/Makefile.am b/Makefile.am index c10d81cd..30941d4f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,5 @@ +# Automake file + # Nonstandard package files for distribution. EXTRA_DIST = @@ -16,6 +18,12 @@ DISTCLEANFILES = scripts/gmock-config # 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 diff --git a/configure.ac b/configure.ac index 25ab6f36..8498a6c5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,7 @@ +m4_include(gtest/m4/acx_pthread.m4) + AC_INIT([Google C++ Mocking Framework], - [1.4.0], + [1.5.0], [googlemock@googlegroups.com], [gmock]) @@ -35,6 +37,25 @@ 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 @@ -80,7 +101,7 @@ AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" -GTEST_MIN_VERSION="1.4.0" +GTEST_MIN_VERSION="1.5.0" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index d8d4749a..9b60f692 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -112,7 +112,7 @@ template class FunctionMockerBase; // expectations when InSequence() is used, and thus affect which // expectation gets picked. Therefore, we sequence all mock function // calls to ensure the integrity of the mock objects' states. -extern Mutex g_gmock_mutex; +GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); // Abstract base class of FunctionMockerBase. This is the // type-agnostic part of the function mocker interface. Its pure diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 4c51ec00..cc51836b 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -103,7 +103,7 @@ FailureReporterInterface* GetFailureReporter() { } // Protects global resources (stdout in particular) used by Log(). -static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); +static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex); // Returns true iff a log with the given severity is visible according // to the --gmock_verbose flag. diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 02a3227f..dab1a2c9 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -53,7 +53,7 @@ namespace internal { // Protects the mock object registry (in class Mock), all function // mockers, and all expectations. -Mutex g_gmock_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); +GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex); // Constructs an ExpectationBase object. ExpectationBase::ExpectationBase(const char* a_file, -- cgit v1.2.3 From 34b034c21ef4af7c0100194ed6f85910fc99debb Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 5 Mar 2010 21:23:23 +0000 Subject: Adds a free function MatchAndExplain(). --- include/gmock/gmock-matchers.h | 8 ++++++++ test/gmock-matchers_test.cc | 28 ++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index ae7e131d..50c0d7bf 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2850,6 +2850,14 @@ inline bool Value(const T& value, M matcher) { return testing::Matches(matcher)(value); } +// Matches the value against the given matcher and explains the match +// result to listener. +template +inline bool MatchAndExplain( + M matcher, const T& value, MatchResultListener* listener) { + return SafeMatcherCast(matcher).MatchAndExplain(value, listener); +} + // AllArgs(m) is a synonym of m. This is useful in // // EXPECT_CALL(foo, Bar(_, _)).With(AllArgs(Eq())); diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index b674cd8a..1eaecf9e 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -88,6 +88,7 @@ using testing::Matcher; using testing::MatcherCast; using testing::MatcherInterface; using testing::Matches; +using testing::MatchAndExplain; using testing::MatchResultListener; using testing::NanSensitiveDoubleEq; using testing::NanSensitiveFloatEq; @@ -118,6 +119,7 @@ using testing::internal::JoinAsTuple; using testing::internal::SkipPrefix; using testing::internal::String; using testing::internal::Strings; +using testing::internal::StringMatchResultListener; using testing::internal::ValidateMatcherDescription; using testing::internal::kInvalidInterpolation; using testing::internal::kPercentInterpolation; @@ -287,11 +289,11 @@ TEST(MatcherTest, CanDescribeItself) { // Tests Matcher::MatchAndExplain(). TEST(MatcherTest, MatchAndExplain) { Matcher m = GreaterThan(0); - ::testing::internal::StringMatchResultListener listener1; + StringMatchResultListener listener1; EXPECT_TRUE(m.MatchAndExplain(42, &listener1)); EXPECT_EQ("is 42 more than 0", listener1.str()); - ::testing::internal::StringMatchResultListener listener2; + StringMatchResultListener listener2; EXPECT_FALSE(m.MatchAndExplain(-9, &listener2)); EXPECT_EQ("is 9 less than 0", listener2.str()); } @@ -2047,6 +2049,28 @@ TEST(ValueTest, WorksWithMonomorphicMatcher) { EXPECT_FALSE(Value(1, ref_n)); } +TEST(MatchAndExplainTest, WorksWithPolymorphicMatcher) { + StringMatchResultListener listener1; + EXPECT_TRUE(MatchAndExplain(PolymorphicIsEven(), 42, &listener1)); + EXPECT_EQ("% 2 == 0", listener1.str()); + + StringMatchResultListener listener2; + EXPECT_FALSE(MatchAndExplain(Ge(42), 1.5, &listener2)); + EXPECT_EQ("", listener2.str()); +} + +TEST(MatchAndExplainTest, WorksWithMonomorphicMatcher) { + const Matcher is_even = PolymorphicIsEven(); + StringMatchResultListener listener1; + EXPECT_TRUE(MatchAndExplain(is_even, 42, &listener1)); + EXPECT_EQ("% 2 == 0", listener1.str()); + + const Matcher is_zero = Eq(0); + StringMatchResultListener listener2; + EXPECT_FALSE(MatchAndExplain(is_zero, 1.5, &listener2)); + EXPECT_EQ("", listener2.str()); +} + TEST(AllArgsTest, WorksForTuple) { EXPECT_THAT(make_tuple(1, 2L), AllArgs(Lt())); EXPECT_THAT(make_tuple(2L, 1), Not(AllArgs(Lt()))); -- cgit v1.2.3 From a862f1de30ed1ef259bcec61c5939200b29c765c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 15 Mar 2010 21:23:04 +0000 Subject: Adds IsInterested() to MatchResultListener; clarifies the format of matcher description and match result explanation; renames the free function MatchAndExplain() to ExplainMatchResult() to avoid it being hidden inside a MATCHER* definition. --- include/gmock/gmock-matchers.h | 19 ++++++++++++--- test/gmock-matchers_test.cc | 53 +++++++++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 50c0d7bf..8dba440a 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -90,6 +90,12 @@ class MatchResultListener { // 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_; @@ -106,7 +112,10 @@ class MatcherInterface { virtual ~MatcherInterface() {} // Returns true iff the matcher matches x; also explains the match - // result to 'listener'. + // result to 'listener', 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 ...". // // You should override this method when defining a new matcher. // @@ -118,7 +127,11 @@ class MatcherInterface { // listener->stream() may be NULL. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - // Describes this matcher to an ostream. + // 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 @@ -2853,7 +2866,7 @@ inline bool Value(const T& value, M matcher) { // Matches the value against the given matcher and explains the match // result to listener. template -inline bool MatchAndExplain( +inline bool ExplainMatchResult( M matcher, const T& value, MatchResultListener* listener) { return SafeMatcherCast(matcher).MatchAndExplain(value, listener); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 1eaecf9e..1ba4c8d9 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -88,7 +89,7 @@ using testing::Matcher; using testing::MatcherCast; using testing::MatcherInterface; using testing::Matches; -using testing::MatchAndExplain; +using testing::ExplainMatchResult; using testing::MatchResultListener; using testing::NanSensitiveDoubleEq; using testing::NanSensitiveFloatEq; @@ -110,6 +111,7 @@ using testing::Truly; using testing::TypedEq; using testing::Value; using testing::_; +using testing::internal::DummyMatchResultListener; using testing::internal::FloatingEqMatcher; using testing::internal::FormatMatcherDescriptionSyntaxError; using testing::internal::GetParamIndex; @@ -117,6 +119,7 @@ using testing::internal::Interpolation; using testing::internal::Interpolations; using testing::internal::JoinAsTuple; using testing::internal::SkipPrefix; +using testing::internal::StreamMatchResultListener; using testing::internal::String; using testing::internal::Strings; using testing::internal::StringMatchResultListener; @@ -187,6 +190,31 @@ string Explain(const MatcherType& m, const Value& x) { return ss.str(); } +TEST(MatchResultListenerTest, StreamingWorks) { + StringMatchResultListener listener; + listener << "hi" << 5; + EXPECT_EQ("hi5", listener.str()); + + // Streaming shouldn't crash when the underlying ostream is NULL. + DummyMatchResultListener dummy; + dummy << "hi" << 5; +} + +TEST(MatchResultListenerTest, CanAccessUnderlyingStream) { + EXPECT_TRUE(DummyMatchResultListener().stream() == NULL); + EXPECT_TRUE(StreamMatchResultListener(NULL).stream() == NULL); + + EXPECT_EQ(&std::cout, StreamMatchResultListener(&std::cout).stream()); +} + +TEST(MatchResultListenerTest, IsInterestedWorks) { + EXPECT_TRUE(StringMatchResultListener().IsInterested()); + EXPECT_TRUE(StreamMatchResultListener(&std::cout).IsInterested()); + + EXPECT_FALSE(DummyMatchResultListener().IsInterested()); + EXPECT_FALSE(StreamMatchResultListener(NULL).IsInterested()); +} + // Makes sure that the MatcherInterface interface doesn't // change. class EvenMatcherImpl : public MatcherInterface { @@ -205,7 +233,8 @@ class EvenMatcherImpl : public MatcherInterface { // two methods is optional. }; -TEST(MatcherInterfaceTest, CanBeImplementedUsingDeprecatedAPI) { +// Makes sure that the MatcherInterface API doesn't change. +TEST(MatcherInterfaceTest, CanBeImplementedUsingPublishedAPI) { EvenMatcherImpl m; } @@ -2049,28 +2078,36 @@ TEST(ValueTest, WorksWithMonomorphicMatcher) { EXPECT_FALSE(Value(1, ref_n)); } -TEST(MatchAndExplainTest, WorksWithPolymorphicMatcher) { +TEST(ExplainMatchResultTest, WorksWithPolymorphicMatcher) { StringMatchResultListener listener1; - EXPECT_TRUE(MatchAndExplain(PolymorphicIsEven(), 42, &listener1)); + EXPECT_TRUE(ExplainMatchResult(PolymorphicIsEven(), 42, &listener1)); EXPECT_EQ("% 2 == 0", listener1.str()); StringMatchResultListener listener2; - EXPECT_FALSE(MatchAndExplain(Ge(42), 1.5, &listener2)); + EXPECT_FALSE(ExplainMatchResult(Ge(42), 1.5, &listener2)); EXPECT_EQ("", listener2.str()); } -TEST(MatchAndExplainTest, WorksWithMonomorphicMatcher) { +TEST(ExplainMatchResultTest, WorksWithMonomorphicMatcher) { const Matcher is_even = PolymorphicIsEven(); StringMatchResultListener listener1; - EXPECT_TRUE(MatchAndExplain(is_even, 42, &listener1)); + EXPECT_TRUE(ExplainMatchResult(is_even, 42, &listener1)); EXPECT_EQ("% 2 == 0", listener1.str()); const Matcher is_zero = Eq(0); StringMatchResultListener listener2; - EXPECT_FALSE(MatchAndExplain(is_zero, 1.5, &listener2)); + EXPECT_FALSE(ExplainMatchResult(is_zero, 1.5, &listener2)); EXPECT_EQ("", listener2.str()); } +MATCHER_P(Really, inner_matcher, "") { + return ExplainMatchResult(inner_matcher, arg, result_listener); +} + +TEST(ExplainMatchResultTest, WorksInsideMATCHER) { + EXPECT_THAT(0, Really(Eq(0))); +} + TEST(AllArgsTest, WorksForTuple) { EXPECT_THAT(make_tuple(1, 2L), AllArgs(Lt())); EXPECT_THAT(make_tuple(2L, 1), Not(AllArgs(Lt()))); -- cgit v1.2.3 From 676e8cc6092853c9dbf1eeab2402be0069d8fb7e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 16 Mar 2010 20:01:51 +0000 Subject: Fixes the explanation generated by many composite matchers (by Manuel Klimek); publishes the gmock value printer as testing::PrintToString() (by Zhanyong Wan). --- include/gmock/gmock-matchers.h | 152 ++++++++++++++++++++-------------- include/gmock/gmock-printers.h | 48 ++++------- test/gmock-generated-matchers_test.cc | 4 +- test/gmock-matchers_test.cc | 104 ++++++++++++++--------- test/gmock-printers_test.cc | 20 +++-- 5 files changed, 185 insertions(+), 143 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 8dba440a..9a1bab24 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -453,6 +453,38 @@ Matcher A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { +// If the explanation is not empty, prints it to the listener. +// 'listener' must not be NULL. +inline void PrintIfNotEmpty( + const internal::string& explanation, MatchResultListener* listener) { + if (explanation != "") { + *listener << ", " << explanation; + } +} + +// 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()); + PrintIfNotEmpty(inner_listener.str(), listener); + + return match; +} + // If the given string is not empty and os is not NULL, wraps the // string inside a pair of parentheses and streams the result to os. inline void StreamInParensAsNeeded(const internal::string& str, @@ -1604,13 +1636,8 @@ class PointeeMatcher { if (GetRawPointer(pointer) == NULL) return false; - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain(*pointer, &inner_listener); - const internal::string s = inner_listener.str(); - if (s != "") { - *listener << "points to a value that " << s; - } - return match; + *listener << "which points to "; + return MatchPrintAndExplain(*pointer, matcher_, listener); } private: @@ -1634,12 +1661,12 @@ class FieldMatcher { : field_(field), matcher_(matcher) {} void DescribeTo(::std::ostream* os) const { - *os << "the given field "; + *os << "is an object whose given field "; matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "the given field "; + *os << "is an object whose given field "; matcher_.DescribeNegationTo(os); } @@ -1657,13 +1684,8 @@ class FieldMatcher { // true_type iff the Field() matcher is used to match a pointer. bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, MatchResultListener* listener) const { - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener); - const internal::string s = inner_listener.str(); - if (s != "") { - *listener << "the given field " << s; - } - return match; + *listener << "whose given field is "; + return MatchPrintAndExplain(obj.*field_, matcher_, listener); } bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, @@ -1671,6 +1693,7 @@ class FieldMatcher { if (p == NULL) return false; + *listener << "which points to an object "; // Since *p has a field, it must be a class/struct/union type and // thus cannot be a pointer. Therefore we pass false_type() as // the first argument. @@ -1699,12 +1722,12 @@ class PropertyMatcher { : property_(property), matcher_(matcher) {} void DescribeTo(::std::ostream* os) const { - *os << "the given property "; + *os << "is an object whose given property "; matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "the given property "; + *os << "is an object whose given property "; matcher_.DescribeNegationTo(os); } @@ -1722,14 +1745,11 @@ class PropertyMatcher { // true_type iff the Property() matcher is used to match a pointer. bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, MatchResultListener* listener) const { - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain((obj.*property_)(), - &inner_listener); - const internal::string s = inner_listener.str(); - if (s != "") { - *listener << "the given property " << s; - } - return match; + *listener << "whose given property is "; + // Cannot pass the return value (for example, int) to MatchPrintAndExplain, + // which takes a non-const reference as argument. + RefToConstProperty result = (obj.*property_)(); + return MatchPrintAndExplain(result, matcher_, listener); } bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, @@ -1737,6 +1757,7 @@ class PropertyMatcher { if (p == NULL) return false; + *listener << "which points to an object "; // Since *p has a property method, it must be a class/struct/union // type and thus cannot be a pointer. Therefore we pass // false_type() as the first argument. @@ -1806,26 +1827,22 @@ class ResultOfMatcher { : callable_(callable), matcher_(matcher) {} virtual void DescribeTo(::std::ostream* os) const { - *os << "result of the given callable "; + *os << "is mapped by the given callable to a value that "; matcher_.DescribeTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "result of the given callable "; + *os << "is mapped by the given callable to a value that "; matcher_.DescribeNegationTo(os); } virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain( - CallableTraits::template Invoke(callable_, obj), - &inner_listener); - - const internal::string s = inner_listener.str(); - if (s != "") - *listener << "result of the given callable " << s; - - return match; + *listener << "which is mapped by the given callable to "; + // Cannot pass the return value (for example, int) to + // MatchPrintAndExplain, which takes a non-const reference as argument. + ResultType result = + CallableTraits::template Invoke(callable_, obj); + return MatchPrintAndExplain(result, matcher_, listener); } private: @@ -2098,39 +2115,50 @@ class PairMatcherImpl : public MatcherInterface { // matches second_matcher. virtual bool MatchAndExplain(PairType a_pair, MatchResultListener* listener) const { - StringMatchResultListener listener1; - const bool match1 = first_matcher_.MatchAndExplain(a_pair.first, - &listener1); - internal::string s1 = listener1.str(); - if (s1 != "") { - s1 = "the first field " + s1; + if (!listener->IsInterested()) { + // If the listener is not interested, we don't need to construct the + // explanation. + return first_matcher_.Matches(a_pair.first) && + second_matcher_.Matches(a_pair.second); } - if (!match1) { - *listener << s1; + StringMatchResultListener first_inner_listener; + if (!first_matcher_.MatchAndExplain(a_pair.first, + &first_inner_listener)) { + *listener << "whose first field does not match"; + PrintIfNotEmpty(first_inner_listener.str(), listener); return false; } - - StringMatchResultListener listener2; - const bool match2 = second_matcher_.MatchAndExplain(a_pair.second, - &listener2); - internal::string s2 = listener2.str(); - if (s2 != "") { - s2 = "the second field " + s2; - } - if (!match2) { - *listener << s2; + StringMatchResultListener second_inner_listener; + if (!second_matcher_.MatchAndExplain(a_pair.second, + &second_inner_listener)) { + *listener << "whose second field does not match"; + PrintIfNotEmpty(second_inner_listener.str(), listener); return false; } - - *listener << s1; - if (s1 != "" && s2 != "") { - *listener << ", and "; - } - *listener << s2; + ExplainSuccess(first_inner_listener.str(), second_inner_listener.str(), + listener); return true; } private: + void ExplainSuccess(const internal::string& first_explanation, + const internal::string& second_explanation, + MatchResultListener* listener) const { + *listener << "whose both fields match"; + if (first_explanation != "") { + *listener << ", where the first field is a value " << first_explanation; + } + if (second_explanation != "") { + *listener << ", "; + if (first_explanation != "") { + *listener << "and "; + } else { + *listener << "where "; + } + *listener << "the second field is a value " << second_explanation; + } + } + const Matcher first_matcher_; const Matcher second_matcher_; diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index cda3545a..d1cd03ca 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -57,18 +57,20 @@ // // We also provide some convenient wrappers: // -// // Prints a value as the given type to a string. -// string ::testing::internal::UniversalPrinter::PrintToString(value); +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); // // // Prints a value tersely: for a reference type, the referenced -// // value (but not the address) is printed; for a (const) char +// // value (but not the address) is printed; for a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // // // Prints value using the type inferred by the compiler. The difference // // from UniversalTersePrint() is that this function prints both the -// // pointer and the NUL-terminated string for a (const) char pointer. +// // pointer and the NUL-terminated string for a (const or not) char pointer. // void ::testing::internal::UniversalPrint(const T& value, ostream*); // // // Prints the fields of a tuple tersely to a string vector, one @@ -545,14 +547,6 @@ class UniversalPrinter { PrintTo(value, os); } - // A convenient wrapper for Print() that returns the print-out as a - // string. - static string PrintToString(const T& value) { - ::std::stringstream ss; - Print(value, &ss); - return ss.str(); - } - #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif // _MSC_VER @@ -585,14 +579,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // This overload prints a (const) char array compactly. void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os); -// Prints an array of 'len' elements, starting at address 'begin', to a string. -template -string UniversalPrintArrayToString(const T* begin, size_t len) { - ::std::stringstream ss; - UniversalPrintArray(begin, len, &ss); - return ss.str(); -} - // Implements printing an array type T[N]. template class UniversalPrinter { @@ -602,12 +588,6 @@ class UniversalPrinter { static void Print(const T (&a)[N], ::std::ostream* os) { UniversalPrintArray(a, N, os); } - - // A convenient wrapper for Print() that returns the print-out as a - // string. - static string PrintToString(const T (&a)[N]) { - return UniversalPrintArrayToString(a, N); - } }; // Implements printing a reference type T&. @@ -630,14 +610,6 @@ class UniversalPrinter { UniversalPrinter::Print(value, os); } - // A convenient wrapper for Print() that returns the print-out as a - // string. - static string PrintToString(const T& value) { - ::std::stringstream ss; - Print(value, &ss); - return ss.str(); - } - #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif // _MSC_VER @@ -740,6 +712,14 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { } } // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrint(value, &ss); + return ss.str(); +} + } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 5e14c42a..db2ffb2f 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -178,9 +178,7 @@ TEST(ArgsTest, CanMatchTupleByReference) { // Validates that arg is printed as str. MATCHER_P(PrintsAs, str, "") { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(arg_type)) RawTuple; - return - testing::internal::UniversalPrinter::PrintToString(arg) == str; + return testing::PrintToString(arg) == str; } TEST(ArgsTest, AcceptsTenTemplateArgs) { diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 1ba4c8d9..5557983c 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -148,11 +148,11 @@ class GreaterThanMatcher : public MatcherInterface { MatchResultListener* listener) const { const int diff = lhs - rhs_; if (diff > 0) { - *listener << "is " << diff << " more than " << rhs_; + *listener << "which is " << diff << " more than " << rhs_; } else if (diff == 0) { - *listener << "is the same as " << rhs_; + *listener << "which is the same as " << rhs_; } else { - *listener << "is " << -diff << " less than " << rhs_; + *listener << "which is " << -diff << " less than " << rhs_; } return lhs > rhs_; @@ -320,11 +320,11 @@ TEST(MatcherTest, MatchAndExplain) { Matcher m = GreaterThan(0); StringMatchResultListener listener1; EXPECT_TRUE(m.MatchAndExplain(42, &listener1)); - EXPECT_EQ("is 42 more than 0", listener1.str()); + EXPECT_EQ("which is 42 more than 0", listener1.str()); StringMatchResultListener listener2; EXPECT_FALSE(m.MatchAndExplain(-9, &listener2)); - EXPECT_EQ("is 9 less than 0", listener2.str()); + EXPECT_EQ("which is 9 less than 0", listener2.str()); } // Tests that a C-string literal can be implicitly converted to a @@ -1180,23 +1180,38 @@ TEST(PairTest, CanExplainMatchResultTo) { // If neither field matches, Pair() should explain about the first // field. const Matcher > m = Pair(GreaterThan(0), GreaterThan(0)); - EXPECT_EQ("the first field is 1 less than 0", + EXPECT_EQ("whose first field does not match, which is 1 less than 0", Explain(m, std::make_pair(-1, -2))); // If the first field matches but the second doesn't, Pair() should // explain about the second field. - EXPECT_EQ("the second field is 2 less than 0", + EXPECT_EQ("whose second field does not match, which is 2 less than 0", Explain(m, std::make_pair(1, -2))); // If the first field doesn't match but the second does, Pair() // should explain about the first field. - EXPECT_EQ("the first field is 1 less than 0", + EXPECT_EQ("whose first field does not match, which is 1 less than 0", Explain(m, std::make_pair(-1, 2))); // If both fields match, Pair() should explain about them both. - EXPECT_EQ("the first field is 1 more than 0" - ", and the second field is 2 more than 0", + EXPECT_EQ("whose both fields match, where the first field is a value " + "which is 1 more than 0, and the second field is a value " + "which is 2 more than 0", Explain(m, std::make_pair(1, 2))); + + // If only the first match has an explanation, only this explanation should + // be printed. + const Matcher > explain_first = Pair(GreaterThan(0), 0); + EXPECT_EQ("whose both fields match, where the first field is a value " + "which is 1 more than 0", + Explain(explain_first, std::make_pair(1, 0))); + + // If only the second match has an explanation, only this explanation should + // be printed. + const Matcher > explain_second = Pair(0, GreaterThan(0)); + EXPECT_EQ("whose both fields match, where the second field is a value " + "which is 1 more than 0", + Explain(explain_second, std::make_pair(0, 1))); } TEST(PairTest, MatchesCorrectly) { @@ -2544,7 +2559,14 @@ TEST(PointeeTest, CanExplainMatchResult) { const Matcher m2 = Pointee(GreaterThan(1)); int n = 3; - EXPECT_EQ("points to a value that is 2 more than 1", Explain(m2, &n)); + EXPECT_EQ("which points to 3, which is 2 more than 1", + Explain(m2, &n)); +} + +TEST(PointeeTest, AlwaysExplainsPointee) { + const Matcher m = Pointee(0); + int n = 42; + EXPECT_EQ("which points to 42", Explain(m, &n)); } // An uncopyable class. @@ -2671,8 +2693,9 @@ TEST(FieldTest, WorksForCompatibleMatcherType) { TEST(FieldTest, CanDescribeSelf) { Matcher m = Field(&AStruct::x, Ge(0)); - EXPECT_EQ("the given field is greater than or equal to 0", Describe(m)); - EXPECT_EQ("the given field is not greater than or equal to 0", + EXPECT_EQ("is an object whose given field is greater than or equal to 0", + Describe(m)); + EXPECT_EQ("is an object whose given field is not greater than or equal to 0", DescribeNegation(m)); } @@ -2682,10 +2705,10 @@ TEST(FieldTest, CanExplainMatchResult) { AStruct a; a.x = 1; - EXPECT_EQ("", Explain(m, a)); + EXPECT_EQ("whose given field is 1", Explain(m, a)); m = Field(&AStruct::x, GreaterThan(0)); - EXPECT_EQ("the given field is 1 more than 0", Explain(m, a)); + EXPECT_EQ("whose given field is 1, which is 1 more than 0", Explain(m, a)); } // Tests that Field() works when the argument is a pointer to const. @@ -2741,8 +2764,9 @@ TEST(FieldForPointerTest, WorksForArgumentOfSubType) { TEST(FieldForPointerTest, CanDescribeSelf) { Matcher m = Field(&AStruct::x, Ge(0)); - EXPECT_EQ("the given field is greater than or equal to 0", Describe(m)); - EXPECT_EQ("the given field is not greater than or equal to 0", + EXPECT_EQ("is an object whose given field is greater than or equal to 0", + Describe(m)); + EXPECT_EQ("is an object whose given field is not greater than or equal to 0", DescribeNegation(m)); } @@ -2753,10 +2777,11 @@ TEST(FieldForPointerTest, CanExplainMatchResult) { AStruct a; a.x = 1; EXPECT_EQ("", Explain(m, static_cast(NULL))); - EXPECT_EQ("", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given field is 1", Explain(m, &a)); m = Field(&AStruct::x, GreaterThan(0)); - EXPECT_EQ("the given field is 1 more than 0", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given field is 1, " + "which is 1 more than 0", Explain(m, &a)); } // A user-defined class for testing Property(). @@ -2875,9 +2900,10 @@ TEST(PropertyTest, WorksForCompatibleMatcherType) { TEST(PropertyTest, CanDescribeSelf) { Matcher m = Property(&AClass::n, Ge(0)); - EXPECT_EQ("the given property is greater than or equal to 0", Describe(m)); - EXPECT_EQ("the given property is not greater than or equal to 0", - DescribeNegation(m)); + EXPECT_EQ("is an object whose given property is greater than or equal to 0", + Describe(m)); + EXPECT_EQ("is an object whose given property " + "is not greater than or equal to 0", DescribeNegation(m)); } // Tests that Property() can explain the match result. @@ -2886,10 +2912,10 @@ TEST(PropertyTest, CanExplainMatchResult) { AClass a; a.set_n(1); - EXPECT_EQ("", Explain(m, a)); + EXPECT_EQ("whose given property is 1", Explain(m, a)); m = Property(&AClass::n, GreaterThan(0)); - EXPECT_EQ("the given property is 1 more than 0", Explain(m, a)); + EXPECT_EQ("whose given property is 1, which is 1 more than 0", Explain(m, a)); } // Tests that Property() works when the argument is a pointer to const. @@ -2954,9 +2980,10 @@ TEST(PropertyForPointerTest, WorksForArgumentOfSubType) { TEST(PropertyForPointerTest, CanDescribeSelf) { Matcher m = Property(&AClass::n, Ge(0)); - EXPECT_EQ("the given property is greater than or equal to 0", Describe(m)); - EXPECT_EQ("the given property is not greater than or equal to 0", - DescribeNegation(m)); + EXPECT_EQ("is an object whose given property is greater than or equal to 0", + Describe(m)); + EXPECT_EQ("is an object whose given property " + "is not greater than or equal to 0", DescribeNegation(m)); } // Tests that Property() can explain the result of matching a pointer. @@ -2966,10 +2993,12 @@ TEST(PropertyForPointerTest, CanExplainMatchResult) { AClass a; a.set_n(1); EXPECT_EQ("", Explain(m, static_cast(NULL))); - EXPECT_EQ("", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given property is 1", + Explain(m, &a)); m = Property(&AClass::n, GreaterThan(0)); - EXPECT_EQ("the given property is 1 more than 0", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given property is 1, " + "which is 1 more than 0", Explain(m, &a)); } // Tests ResultOf. @@ -2989,10 +3018,10 @@ TEST(ResultOfTest, WorksForFunctionPointers) { TEST(ResultOfTest, CanDescribeItself) { Matcher matcher = ResultOf(&IntToStringFunction, StrEq("foo")); - EXPECT_EQ("result of the given callable is equal to \"foo\"", - Describe(matcher)); - EXPECT_EQ("result of the given callable is not equal to \"foo\"", - DescribeNegation(matcher)); + EXPECT_EQ("is mapped by the given callable to a value that " + "is equal to \"foo\"", Describe(matcher)); + EXPECT_EQ("is mapped by the given callable to a value that " + "is not equal to \"foo\"", DescribeNegation(matcher)); } // Tests that ResultOf() can explain the match result. @@ -3000,11 +3029,12 @@ int IntFunction(int input) { return input == 42 ? 80 : 90; } TEST(ResultOfTest, CanExplainMatchResult) { Matcher matcher = ResultOf(&IntFunction, Ge(85)); - EXPECT_EQ("", Explain(matcher, 36)); + EXPECT_EQ("which is mapped by the given callable to 90", + Explain(matcher, 36)); matcher = ResultOf(&IntFunction, GreaterThan(85)); - EXPECT_EQ("result of the given callable is 5 more than 85", - Explain(matcher, 36)); + EXPECT_EQ("which is mapped by the given callable to 90, " + "which is 5 more than 85", Explain(matcher, 36)); } // Tests that ResultOf(f, ...) compiles and works as expected when f(x) @@ -3202,7 +3232,7 @@ TEST(ExplainMatchResultTest, AllOf_True_True_2) { TEST(ExplainmatcherResultTest, MonomorphicMatcher) { const Matcher m = GreaterThan(5); - EXPECT_EQ("is 1 more than 5", Explain(m, 6)); + EXPECT_EQ("which is 1 more than 5", Explain(m, 6)); } // The following two tests verify that values without a public copy diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 0553e9ce..92c8413c 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -153,6 +153,7 @@ using ::std::tr1::make_tuple; using ::std::tr1::tuple; using ::std::vector; using ::testing::ElementsAre; +using ::testing::PrintToString; using ::testing::StartsWith; using ::testing::internal::NativeArray; using ::testing::internal::Strings; @@ -1010,19 +1011,24 @@ TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + " " + Print(sizeof(p)) + "-byte object ")); } -TEST(PrintToStringTest, WorksForNonReference) { - EXPECT_EQ("123", UniversalPrinter::PrintToString(123)); +TEST(PrintToStringTest, WorksForScalar) { + EXPECT_EQ("123", PrintToString(123)); } -TEST(PrintToStringTest, WorksForReference) { - int n = 123; - EXPECT_EQ("@" + PrintPointer(&n) + " 123", - UniversalPrinter::PrintToString(n)); +TEST(PrintToStringTest, WorksForPointerToConstChar) { + const char* p = "hello"; + EXPECT_EQ("\"hello\"", PrintToString(p)); +} + +TEST(PrintToStringTest, WorksForPointerToNonConstChar) { + char s[] = "hello"; + char* p = s; + EXPECT_EQ("\"hello\"", PrintToString(p)); } TEST(PrintToStringTest, WorksForArray) { int n[3] = { 1, 2, 3 }; - EXPECT_EQ("{ 1, 2, 3 }", UniversalPrinter::PrintToString(n)); + EXPECT_EQ("{ 1, 2, 3 }", PrintToString(n)); } TEST(UniversalTersePrintTest, WorksForNonReference) { -- cgit v1.2.3 From b1c7f93c52d7fbf484f34d01a65cfaec03786564 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Mar 2010 17:35:11 +0000 Subject: Improves matcher messages across the board. --- include/gmock/gmock-generated-matchers.h | 21 +- include/gmock/gmock-generated-matchers.h.pump | 17 +- include/gmock/gmock-matchers.h | 171 +++++----- include/gmock/gmock-spec-builders.h | 12 +- test/gmock-generated-matchers_test.cc | 85 +++-- test/gmock-matchers_test.cc | 437 ++++++++++++++++++-------- test/gmock_output_test_golden.txt | 6 +- 7 files changed, 504 insertions(+), 245 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 731ad7df..9e5bedea 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -1,4 +1,6 @@ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! +// 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. @@ -231,15 +233,28 @@ class ArgsMatcherImpl : public MatcherInterface { virtual bool MatchAndExplain(ArgsTuple args, MatchResultListener* listener) const { - return inner_matcher_.MatchAndExplain(GetSelectedArgs(args), listener); + 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); } @@ -252,7 +267,7 @@ class ArgsMatcherImpl : public MatcherInterface { // Prints the indices of the selected fields. static void PrintIndices(::std::ostream* os) { - *os << "are a tuple whose fields ("; + *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) diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index fb2bc358..07a51a36 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -118,15 +118,28 @@ class ArgsMatcherImpl : public MatcherInterface { virtual bool MatchAndExplain(ArgsTuple args, MatchResultListener* listener) const { - return inner_matcher_.MatchAndExplain(GetSelectedArgs(args), listener); + 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); } @@ -138,7 +151,7 @@ class ArgsMatcherImpl : public MatcherInterface { // Prints the indices of the selected fields. static void PrintIndices(::std::ostream* os) { - *os << "are a tuple whose fields ("; + *os << "whose fields ("; const int indices[$n] = { $ks }; for (int i = 0; i < $n; i++) { if (indices[i] < 0) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 9a1bab24..66efecd4 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -453,12 +453,11 @@ Matcher A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { -// If the explanation is not empty, prints it to the listener. -// 'listener' must not be NULL. -inline void PrintIfNotEmpty( - const internal::string& explanation, MatchResultListener* listener) { - if (explanation != "") { - *listener << ", " << explanation; +// 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; } } @@ -480,20 +479,11 @@ bool MatchPrintAndExplain(Value& value, const Matcher& matcher, const bool match = matcher.MatchAndExplain(value, &inner_listener); UniversalPrint(value, listener->stream()); - PrintIfNotEmpty(inner_listener.str(), listener); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); return match; } -// If the given string is not empty and os is not NULL, wraps the -// string inside a pair of parentheses and streams the result to os. -inline void StreamInParensAsNeeded(const internal::string& str, - ::std::ostream* os) { - if (!str.empty() && os != NULL) { - *os << " (" << str << ")"; - } -} - // An internal helper class for doing compile-time loop on a tuple's // fields. template @@ -510,19 +500,19 @@ class TuplePrefix { && get(matcher_tuple).Matches(get(value_tuple)); } - // TuplePrefix::DescribeMatchFailuresTo(matchers, values, os) + // 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 DescribeMatchFailuresTo(const MatcherTuple& matchers, - const ValueTuple& values, - ::std::ostream* os) { + static void ExplainMatchFailuresTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { using ::std::tr1::tuple_element; using ::std::tr1::get; // First, describes failures in the first N - 1 fields. - TuplePrefix::DescribeMatchFailuresTo(matchers, values, os); + TuplePrefix::ExplainMatchFailuresTo(matchers, values, os); // Then describes the failure (if any) in the (N - 1)-th (0-based) // field. @@ -542,10 +532,8 @@ class TuplePrefix { // isn't interesting to the user most of the time. The // matcher's MatchAndExplain() method handles the case when // the address is interesting. - internal::UniversalPrinter:: - Print(value, os); - - StreamInParensAsNeeded(listener.str(), os); + internal::UniversalPrint(value, os); + PrintIfNotEmpty(listener.str(), os); *os << "\n"; } } @@ -562,9 +550,9 @@ class TuplePrefix<0> { } template - static void DescribeMatchFailuresTo(const MatcherTuple& /* matchers */, - const ValueTuple& /* values */, - ::std::ostream* /* os */) {} + static void ExplainMatchFailuresTo(const MatcherTuple& /* matchers */, + const ValueTuple& /* values */, + ::std::ostream* /* os */) {} }; // TupleMatches(matcher_tuple, value_tuple) returns true iff all @@ -588,11 +576,11 @@ bool TupleMatches(const MatcherTuple& matcher_tuple, // Describes failures in matching matchers against values. If there // is no failure, nothing will be streamed to os. template -void DescribeMatchFailureTupleTo(const MatcherTuple& matchers, - const ValueTuple& values, - ::std::ostream* os) { +void ExplainMatchFailureTupleTo(const MatcherTuple& matchers, + const ValueTuple& values, + ::std::ostream* os) { using ::std::tr1::tuple_size; - TuplePrefix::value>::DescribeMatchFailuresTo( + TuplePrefix::value>::ExplainMatchFailuresTo( matchers, values, os); } @@ -695,7 +683,8 @@ class AnythingMatcher { // // The following template definition assumes that the Rhs parameter is // a "bare" type (i.e. neither 'const T' nor 'T&'). -#define GMOCK_IMPLEMENT_COMPARISON_MATCHER_(name, op, relation) \ +#define GMOCK_IMPLEMENT_COMPARISON_MATCHER_( \ + name, op, relation, negated_relation) \ template class name##Matcher { \ public: \ explicit name##Matcher(const Rhs& rhs) : rhs_(rhs) {} \ @@ -713,11 +702,11 @@ class AnythingMatcher { return lhs op rhs_; \ } \ virtual void DescribeTo(::std::ostream* os) const { \ - *os << "is " relation " "; \ + *os << relation " "; \ UniversalPrinter::Print(rhs_, os); \ } \ virtual void DescribeNegationTo(::std::ostream* os) const { \ - *os << "is not " relation " "; \ + *os << negated_relation " "; \ UniversalPrinter::Print(rhs_, os); \ } \ private: \ @@ -730,12 +719,12 @@ class AnythingMatcher { // Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v) // respectively. -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Eq, ==, "equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ge, >=, "greater than or equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Gt, >, "greater than"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Le, <=, "less than or equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Lt, <, "less than"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "not equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Eq, ==, "is equal to", "isn't equal to"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ge, >=, "is >=", "isn't >="); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Gt, >, "is >", "isn't >"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Le, <=, "is <=", "isn't <="); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Lt, <, "is <", "isn't <"); +GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "isn't equal to", "is equal to"); #undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_ @@ -751,7 +740,7 @@ class IsNullMatcher { void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } void DescribeNegationTo(::std::ostream* os) const { - *os << "is not NULL"; + *os << "isn't NULL"; } }; @@ -765,7 +754,7 @@ class NotNullMatcher { return GetRawPointer(p) != NULL; } - void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } + void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; } void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } @@ -820,7 +809,7 @@ class RefMatcher { // in order to match the interface MatcherInterface. virtual bool MatchAndExplain( Super& x, MatchResultListener* listener) const { - *listener << "is located @" << static_cast(&x); + *listener << "which is located @" << static_cast(&x); return &x == &object_; } @@ -917,10 +906,7 @@ class StrEqualityMatcher { private: void DescribeToHelper(bool expect_eq, ::std::ostream* os) const { - *os << "is "; - if (!expect_eq) { - *os << "not "; - } + *os << (expect_eq ? "is " : "isn't "); *os << "equal to "; if (!case_sensitive_) { *os << "(ignoring case) "; @@ -1212,8 +1198,11 @@ class BothOfMatcherImpl : public MatcherInterface { } virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not "; - DescribeTo(os); + *os << "("; + matcher1_.DescribeNegationTo(os); + *os << ") or ("; + matcher2_.DescribeNegationTo(os); + *os << ")"; } virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { @@ -1240,7 +1229,7 @@ class BothOfMatcherImpl : public MatcherInterface { } else { *listener << s1; if (s2 != "") { - *listener << "; " << s2; + *listener << ", and " << s2; } } return true; @@ -1296,8 +1285,11 @@ class EitherOfMatcherImpl : public MatcherInterface { } virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not "; - DescribeTo(os); + *os << "("; + matcher1_.DescribeNegationTo(os); + *os << ") and ("; + matcher2_.DescribeNegationTo(os); + *os << ")"; } virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { @@ -1324,7 +1316,7 @@ class EitherOfMatcherImpl : public MatcherInterface { } else { *listener << s1; if (s2 != "") { - *listener << "; " << s2; + *listener << ", and " << s2; } } return false; @@ -1462,18 +1454,15 @@ class PredicateFormatterFromMatcher { // matcher_ has type Matcher (e.g. An()). const Matcher matcher = MatcherCast(matcher_); StringMatchResultListener listener; - if (matcher.MatchAndExplain(x, &listener)) { + if (MatchPrintAndExplain(x, matcher, &listener)) return AssertionSuccess(); - } else { - ::std::stringstream ss; - ss << "Value of: " << value_text << "\n" - << "Expected: "; - matcher.DescribeTo(&ss); - ss << "\n Actual: "; - UniversalPrinter::Print(x, &ss); - StreamInParensAsNeeded(listener.str(), &ss); - return AssertionFailure(Message() << ss.str()); - } + + ::std::stringstream ss; + ss << "Value of: " << value_text << "\n" + << "Expected: "; + matcher.DescribeTo(&ss); + ss << "\n Actual: " << listener.str(); + return AssertionFailure() << ss.str(); } private: @@ -1548,12 +1537,12 @@ class FloatingEqMatcher { ::std::numeric_limits::digits10 + 2); if (FloatingPoint(rhs_).is_nan()) { if (nan_eq_nan_) { - *os << "is not NaN"; + *os << "isn't NaN"; } else { *os << "is anything"; } } else { - *os << "is not approximately " << rhs_; + *os << "isn't approximately " << rhs_; } // Restore original precision. os->precision(old_precision); @@ -1912,7 +1901,7 @@ class ContainerEqMatcher { ::std::ostream* const os = listener->stream(); if (os != NULL) { - // Something is different. Check for missing values first. + // Something is different. Check for extra values first. bool printed_header = false; for (typename LhsStlContainer::const_iterator it = lhs_stl_container.begin(); @@ -1922,7 +1911,7 @@ class ContainerEqMatcher { if (printed_header) { *os << ", "; } else { - *os << "Only in actual: "; + *os << "which has these unexpected elements: "; printed_header = true; } UniversalPrinter:: @@ -1930,7 +1919,7 @@ class ContainerEqMatcher { } } - // Now check for extra values. + // Now check for missing values. bool printed_header2 = false; for (typename StlContainer::const_iterator it = rhs_.begin(); it != rhs_.end(); ++it) { @@ -1940,7 +1929,8 @@ class ContainerEqMatcher { if (printed_header2) { *os << ", "; } else { - *os << (printed_header ? "; not" : "Not") << " in actual: "; + *os << (printed_header ? ",\nand" : "which") + << " doesn't have these expected elements: "; printed_header2 = true; } UniversalPrinter::Print(*it, os); @@ -1990,8 +1980,10 @@ class ContainsMatcherImpl : public MatcherInterface { size_t i = 0; for (typename StlContainer::const_iterator it = stl_container.begin(); it != stl_container.end(); ++it, ++i) { - if (inner_matcher_.Matches(*it)) { - *listener << "element " << i << " matches"; + StringMatchResultListener inner_listener; + if (inner_matcher_.MatchAndExplain(*it, &inner_listener)) { + *listener << "whose element #" << i << " matches"; + PrintIfNotEmpty(inner_listener.str(), listener->stream()); return true; } } @@ -2040,7 +2032,14 @@ class KeyMatcherImpl : public MatcherInterface { // Returns true iff 'key_value.first' (the key) matches the inner matcher. virtual bool MatchAndExplain(PairType key_value, MatchResultListener* listener) const { - return inner_matcher_.MatchAndExplain(key_value.first, listener); + StringMatchResultListener inner_listener; + const bool match = inner_matcher_.MatchAndExplain(key_value.first, + &inner_listener); + const internal::string explanation = inner_listener.str(); + if (explanation != "") { + *listener << "whose first field is a value " << explanation; + } + return match; } // Describes what this matcher does. @@ -2125,14 +2124,14 @@ class PairMatcherImpl : public MatcherInterface { if (!first_matcher_.MatchAndExplain(a_pair.first, &first_inner_listener)) { *listener << "whose first field does not match"; - PrintIfNotEmpty(first_inner_listener.str(), listener); + PrintIfNotEmpty(first_inner_listener.str(), listener->stream()); return false; } StringMatchResultListener second_inner_listener; if (!second_matcher_.MatchAndExplain(a_pair.second, &second_inner_listener)) { *listener << "whose second field does not match"; - PrintIfNotEmpty(second_inner_listener.str(), listener); + PrintIfNotEmpty(second_inner_listener.str(), listener->stream()); return false; } ExplainSuccess(first_inner_listener.str(), second_inner_listener.str(), @@ -2217,7 +2216,7 @@ class ElementsAreMatcherImpl : public MatcherInterface { } else { *os << "has " << Elements(count()) << " where\n"; for (size_t i = 0; i != count(); ++i) { - *os << "element " << i << " "; + *os << "element #" << i << " "; matchers_[i].DescribeTo(os); if (i + 1 < count()) { *os << ",\n"; @@ -2229,13 +2228,13 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Describes what the negation of this matcher does. virtual void DescribeNegationTo(::std::ostream* os) const { if (count() == 0) { - *os << "is not empty"; + *os << "isn't empty"; return; } - *os << "does not have " << Elements(count()) << ", or\n"; + *os << "doesn't have " << Elements(count()) << ", or\n"; for (size_t i = 0; i != count(); ++i) { - *os << "element " << i << " "; + *os << "element #" << i << " "; matchers_[i].DescribeNegationTo(os); if (i + 1 < count()) { *os << ", or\n"; @@ -2253,7 +2252,7 @@ class ElementsAreMatcherImpl : public MatcherInterface { // prints the empty container. Otherwise we just need to show // how many elements there actually are. if (actual_count != 0) { - *listener << "has " << Elements(actual_count); + *listener << "which has " << Elements(actual_count); } return false; } @@ -2268,24 +2267,22 @@ class ElementsAreMatcherImpl : public MatcherInterface { } else { // The container has the right size but the i-th element // doesn't match its expectation. - *listener << "element " << i << " doesn't match"; - - StreamInParensAsNeeded(s.str(), listener->stream()); + *listener << "whose element #" << i << " doesn't match"; + PrintIfNotEmpty(s.str(), listener->stream()); return false; } } // Every element matches its expectation. We need to explain why // (the obvious ones can be skipped). - bool reason_printed = false; for (size_t i = 0; i != count(); ++i) { const internal::string& s = explanations[i]; if (!s.empty()) { if (reason_printed) { - *listener << ",\n"; + *listener << ",\nand "; } - *listener << "element " << i << " " << s; + *listener << "whose element #" << i << " matches, " << s; reason_printed = true; } } diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 9b60f692..74a095da 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -993,8 +993,8 @@ class TypedExpectation : public ExpectationBase { // Describes the result of matching the arguments against this // expectation to the given ostream. // L >= g_gmock_mutex - void DescribeMatchResultTo(const ArgumentTuple& args, - ::std::ostream* os) const { + void ExplainMatchResultTo(const ArgumentTuple& args, + ::std::ostream* os) const { g_gmock_mutex.AssertHeld(); if (is_retired()) { @@ -1002,7 +1002,7 @@ class TypedExpectation : public ExpectationBase { << " Actual: it is retired\n"; } else if (!Matches(args)) { if (!TupleMatches(matchers_, args)) { - DescribeMatchFailureTupleTo(matchers_, args, os); + ExplainMatchFailureTupleTo(matchers_, args, os); } StringMatchResultListener listener; if (!extra_matcher_.MatchAndExplain(args, &listener)) { @@ -1010,7 +1010,7 @@ class TypedExpectation : public ExpectationBase { extra_matcher_.DescribeTo(os); *os << "\n Actual: don't match"; - internal::StreamInParensAsNeeded(listener.str(), os); + internal::PrintIfNotEmpty(listener.str(), os); *os << "\n"; } } else if (!AllPrerequisitesAreSatisfied()) { @@ -1028,7 +1028,7 @@ class TypedExpectation : public ExpectationBase { *os << " (end of pre-requisites)\n"; } else { // This line is here just for completeness' sake. It will never - // be executed as currently the DescribeMatchResultTo() function + // be executed as currently the ExplainMatchResultTo() function // is called only when the mock function call does NOT match the // expectation. *os << "The call matches the expectation.\n"; @@ -1618,7 +1618,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { *why << "tried expectation #" << i << ": "; } *why << expectations_[i]->source_text() << "...\n"; - expectations_[i]->DescribeMatchResultTo(args, why); + expectations_[i]->ExplainMatchResultTo(args, why); expectations_[i]->DescribeCallCountTo(why); } } diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index db2ffb2f..12479af4 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -211,6 +211,43 @@ TEST(ArgsTest, DescribesNegationCorrectly) { DescribeNegation(m)); } +TEST(ArgsTest, ExplainsMatchResultWithoutInnerExplanation) { + const Matcher > m = Args<1, 2>(Eq()); + EXPECT_EQ("whose fields (#1, #2) are (42, 42)", + Explain(m, make_tuple(false, 42, 42))); + EXPECT_EQ("whose fields (#1, #2) are (42, 43)", + Explain(m, make_tuple(false, 42, 43))); +} + +// For testing Args<>'s explanation. +class LessThanMatcher : public MatcherInterface > { + public: + virtual void DescribeTo(::std::ostream* os) const {} + + virtual bool MatchAndExplain(tuple value, + MatchResultListener* listener) const { + const int diff = get<0>(value) - get<1>(value); + if (diff > 0) { + *listener << "where the first value is " << diff + << " more than the second"; + } + return diff < 0; + } +}; + +Matcher > LessThan() { + return MakeMatcher(new LessThanMatcher); +} + +TEST(ArgsTest, ExplainsMatchResultWithInnerExplanation) { + const Matcher > m = Args<0, 2>(LessThan()); + EXPECT_EQ("whose fields (#0, #2) are ('a' (97), 42), " + "where the first value is 55 more than the second", + Explain(m, make_tuple('a', 42, 42))); + EXPECT_EQ("whose fields (#0, #2) are ('\\0', 43)", + Explain(m, make_tuple('\0', 42, 43))); +} + // For testing ExplainMatchResultTo(). class GreaterThanMatcher : public MatcherInterface { public: @@ -224,11 +261,11 @@ class GreaterThanMatcher : public MatcherInterface { MatchResultListener* listener) const { const int diff = lhs - rhs_; if (diff > 0) { - *listener << "is " << diff << " more than " << rhs_; + *listener << "which is " << diff << " more than " << rhs_; } else if (diff == 0) { - *listener << "is the same as " << rhs_; + *listener << "which is the same as " << rhs_; } else { - *listener << "is " << -diff << " less than " << rhs_; + *listener << "which is " << -diff << " less than " << rhs_; } return lhs > rhs_; @@ -254,32 +291,32 @@ TEST(ElementsAreTest, CanDescribeExpectingNoElement) { TEST(ElementsAreTest, CanDescribeExpectingOneElement) { Matcher > m = ElementsAre(Gt(5)); - EXPECT_EQ("has 1 element that is greater than 5", Describe(m)); + EXPECT_EQ("has 1 element that is > 5", Describe(m)); } TEST(ElementsAreTest, CanDescribeExpectingManyElements) { Matcher > m = ElementsAre(StrEq("one"), "two"); EXPECT_EQ("has 2 elements where\n" - "element 0 is equal to \"one\",\n" - "element 1 is equal to \"two\"", Describe(m)); + "element #0 is equal to \"one\",\n" + "element #1 is equal to \"two\"", Describe(m)); } TEST(ElementsAreTest, CanDescribeNegationOfExpectingNoElement) { Matcher > m = ElementsAre(); - EXPECT_EQ("is not empty", DescribeNegation(m)); + EXPECT_EQ("isn't empty", DescribeNegation(m)); } TEST(ElementsAreTest, CanDescribeNegationOfExpectingOneElment) { Matcher& > m = ElementsAre(Gt(5)); - EXPECT_EQ("does not have 1 element, or\n" - "element 0 is not greater than 5", DescribeNegation(m)); + EXPECT_EQ("doesn't have 1 element, or\n" + "element #0 isn't > 5", DescribeNegation(m)); } TEST(ElementsAreTest, CanDescribeNegationOfExpectingManyElements) { Matcher& > m = ElementsAre("one", "two"); - EXPECT_EQ("does not have 2 elements, or\n" - "element 0 is not equal to \"one\", or\n" - "element 1 is not equal to \"two\"", DescribeNegation(m)); + EXPECT_EQ("doesn't have 2 elements, or\n" + "element #0 isn't equal to \"one\", or\n" + "element #1 isn't equal to \"two\"", DescribeNegation(m)); } TEST(ElementsAreTest, DoesNotExplainTrivialMatch) { @@ -297,8 +334,9 @@ TEST(ElementsAreTest, ExplainsNonTrivialMatch) { const int a[] = { 10, 0, 100 }; vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); - EXPECT_EQ("element 0 is 9 more than 1,\n" - "element 2 is 98 more than 2", Explain(m, test_vector)); + EXPECT_EQ("whose element #0 matches, which is 9 more than 1,\n" + "and whose element #2 matches, which is 98 more than 2", + Explain(m, test_vector)); } TEST(ElementsAreTest, CanExplainMismatchWrongSize) { @@ -309,7 +347,7 @@ TEST(ElementsAreTest, CanExplainMismatchWrongSize) { EXPECT_EQ("", Explain(m, test_list)); test_list.push_back(1); - EXPECT_EQ("has 1 element", Explain(m, test_list)); + EXPECT_EQ("which has 1 element", Explain(m, test_list)); } TEST(ElementsAreTest, CanExplainMismatchRightSize) { @@ -318,10 +356,11 @@ TEST(ElementsAreTest, CanExplainMismatchRightSize) { vector v; v.push_back(2); v.push_back(1); - EXPECT_EQ("element 0 doesn't match", Explain(m, v)); + EXPECT_EQ("whose element #0 doesn't match", Explain(m, v)); v[0] = 1; - EXPECT_EQ("element 1 doesn't match (is 4 less than 5)", Explain(m, v)); + EXPECT_EQ("whose element #1 doesn't match, which is 4 less than 5", + Explain(m, v)); } TEST(ElementsAreTest, MatchesOneElementVector) { @@ -1030,16 +1069,22 @@ TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { EXPECT_THAT(c_string_set, Not(Contains(string("hello").c_str()))); } -TEST(ContainsTest, DescribesItselfCorrectly) { +TEST(ContainsTest, ExplainsMatchResultCorrectly) { const int a[2] = { 1, 2 }; Matcher m = Contains(2); - EXPECT_EQ("element 1 matches", Explain(m, a)); + EXPECT_EQ("whose element #1 matches", Explain(m, a)); m = Contains(3); EXPECT_EQ("", Explain(m, a)); + + m = Contains(GreaterThan(0)); + EXPECT_EQ("whose element #0 matches, which is 1 more than 0", Explain(m, a)); + + m = Contains(GreaterThan(10)); + EXPECT_EQ("", Explain(m, a)); } -TEST(ContainsTest, ExplainsMatchResultCorrectly) { +TEST(ContainsTest, DescribesItselfCorrectly) { Matcher > m = Contains(1); EXPECT_EQ("contains at least one element that is equal to 1", Describe(m)); diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 5557983c..6d784f16 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -61,8 +61,10 @@ bool SkipPrefix(const char* prefix, const char** pstr); namespace gmock_matchers_test { +using std::make_pair; using std::map; using std::multimap; +using std::pair; using std::stringstream; using std::tr1::make_tuple; using testing::A; @@ -71,9 +73,11 @@ using testing::AllOf; using testing::An; using testing::AnyOf; using testing::ByRef; +using testing::ContainsRegex; using testing::DoubleEq; using testing::EndsWith; using testing::Eq; +using testing::ExplainMatchResult; using testing::Field; using testing::FloatEq; using testing::Ge; @@ -85,12 +89,12 @@ using testing::Le; using testing::Lt; using testing::MakeMatcher; using testing::MakePolymorphicMatcher; +using testing::MatchResultListener; using testing::Matcher; using testing::MatcherCast; using testing::MatcherInterface; using testing::Matches; -using testing::ExplainMatchResult; -using testing::MatchResultListener; +using testing::MatchesRegex; using testing::NanSensitiveDoubleEq; using testing::NanSensitiveFloatEq; using testing::Ne; @@ -112,17 +116,19 @@ using testing::TypedEq; using testing::Value; using testing::_; using testing::internal::DummyMatchResultListener; +using testing::internal::ExplainMatchFailureTupleTo; using testing::internal::FloatingEqMatcher; using testing::internal::FormatMatcherDescriptionSyntaxError; using testing::internal::GetParamIndex; using testing::internal::Interpolation; using testing::internal::Interpolations; using testing::internal::JoinAsTuple; +using testing::internal::RE; using testing::internal::SkipPrefix; using testing::internal::StreamMatchResultListener; using testing::internal::String; -using testing::internal::Strings; using testing::internal::StringMatchResultListener; +using testing::internal::Strings; using testing::internal::ValidateMatcherDescription; using testing::internal::kInvalidInterpolation; using testing::internal::kPercentInterpolation; @@ -131,17 +137,13 @@ using testing::internal::linked_ptr; using testing::internal::scoped_ptr; using testing::internal::string; -using testing::ContainsRegex; -using testing::MatchesRegex; -using testing::internal::RE; - // For testing ExplainMatchResultTo(). class GreaterThanMatcher : public MatcherInterface { public: explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} virtual void DescribeTo(::std::ostream* os) const { - *os << "is greater than " << rhs_; + *os << "is > " << rhs_; } virtual bool MatchAndExplain(int lhs, @@ -757,7 +759,7 @@ TEST(GeTest, ImplementsGreaterThanOrEqual) { // Tests that Ge(v) describes itself properly. TEST(GeTest, CanDescribeSelf) { Matcher m = Ge(5); - EXPECT_EQ("is greater than or equal to 5", Describe(m)); + EXPECT_EQ("is >= 5", Describe(m)); } // Tests that Gt(v) matches anything > v. @@ -771,7 +773,7 @@ TEST(GtTest, ImplementsGreaterThan) { // Tests that Gt(v) describes itself properly. TEST(GtTest, CanDescribeSelf) { Matcher m = Gt(5); - EXPECT_EQ("is greater than 5", Describe(m)); + EXPECT_EQ("is > 5", Describe(m)); } // Tests that Le(v) matches anything <= v. @@ -785,7 +787,7 @@ TEST(LeTest, ImplementsLessThanOrEqual) { // Tests that Le(v) describes itself properly. TEST(LeTest, CanDescribeSelf) { Matcher m = Le(5); - EXPECT_EQ("is less than or equal to 5", Describe(m)); + EXPECT_EQ("is <= 5", Describe(m)); } // Tests that Lt(v) matches anything < v. @@ -799,7 +801,7 @@ TEST(LtTest, ImplementsLessThan) { // Tests that Lt(v) describes itself properly. TEST(LtTest, CanDescribeSelf) { Matcher m = Lt(5); - EXPECT_EQ("is less than 5", Describe(m)); + EXPECT_EQ("is < 5", Describe(m)); } // Tests that Ne(v) matches anything != v. @@ -813,7 +815,7 @@ TEST(NeTest, ImplementsNotEqual) { // Tests that Ne(v) describes itself properly. TEST(NeTest, CanDescribeSelf) { Matcher m = Ne(5); - EXPECT_EQ("is not equal to 5", Describe(m)); + EXPECT_EQ("isn't equal to 5", Describe(m)); } // Tests that IsNull() matches any NULL pointer of any type. @@ -876,7 +878,7 @@ TEST(IsNullTest, ReferenceToConstScopedPtr) { TEST(IsNullTest, CanDescribeSelf) { Matcher m = IsNull(); EXPECT_EQ("is NULL", Describe(m)); - EXPECT_EQ("is not NULL", DescribeNegation(m)); + EXPECT_EQ("isn't NULL", DescribeNegation(m)); } // Tests that NotNull() matches any non-NULL pointer of any type. @@ -923,7 +925,7 @@ TEST(NotNullTest, ReferenceToConstScopedPtr) { // Tests that NotNull() describes itself properly. TEST(NotNullTest, CanDescribeSelf) { Matcher m = NotNull(); - EXPECT_EQ("is not NULL", Describe(m)); + EXPECT_EQ("isn't NULL", Describe(m)); } // Tests that Ref(variable) matches an argument that references @@ -973,6 +975,16 @@ TEST(RefTest, IsCovariant) { EXPECT_FALSE(m1.Matches(base2)); } +TEST(RefTest, ExplainsResult) { + int n = 0; + EXPECT_THAT(Explain(Matcher(Ref(n)), n), + StartsWith("which is located @")); + + int m = 0; + EXPECT_THAT(Explain(Matcher(Ref(n)), m), + StartsWith("which is located @")); +} + // Tests string comparison matchers. TEST(StrEqTest, MatchesEqualString) { @@ -1013,7 +1025,7 @@ TEST(StrNeTest, MatchesUnequalString) { TEST(StrNeTest, CanDescribeSelf) { Matcher m = StrNe("Hi"); - EXPECT_EQ("is not equal to \"Hi\"", Describe(m)); + EXPECT_EQ("isn't equal to \"Hi\"", Describe(m)); } TEST(StrCaseEqTest, MatchesEqualStringIgnoringCase) { @@ -1072,7 +1084,7 @@ TEST(StrCaseNeTest, MatchesUnequalStringIgnoringCase) { TEST(StrCaseNeTest, CanDescribeSelf) { Matcher m = StrCaseNe("Hi"); - EXPECT_EQ("is not equal to (ignoring case) \"Hi\"", Describe(m)); + EXPECT_EQ("isn't equal to (ignoring case) \"Hi\"", Describe(m)); } // Tests that HasSubstr() works for matching string-typed values. @@ -1106,12 +1118,21 @@ TEST(HasSubstrTest, CanDescribeSelf) { } TEST(KeyTest, CanDescribeSelf) { - Matcher&> m = Key("foo"); + Matcher&> m = Key("foo"); EXPECT_EQ("has a key that is equal to \"foo\"", Describe(m)); + EXPECT_EQ("doesn't have a key that is equal to \"foo\"", DescribeNegation(m)); +} + +TEST(KeyTest, ExplainsResult) { + Matcher > m = Key(GreaterThan(10)); + EXPECT_EQ("whose first field is a value which is 5 less than 10", + Explain(m, make_pair(5, true))); + EXPECT_EQ("whose first field is a value which is 5 more than 10", + Explain(m, make_pair(15, true))); } TEST(KeyTest, MatchesCorrectly) { - std::pair p(25, "foo"); + pair p(25, "foo"); EXPECT_THAT(p, Key(25)); EXPECT_THAT(p, Not(Key(42))); EXPECT_THAT(p, Key(Ge(20))); @@ -1121,30 +1142,30 @@ TEST(KeyTest, MatchesCorrectly) { TEST(KeyTest, SafelyCastsInnerMatcher) { Matcher is_positive = Gt(0); Matcher is_negative = Lt(0); - std::pair p('a', true); + pair p('a', true); EXPECT_THAT(p, Key(is_positive)); EXPECT_THAT(p, Not(Key(is_negative))); } TEST(KeyTest, InsideContainsUsingMap) { std::map container; - container.insert(std::make_pair(1, 'a')); - container.insert(std::make_pair(2, 'b')); - container.insert(std::make_pair(4, 'c')); + container.insert(make_pair(1, 'a')); + container.insert(make_pair(2, 'b')); + container.insert(make_pair(4, 'c')); EXPECT_THAT(container, Contains(Key(1))); EXPECT_THAT(container, Not(Contains(Key(3)))); } TEST(KeyTest, InsideContainsUsingMultimap) { std::multimap container; - container.insert(std::make_pair(1, 'a')); - container.insert(std::make_pair(2, 'b')); - container.insert(std::make_pair(4, 'c')); + container.insert(make_pair(1, 'a')); + container.insert(make_pair(2, 'b')); + container.insert(make_pair(4, 'c')); EXPECT_THAT(container, Not(Contains(Key(25)))); - container.insert(std::make_pair(25, 'd')); + container.insert(make_pair(25, 'd')); EXPECT_THAT(container, Contains(Key(25))); - container.insert(std::make_pair(25, 'e')); + container.insert(make_pair(25, 'e')); EXPECT_THAT(container, Contains(Key(25))); EXPECT_THAT(container, Contains(Key(1))); @@ -1153,25 +1174,25 @@ TEST(KeyTest, InsideContainsUsingMultimap) { TEST(PairTest, Typing) { // Test verifies the following type conversions can be compiled. - Matcher&> m1 = Pair("foo", 42); - Matcher > m2 = Pair("foo", 42); - Matcher > m3 = Pair("foo", 42); + Matcher&> m1 = Pair("foo", 42); + Matcher > m2 = Pair("foo", 42); + Matcher > m3 = Pair("foo", 42); - Matcher > m4 = Pair(25, "42"); - Matcher > m5 = Pair("25", 42); + Matcher > m4 = Pair(25, "42"); + Matcher > m5 = Pair("25", 42); } TEST(PairTest, CanDescribeSelf) { - Matcher&> m1 = Pair("foo", 42); + Matcher&> m1 = Pair("foo", 42); EXPECT_EQ("has a first field that is equal to \"foo\"" ", and has a second field that is equal to 42", Describe(m1)); - EXPECT_EQ("has a first field that is not equal to \"foo\"" - ", or has a second field that is not equal to 42", + EXPECT_EQ("has a first field that isn't equal to \"foo\"" + ", or has a second field that isn't equal to 42", DescribeNegation(m1)); // Double and triple negation (1 or 2 times not and description of negation). - Matcher&> m2 = Not(Pair(Not(13), 42)); - EXPECT_EQ("has a first field that is not equal to 13" + Matcher&> m2 = Not(Pair(Not(13), 42)); + EXPECT_EQ("has a first field that isn't equal to 13" ", and has a second field that is equal to 42", DescribeNegation(m2)); } @@ -1179,43 +1200,43 @@ TEST(PairTest, CanDescribeSelf) { TEST(PairTest, CanExplainMatchResultTo) { // If neither field matches, Pair() should explain about the first // field. - const Matcher > m = Pair(GreaterThan(0), GreaterThan(0)); + const Matcher > m = Pair(GreaterThan(0), GreaterThan(0)); EXPECT_EQ("whose first field does not match, which is 1 less than 0", - Explain(m, std::make_pair(-1, -2))); + Explain(m, make_pair(-1, -2))); // If the first field matches but the second doesn't, Pair() should // explain about the second field. EXPECT_EQ("whose second field does not match, which is 2 less than 0", - Explain(m, std::make_pair(1, -2))); + Explain(m, make_pair(1, -2))); // If the first field doesn't match but the second does, Pair() // should explain about the first field. EXPECT_EQ("whose first field does not match, which is 1 less than 0", - Explain(m, std::make_pair(-1, 2))); + Explain(m, make_pair(-1, 2))); // If both fields match, Pair() should explain about them both. EXPECT_EQ("whose both fields match, where the first field is a value " "which is 1 more than 0, and the second field is a value " "which is 2 more than 0", - Explain(m, std::make_pair(1, 2))); + Explain(m, make_pair(1, 2))); // If only the first match has an explanation, only this explanation should // be printed. - const Matcher > explain_first = Pair(GreaterThan(0), 0); + const Matcher > explain_first = Pair(GreaterThan(0), 0); EXPECT_EQ("whose both fields match, where the first field is a value " "which is 1 more than 0", - Explain(explain_first, std::make_pair(1, 0))); + Explain(explain_first, make_pair(1, 0))); // If only the second match has an explanation, only this explanation should // be printed. - const Matcher > explain_second = Pair(0, GreaterThan(0)); + const Matcher > explain_second = Pair(0, GreaterThan(0)); EXPECT_EQ("whose both fields match, where the second field is a value " "which is 1 more than 0", - Explain(explain_second, std::make_pair(0, 1))); + Explain(explain_second, make_pair(0, 1))); } TEST(PairTest, MatchesCorrectly) { - std::pair p(25, "foo"); + pair p(25, "foo"); // Both fields match. EXPECT_THAT(p, Pair(25, "foo")); @@ -1237,7 +1258,7 @@ TEST(PairTest, MatchesCorrectly) { TEST(PairTest, SafelyCastsInnerMatchers) { Matcher is_positive = Gt(0); Matcher is_negative = Lt(0); - std::pair p('a', true); + pair p('a', true); EXPECT_THAT(p, Pair(is_positive, _)); EXPECT_THAT(p, Not(Pair(is_negative, _))); EXPECT_THAT(p, Pair(_, is_positive)); @@ -1246,9 +1267,9 @@ TEST(PairTest, SafelyCastsInnerMatchers) { TEST(PairTest, InsideContainsUsingMap) { std::map container; - container.insert(std::make_pair(1, 'a')); - container.insert(std::make_pair(2, 'b')); - container.insert(std::make_pair(4, 'c')); + container.insert(make_pair(1, 'a')); + container.insert(make_pair(2, 'b')); + container.insert(make_pair(4, 'c')); EXPECT_THAT(container, Contains(Pair(1, 'a'))); EXPECT_THAT(container, Contains(Pair(1, _))); EXPECT_THAT(container, Contains(Pair(_, 'a'))); @@ -1397,7 +1418,7 @@ TEST(StdWideStrNeTest, MatchesUnequalString) { TEST(StdWideStrNeTest, CanDescribeSelf) { Matcher m = StrNe(L"Hi"); - EXPECT_EQ("is not equal to L\"Hi\"", Describe(m)); + EXPECT_EQ("isn't equal to L\"Hi\"", Describe(m)); } TEST(StdWideStrCaseEqTest, MatchesEqualStringIgnoringCase) { @@ -1456,7 +1477,7 @@ TEST(StdWideStrCaseNeTest, MatchesUnequalStringIgnoringCase) { TEST(StdWideStrCaseNeTest, CanDescribeSelf) { Matcher m = StrCaseNe(L"Hi"); - EXPECT_EQ("is not equal to (ignoring case) L\"Hi\"", Describe(m)); + EXPECT_EQ("isn't equal to (ignoring case) L\"Hi\"", Describe(m)); } // Tests that HasSubstr() works for matching wstring-typed values. @@ -1588,7 +1609,7 @@ TEST(GlobalWideStrNeTest, MatchesUnequalString) { TEST(GlobalWideStrNeTest, CanDescribeSelf) { Matcher m = StrNe(L"Hi"); - EXPECT_EQ("is not equal to L\"Hi\"", Describe(m)); + EXPECT_EQ("isn't equal to L\"Hi\"", Describe(m)); } TEST(GlobalWideStrCaseEqTest, MatchesEqualStringIgnoringCase) { @@ -1647,7 +1668,7 @@ TEST(GlobalWideStrCaseNeTest, MatchesUnequalStringIgnoringCase) { TEST(GlobalWideStrCaseNeTest, CanDescribeSelf) { Matcher m = StrCaseNe(L"Hi"); - EXPECT_EQ("is not equal to (ignoring case) L\"Hi\"", Describe(m)); + EXPECT_EQ("isn't equal to (ignoring case) L\"Hi\"", Describe(m)); } // Tests that HasSubstr() works for matching wstring-typed values. @@ -1827,7 +1848,7 @@ TEST(NotTest, NegatesMatcher) { // Tests that Not(m) describes itself properly. TEST(NotTest, CanDescribeSelf) { Matcher m = Not(Eq(5)); - EXPECT_EQ("is not equal to 5", Describe(m)); + EXPECT_EQ("isn't equal to 5", Describe(m)); } // Tests that monomorphic matchers are safely cast by the Not matcher. @@ -1873,31 +1894,62 @@ TEST(AllOfTest, MatchesWhenAllMatch) { TEST(AllOfTest, CanDescribeSelf) { Matcher m; m = AllOf(Le(2), Ge(1)); - EXPECT_EQ("(is less than or equal to 2) and " - "(is greater than or equal to 1)", - Describe(m)); + EXPECT_EQ("(is <= 2) and (is >= 1)", Describe(m)); m = AllOf(Gt(0), Ne(1), Ne(2)); - EXPECT_EQ("(is greater than 0) and " - "((is not equal to 1) and " - "(is not equal to 2))", + EXPECT_EQ("(is > 0) and " + "((isn't equal to 1) and " + "(isn't equal to 2))", Describe(m)); m = AllOf(Gt(0), Ne(1), Ne(2), Ne(3)); - EXPECT_EQ("(is greater than 0) and " - "((is not equal to 1) and " - "((is not equal to 2) and " - "(is not equal to 3)))", + EXPECT_EQ("(is > 0) and " + "((isn't equal to 1) and " + "((isn't equal to 2) and " + "(isn't equal to 3)))", Describe(m)); m = AllOf(Ge(0), Lt(10), Ne(3), Ne(5), Ne(7)); - EXPECT_EQ("(is greater than or equal to 0) and " - "((is less than 10) and " - "((is not equal to 3) and " - "((is not equal to 5) and " - "(is not equal to 7))))", Describe(m)); + EXPECT_EQ("(is >= 0) and " + "((is < 10) and " + "((isn't equal to 3) and " + "((isn't equal to 5) and " + "(isn't equal to 7))))", + Describe(m)); +} + +// Tests that AllOf(m1, ..., mn) describes its negation properly. +TEST(AllOfTest, CanDescribeNegation) { + Matcher m; + m = AllOf(Le(2), Ge(1)); + EXPECT_EQ("(isn't <= 2) or " + "(isn't >= 1)", + DescribeNegation(m)); + + m = AllOf(Gt(0), Ne(1), Ne(2)); + EXPECT_EQ("(isn't > 0) or " + "((is equal to 1) or " + "(is equal to 2))", + DescribeNegation(m)); + + + m = AllOf(Gt(0), Ne(1), Ne(2), Ne(3)); + EXPECT_EQ("(isn't > 0) or " + "((is equal to 1) or " + "((is equal to 2) or " + "(is equal to 3)))", + DescribeNegation(m)); + + + m = AllOf(Ge(0), Lt(10), Ne(3), Ne(5), Ne(7)); + EXPECT_EQ("(isn't >= 0) or " + "((isn't < 10) or " + "((is equal to 3) or " + "((is equal to 5) or " + "(is equal to 7))))", + DescribeNegation(m)); } // Tests that monomorphic matchers are safely cast by the AllOf matcher. @@ -1915,6 +1967,49 @@ TEST(AllOfTest, AllOfMatcherSafelyCastsMonomorphicMatchers) { Matcher m5 = AllOf(greater_than_5, less_than_10, less_than_10); } +TEST(AllOfTest, ExplainsResult) { + Matcher m; + + // Successful match. Both matchers need to explain. The second + // matcher doesn't give an explanation, so only the first matcher's + // explanation is printed. + m = AllOf(GreaterThan(10), Lt(30)); + EXPECT_EQ("which is 15 more than 10", Explain(m, 25)); + + // Successful match. Both matchers need to explain. + m = AllOf(GreaterThan(10), GreaterThan(20)); + EXPECT_EQ("which is 20 more than 10, and which is 10 more than 20", + Explain(m, 30)); + + // Successful match. All matchers need to explain. The second + // matcher doesn't given an explanation. + m = AllOf(GreaterThan(10), Lt(30), GreaterThan(20)); + EXPECT_EQ("which is 15 more than 10, and which is 5 more than 20", + Explain(m, 25)); + + // Successful match. All matchers need to explain. + m = AllOf(GreaterThan(10), GreaterThan(20), GreaterThan(30)); + EXPECT_EQ("which is 30 more than 10, and which is 20 more than 20, " + "and which is 10 more than 30", + Explain(m, 40)); + + // Failed match. The first matcher, which failed, needs to + // explain. + m = AllOf(GreaterThan(10), GreaterThan(20)); + EXPECT_EQ("which is 5 less than 10", Explain(m, 5)); + + // Failed match. The second matcher, which failed, needs to + // explain. Since it doesn't given an explanation, nothing is + // printed. + m = AllOf(GreaterThan(10), Lt(30)); + EXPECT_EQ("", Explain(m, 40)); + + // Failed match. The second matcher, which failed, needs to + // explain. + m = AllOf(GreaterThan(10), GreaterThan(20)); + EXPECT_EQ("which is 5 less than 20", Explain(m, 15)); +} + // Tests that AnyOf(m1, ..., mn) matches any value that matches at // least one of the given matchers. TEST(AnyOfTest, MatchesWhenAnyMatches) { @@ -1948,31 +2043,58 @@ TEST(AnyOfTest, MatchesWhenAnyMatches) { TEST(AnyOfTest, CanDescribeSelf) { Matcher m; m = AnyOf(Le(1), Ge(3)); - EXPECT_EQ("(is less than or equal to 1) or " - "(is greater than or equal to 3)", + EXPECT_EQ("(is <= 1) or (is >= 3)", Describe(m)); m = AnyOf(Lt(0), Eq(1), Eq(2)); - EXPECT_EQ("(is less than 0) or " + EXPECT_EQ("(is < 0) or " "((is equal to 1) or (is equal to 2))", Describe(m)); m = AnyOf(Lt(0), Eq(1), Eq(2), Eq(3)); - EXPECT_EQ("(is less than 0) or " + EXPECT_EQ("(is < 0) or " "((is equal to 1) or " "((is equal to 2) or " "(is equal to 3)))", Describe(m)); m = AnyOf(Le(0), Gt(10), 3, 5, 7); - EXPECT_EQ("(is less than or equal to 0) or " - "((is greater than 10) or " + EXPECT_EQ("(is <= 0) or " + "((is > 10) or " "((is equal to 3) or " "((is equal to 5) or " "(is equal to 7))))", Describe(m)); } +// Tests that AnyOf(m1, ..., mn) describes its negation properly. +TEST(AnyOfTest, CanDescribeNegation) { + Matcher m; + m = AnyOf(Le(1), Ge(3)); + EXPECT_EQ("(isn't <= 1) and (isn't >= 3)", + DescribeNegation(m)); + + m = AnyOf(Lt(0), Eq(1), Eq(2)); + EXPECT_EQ("(isn't < 0) and " + "((isn't equal to 1) and (isn't equal to 2))", + DescribeNegation(m)); + + m = AnyOf(Lt(0), Eq(1), Eq(2), Eq(3)); + EXPECT_EQ("(isn't < 0) and " + "((isn't equal to 1) and " + "((isn't equal to 2) and " + "(isn't equal to 3)))", + DescribeNegation(m)); + + m = AnyOf(Le(0), Gt(10), 3, 5, 7); + EXPECT_EQ("(isn't <= 0) and " + "((isn't > 10) and " + "((isn't equal to 3) and " + "((isn't equal to 5) and " + "(isn't equal to 7))))", + DescribeNegation(m)); +} + // Tests that monomorphic matchers are safely cast by the AnyOf matcher. TEST(AnyOfTest, AnyOfMatcherSafelyCastsMonomorphicMatchers) { // greater_than_5 and less_than_10 are monomorphic matchers. @@ -1988,6 +2110,49 @@ TEST(AnyOfTest, AnyOfMatcherSafelyCastsMonomorphicMatchers) { Matcher m5 = AnyOf(greater_than_5, less_than_10, less_than_10); } +TEST(AnyOfTest, ExplainsResult) { + Matcher m; + + // Failed match. Both matchers need to explain. The second + // matcher doesn't give an explanation, so only the first matcher's + // explanation is printed. + m = AnyOf(GreaterThan(10), Lt(0)); + EXPECT_EQ("which is 5 less than 10", Explain(m, 5)); + + // Failed match. Both matchers need to explain. + m = AnyOf(GreaterThan(10), GreaterThan(20)); + EXPECT_EQ("which is 5 less than 10, and which is 15 less than 20", + Explain(m, 5)); + + // Failed match. All matchers need to explain. The second + // matcher doesn't given an explanation. + m = AnyOf(GreaterThan(10), Gt(20), GreaterThan(30)); + EXPECT_EQ("which is 5 less than 10, and which is 25 less than 30", + Explain(m, 5)); + + // Failed match. All matchers need to explain. + m = AnyOf(GreaterThan(10), GreaterThan(20), GreaterThan(30)); + EXPECT_EQ("which is 5 less than 10, and which is 15 less than 20, " + "and which is 25 less than 30", + Explain(m, 5)); + + // Successful match. The first matcher, which succeeded, needs to + // explain. + m = AnyOf(GreaterThan(10), GreaterThan(20)); + EXPECT_EQ("which is 5 more than 10", Explain(m, 15)); + + // Successful match. The second matcher, which succeeded, needs to + // explain. Since it doesn't given an explanation, nothing is + // printed. + m = AnyOf(GreaterThan(10), Lt(30)); + EXPECT_EQ("", Explain(m, 0)); + + // Successful match. The second matcher, which succeeded, needs to + // explain. + m = AnyOf(GreaterThan(30), GreaterThan(20)); + EXPECT_EQ("which is 5 more than 20", Explain(m, 25)); +} + // The following predicate function and predicate functor are for // testing the Truly(predicate) matcher. @@ -2181,14 +2346,13 @@ TEST(MatcherAssertionTest, WorksWhenMatcherIsNotSatisfied) { // resolved. EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Gt(10)), "Value of: n\n" - "Expected: is greater than 10\n" + "Expected: is > 10\n" " Actual: 5"); n = 0; EXPECT_NONFATAL_FAILURE( EXPECT_THAT(n, ::testing::AllOf(::testing::Le(7), ::testing::Ge(5))), "Value of: n\n" - "Expected: (is less than or equal to 7) and " - "(is greater than or equal to 5)\n" + "Expected: (is <= 7) and (is >= 5)\n" " Actual: 0"); } @@ -2205,7 +2369,7 @@ TEST(MatcherAssertionTest, WorksForByRefArguments) { "Expected: does not reference the variable @"); // Tests the "Actual" part. EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Not(::testing::Ref(n))), - "Actual: 0 (is located @"); + "Actual: 0, which is located @"); } #if !GTEST_OS_SYMBIAN @@ -2232,7 +2396,7 @@ TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { Matcher is_greater_than_5 = Gt(5); EXPECT_NONFATAL_FAILURE(EXPECT_THAT(5, is_greater_than_5), "Value of: 5\n" - "Expected: is greater than 5\n" + "Expected: is > 5\n" " Actual: 5"); } #endif // !GTEST_OS_SYMBIAN @@ -2407,11 +2571,11 @@ TEST_F(FloatTest, NanSensitiveFloatEqCanMatchNaN) { TEST_F(FloatTest, FloatEqCanDescribeSelf) { Matcher m1 = FloatEq(2.0f); EXPECT_EQ("is approximately 2", Describe(m1)); - EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + EXPECT_EQ("isn't approximately 2", DescribeNegation(m1)); Matcher m2 = FloatEq(0.5f); EXPECT_EQ("is approximately 0.5", Describe(m2)); - EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + EXPECT_EQ("isn't approximately 0.5", DescribeNegation(m2)); Matcher m3 = FloatEq(nan1_); EXPECT_EQ("never matches", Describe(m3)); @@ -2421,15 +2585,15 @@ TEST_F(FloatTest, FloatEqCanDescribeSelf) { TEST_F(FloatTest, NanSensitiveFloatEqCanDescribeSelf) { Matcher m1 = NanSensitiveFloatEq(2.0f); EXPECT_EQ("is approximately 2", Describe(m1)); - EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + EXPECT_EQ("isn't approximately 2", DescribeNegation(m1)); Matcher m2 = NanSensitiveFloatEq(0.5f); EXPECT_EQ("is approximately 0.5", Describe(m2)); - EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + EXPECT_EQ("isn't approximately 0.5", DescribeNegation(m2)); Matcher m3 = NanSensitiveFloatEq(nan1_); EXPECT_EQ("is NaN", Describe(m3)); - EXPECT_EQ("is not NaN", DescribeNegation(m3)); + EXPECT_EQ("isn't NaN", DescribeNegation(m3)); } // Instantiate FloatingPointTest for testing doubles. @@ -2462,11 +2626,11 @@ TEST_F(DoubleTest, NanSensitiveDoubleEqCanMatchNaN) { TEST_F(DoubleTest, DoubleEqCanDescribeSelf) { Matcher m1 = DoubleEq(2.0); EXPECT_EQ("is approximately 2", Describe(m1)); - EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + EXPECT_EQ("isn't approximately 2", DescribeNegation(m1)); Matcher m2 = DoubleEq(0.5); EXPECT_EQ("is approximately 0.5", Describe(m2)); - EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + EXPECT_EQ("isn't approximately 0.5", DescribeNegation(m2)); Matcher m3 = DoubleEq(nan1_); EXPECT_EQ("never matches", Describe(m3)); @@ -2476,15 +2640,15 @@ TEST_F(DoubleTest, DoubleEqCanDescribeSelf) { TEST_F(DoubleTest, NanSensitiveDoubleEqCanDescribeSelf) { Matcher m1 = NanSensitiveDoubleEq(2.0); EXPECT_EQ("is approximately 2", Describe(m1)); - EXPECT_EQ("is not approximately 2", DescribeNegation(m1)); + EXPECT_EQ("isn't approximately 2", DescribeNegation(m1)); Matcher m2 = NanSensitiveDoubleEq(0.5); EXPECT_EQ("is approximately 0.5", Describe(m2)); - EXPECT_EQ("is not approximately 0.5", DescribeNegation(m2)); + EXPECT_EQ("isn't approximately 0.5", DescribeNegation(m2)); Matcher m3 = NanSensitiveDoubleEq(nan1_); EXPECT_EQ("is NaN", Describe(m3)); - EXPECT_EQ("is not NaN", DescribeNegation(m3)); + EXPECT_EQ("isn't NaN", DescribeNegation(m3)); } TEST(PointeeTest, RawPointer) { @@ -2547,8 +2711,8 @@ TEST(PointeeTest, MatchesAgainstAValue) { TEST(PointeeTest, CanDescribeSelf) { const Matcher m = Pointee(Gt(3)); - EXPECT_EQ("points to a value that is greater than 3", Describe(m)); - EXPECT_EQ("does not point to a value that is greater than 3", + EXPECT_EQ("points to a value that is > 3", Describe(m)); + EXPECT_EQ("does not point to a value that is > 3", DescribeNegation(m)); } @@ -2693,10 +2857,8 @@ TEST(FieldTest, WorksForCompatibleMatcherType) { TEST(FieldTest, CanDescribeSelf) { Matcher m = Field(&AStruct::x, Ge(0)); - EXPECT_EQ("is an object whose given field is greater than or equal to 0", - Describe(m)); - EXPECT_EQ("is an object whose given field is not greater than or equal to 0", - DescribeNegation(m)); + EXPECT_EQ("is an object whose given field is >= 0", Describe(m)); + EXPECT_EQ("is an object whose given field isn't >= 0", DescribeNegation(m)); } // Tests that Field() can explain the match result. @@ -2764,10 +2926,8 @@ TEST(FieldForPointerTest, WorksForArgumentOfSubType) { TEST(FieldForPointerTest, CanDescribeSelf) { Matcher m = Field(&AStruct::x, Ge(0)); - EXPECT_EQ("is an object whose given field is greater than or equal to 0", - Describe(m)); - EXPECT_EQ("is an object whose given field is not greater than or equal to 0", - DescribeNegation(m)); + EXPECT_EQ("is an object whose given field is >= 0", Describe(m)); + EXPECT_EQ("is an object whose given field isn't >= 0", DescribeNegation(m)); } // Tests that Field() can explain the result of matching a pointer. @@ -2900,10 +3060,9 @@ TEST(PropertyTest, WorksForCompatibleMatcherType) { TEST(PropertyTest, CanDescribeSelf) { Matcher m = Property(&AClass::n, Ge(0)); - EXPECT_EQ("is an object whose given property is greater than or equal to 0", - Describe(m)); - EXPECT_EQ("is an object whose given property " - "is not greater than or equal to 0", DescribeNegation(m)); + EXPECT_EQ("is an object whose given property is >= 0", Describe(m)); + EXPECT_EQ("is an object whose given property isn't >= 0", + DescribeNegation(m)); } // Tests that Property() can explain the match result. @@ -2980,10 +3139,9 @@ TEST(PropertyForPointerTest, WorksForArgumentOfSubType) { TEST(PropertyForPointerTest, CanDescribeSelf) { Matcher m = Property(&AClass::n, Ge(0)); - EXPECT_EQ("is an object whose given property is greater than or equal to 0", - Describe(m)); - EXPECT_EQ("is an object whose given property " - "is not greater than or equal to 0", DescribeNegation(m)); + EXPECT_EQ("is an object whose given property is >= 0", Describe(m)); + EXPECT_EQ("is an object whose given property isn't >= 0", + DescribeNegation(m)); } // Tests that Property() can explain the result of matching a pointer. @@ -3021,7 +3179,7 @@ TEST(ResultOfTest, CanDescribeItself) { EXPECT_EQ("is mapped by the given callable to a value that " "is equal to \"foo\"", Describe(matcher)); EXPECT_EQ("is mapped by the given callable to a value that " - "is not equal to \"foo\"", DescribeNegation(matcher)); + "isn't equal to \"foo\"", DescribeNegation(matcher)); } // Tests that ResultOf() can explain the match result. @@ -3173,7 +3331,7 @@ class DivisibleByImpl { // For testing using ExplainMatchResultTo() with polymorphic matchers. template bool MatchAndExplain(const T& n, MatchResultListener* listener) const { - *listener << "is " << (n % divider_) << " modulo " + *listener << "which is " << (n % divider_) << " modulo " << divider_; return (n % divider_) == 0; } @@ -3201,28 +3359,28 @@ PolymorphicMatcher DivisibleBy(int n) { // asked to explain why. TEST(ExplainMatchResultTest, AllOf_False_False) { const Matcher m = AllOf(DivisibleBy(4), DivisibleBy(3)); - EXPECT_EQ("is 1 modulo 4", Explain(m, 5)); + EXPECT_EQ("which is 1 modulo 4", Explain(m, 5)); } // Tests that when AllOf() fails, only the first failing matcher is // asked to explain why. TEST(ExplainMatchResultTest, AllOf_False_True) { const Matcher m = AllOf(DivisibleBy(4), DivisibleBy(3)); - EXPECT_EQ("is 2 modulo 4", Explain(m, 6)); + EXPECT_EQ("which is 2 modulo 4", Explain(m, 6)); } // Tests that when AllOf() fails, only the first failing matcher is // asked to explain why. TEST(ExplainMatchResultTest, AllOf_True_False) { const Matcher m = AllOf(Ge(1), DivisibleBy(3)); - EXPECT_EQ("is 2 modulo 3", Explain(m, 5)); + EXPECT_EQ("which is 2 modulo 3", Explain(m, 5)); } // Tests that when AllOf() succeeds, all matchers are asked to explain // why. TEST(ExplainMatchResultTest, AllOf_True_True) { const Matcher m = AllOf(DivisibleBy(2), DivisibleBy(3)); - EXPECT_EQ("is 0 modulo 2; is 0 modulo 3", Explain(m, 6)); + EXPECT_EQ("which is 0 modulo 2, and which is 0 modulo 3", Explain(m, 6)); } TEST(ExplainMatchResultTest, AllOf_True_True_2) { @@ -3309,7 +3467,8 @@ TYPED_TEST(ContainerEqTest, ValueMissing) { TypeParam test_set(test_vals, test_vals + 4); const Matcher m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); - EXPECT_EQ("Not in actual: 3", Explain(m, test_set)); + EXPECT_EQ("which doesn't have these expected elements: 3", + Explain(m, test_set)); } // Tests that added values are reported. @@ -3320,7 +3479,7 @@ TYPED_TEST(ContainerEqTest, ValueAdded) { TypeParam test_set(test_vals, test_vals + 6); const Matcher m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); - EXPECT_EQ("Only in actual: 46", Explain(m, test_set)); + EXPECT_EQ("which has these unexpected elements: 46", Explain(m, test_set)); } // Tests that added and missing values are reported together. @@ -3331,7 +3490,9 @@ TYPED_TEST(ContainerEqTest, ValueAddedAndRemoved) { TypeParam test_set(test_vals, test_vals + 5); const Matcher m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); - EXPECT_EQ("Only in actual: 46; not in actual: 5", Explain(m, test_set)); + EXPECT_EQ("which has these unexpected elements: 46,\n" + "and doesn't have these expected elements: 5", + Explain(m, test_set)); } // Tests duplicated value -- expect no explanation. @@ -3356,7 +3517,8 @@ TEST(ContainerEqExtraTest, MultipleValuesMissing) { std::vector test_set(test_vals, test_vals + 3); const Matcher > m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); - EXPECT_EQ("Not in actual: 3, 8", Explain(m, test_set)); + EXPECT_EQ("which doesn't have these expected elements: 3, 8", + Explain(m, test_set)); } // Tests that added values are reported. @@ -3368,7 +3530,8 @@ TEST(ContainerEqExtraTest, MultipleValuesAdded) { std::list test_set(test_vals, test_vals + 7); const Matcher&> m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); - EXPECT_EQ("Only in actual: 92, 46", Explain(m, test_set)); + EXPECT_EQ("which has these unexpected elements: 92, 46", + Explain(m, test_set)); } // Tests that added and missing values are reported together. @@ -3379,7 +3542,8 @@ TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) { std::list test_set(test_vals, test_vals + 5); const Matcher > m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); - EXPECT_EQ("Only in actual: 92, 46; not in actual: 5, 8", + EXPECT_EQ("which has these unexpected elements: 92, 46,\n" + "and doesn't have these expected elements: 5, 8", Explain(m, test_set)); } @@ -3412,7 +3576,8 @@ TEST(ContainerEqExtraTest, WorksForMaps) { EXPECT_TRUE(m.Matches(my_map)); EXPECT_FALSE(m.Matches(test_map)); - EXPECT_EQ("Only in actual: (0, \"aa\"); not in actual: (0, \"a\")", + EXPECT_EQ("which has these unexpected elements: (0, \"aa\"),\n" + "and doesn't have these expected elements: (0, \"a\")", Explain(m, test_map)); } @@ -3795,5 +3960,29 @@ TEST(PolymorphicMatcherTest, CanAccessImpl) { EXPECT_EQ(42, impl.divider()); } +TEST(MatcherTupleTest, ExplainsMatchFailure) { + stringstream ss1; + ExplainMatchFailureTupleTo(make_tuple(Matcher(Eq('a')), GreaterThan(5)), + make_tuple('a', 10), &ss1); + EXPECT_EQ("", ss1.str()); // Successful match. + + stringstream ss2; + ExplainMatchFailureTupleTo(make_tuple(GreaterThan(5), Matcher(Eq('a'))), + make_tuple(2, 'b'), &ss2); + EXPECT_EQ(" Expected arg #0: is > 5\n" + " Actual: 2, which is 3 less than 5\n" + " Expected arg #1: is equal to 'a' (97)\n" + " Actual: 'b' (98)\n", + ss2.str()); // Failed match where both arguments need explanation. + + stringstream ss3; + ExplainMatchFailureTupleTo(make_tuple(GreaterThan(5), Matcher(Eq('a'))), + make_tuple(2, 'a'), &ss3); + EXPECT_EQ(" Expected arg #0: is > 5\n" + " Actual: 2, which is 3 less than 5\n", + ss3.str()); // Failed match where only one argument needs + // explanation. +} + } // namespace gmock_matchers_test } // namespace testing diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index ed8decac..382dc8cc 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -175,8 +175,8 @@ Google Mock tried the following 1 expectation, but it didn't match: FILE:#: EXPECT_CALL(foo_, Bar(Ref(s), _, Ge(0)))... Expected arg #0: references the variable @0x# "Hi" - Actual: "Ho" (is located @0x#) - Expected arg #2: is greater than or equal to 0 + Actual: "Ho", which is located @0x# + Expected arg #2: is >= 0 Actual: -0.1 Expected: to be called once Actual: never called - unsatisfied and active @@ -204,7 +204,7 @@ Unexpected mock function call - returning default value. Google Mock tried the following 1 expectation, but it didn't match: FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... - Expected arg #0: is greater than or equal to 2 + Expected arg #0: is >= 2 Actual: 1 Expected args: are a pair (x, y) where x >= y Actual: don't match -- cgit v1.2.3 From 439df04138a6be314be7cfe0ef670055fbf292bb Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 25 Mar 2010 20:17:31 +0000 Subject: Adds Manuel to CONTRIBUTORS, and pulls in gtest r405. --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9a8cc2e2..6e9ae362 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -19,6 +19,7 @@ Keir Mierle Keith Ray Kostya Serebryany Lev Makhlis +Manuel Klimek Mario Tanev Mark Paskin Markus Heule -- cgit v1.2.3 From aa28b178c4814cd3d56af432d11a7ea3eb16131b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 26 Mar 2010 05:38:55 +0000 Subject: Updates the release notes. --- CHANGES | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 16fc85d8..21ab4882 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,17 @@ Changes for 1.5.0: - * Support for use in multi-threaded tests on platforms having pthreads - (by virtue of the Google Test thread change) + * 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 expectation failure messages. + * 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 matching on all platforms. + * 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. -- cgit v1.2.3 From d19f58677bb1b842505b5856f43633a21e454828 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 14 Apr 2010 16:26:57 +0000 Subject: Improves Makefile.am (by Vlad Losev); fixes Makefile and updates README (by Zhanyong Wan). --- Makefile.am | 44 ++++++- README | 390 ++++++++++++++++++++++++++++++++++++---------------------- make/Makefile | 29 ++--- 3 files changed, 290 insertions(+), 173 deletions(-) diff --git a/Makefile.am b/Makefile.am index 30941d4f..8e9b61c3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -76,8 +76,18 @@ test_gmock_link_test_SOURCES = test/gmock_link_test.cc \ test/gmock_link_test.h test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la +# 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_main.cc \ + fused-src/gmock/gmock.h \ + fused-src/gtest/gtest.h \ + test/gmock_test.cc +test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src" + # Google Mock source files that we don't compile directly. -EXTRA_DIST += \ +GMOCK_SOURCE_INGLUDES = \ src/gmock.cc \ src/gmock-cardinalities.cc \ src/gmock-internal-utils.cc \ @@ -85,6 +95,8 @@ EXTRA_DIST += \ src/gmock-printers.cc \ src/gmock-spec-builders.cc +EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES) + # C++ tests that we don't compile using autotools. EXTRA_DIST += \ test/gmock_all_test.cc \ @@ -99,8 +111,7 @@ EXTRA_DIST += \ test/gmock-more-actions_test.cc \ test/gmock-nice-strict_test.cc \ test/gmock-port_test.cc \ - test/gmock-printers_test.cc \ - test/gmock_test.cc + test/gmock-printers_test.cc # Python tests, which we don't run using autotools. EXTRA_DIST += \ @@ -152,3 +163,30 @@ EXTRA_DIST += \ msvc/gmock_main.vcproj \ msvc/gmock-spec-builders_test.vcproj \ msvc/gmock_test.vcproj + +# 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" + +# Death tests may produce core dumps in the build directory. In case +# this happens, clean them to keep distcleancheck happy. +CLEANFILES = core diff --git a/README b/README index 4b3efd82..f57b254d 100644 --- a/README +++ b/README @@ -1,13 +1,16 @@ Google C++ Mocking Framework ============================ + http://code.google.com/p/googlemock/ Overview -------- -Google's framework for writing and using C++ mock classes on Linux, -Mac OS X, and Windows. Inspired by jMock, EasyMock, and Hamcrest, and -designed with C++'s specifics in mind, it can help you derive better -designs of your system and write better tests. + +Google's framework for writing and using C++ mock classes on a variety +of platforms (Linux, Mac OS X, Windows, Windows CE, Symbian, etc). +Inspired by jMock, EasyMock, and Hamcrest, and designed with C++'s +specifics in mind, it can help you derive better designs of your +system and write better tests. Google Mock: @@ -25,22 +28,23 @@ Google Mock: - does not use exceptions, and - is easy to learn and use. -Please see the project page above for more information as well as mailing lists -for questions, discussions, and development. There is also an IRC channel on -OFTC (irc.oftc.net) #gtest available. Please join us! +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/ is from the cppclean project (http://code.google.com/p/cppclean/) and under the Apache License, which is different from Google Mock's license. -Requirements ------------- -Google Mock is not a testing framework itself. Instead, it needs a -testing framework for writing tests. It works with Google Test -(http://code.google.com/p/googletest/) out of the box. You can use -either the copy of Google Test that comes with Google Mock, or a -compatible version you already have. This version of Google Mock -requires Google Test 1.4.0. +Requirements for End Users +-------------------------- + +Google Mock is implemented on top of the Google Test C++ testing +framework (http://code.google.com/p/googletest/), and includes the +latter as part of the SVN repositary and distribution package. You +must use the bundled version of Google Test when using Google Mock, or +you may get compiler/linker errors. You can also easily configure Google Mock to work with another testing framework of your choice; although it will still need Google Test as @@ -52,90 +56,186 @@ Google Mock depends on advanced C++ features and thus requires a more modern compiler. The following are needed to use Google Mock: ### Linux Requirements ### + These are the base requirements to build and use Google Mock from a source package (as described below): + * GNU-compatible Make or "gmake" * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) - * gcc 3.4 or newer. - -Furthermore, if you are building Google Mock from a VCS Checkout (also -described below), there are further requirements: - * Automake version 1.9 or newer - * Autoconf version 2.59 or newer - * Libtool / Libtoolize - * Python version 2.3 or newer + * 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 own tests from an SVN checkout (described +below), 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) + Getting the Source ------------------ -There are two primary ways of getting Google Mock's source code: you can -download a source release in your preferred archive format, or directly check -out the source from a Version Control System (VCS, we use Google Code's -Subversion hosting). The VCS checkout requires a few extra steps and some extra -software packages on your system, but lets you track development, and make -patches to contribute much more easily, so we highly encourage it. - -### VCS Checkout: ### -The first step is to select whether you want to check out the main line of -development on Google Mock, or one of the released branches. The former will be -much more active and have the latest features, but the latter provides much -more stability and predictability. Choose whichever fits your needs best, and -proceed with the following Subversion commands: - svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn +There are two primary ways of getting Google Mock's source code: you +can download a stable source release in your preferred archive format, +or directly check out the source from our Subversion (SVN) repositary. +The SVN checkout requires a few extra steps and some extra software +packages on your system, but lets you track development and make +patches much more easily, so we highly encourage it. -or for a release version X.Y.*'s branch: +### Source Package ### - svn checkout http://googlemock.googlecode.com/svn/branches/release-X.Y/ \ - gmock-X.Y-svn +Google Mock is released in versioned source packages which can be +downloaded from the download page [1]. Several different archive +formats are provided, but the only difference is the tools needed to +extract their contents, and the size of the resulting file. Download +whichever you are most comfortable with. -Next you will need to prepare the GNU Autotools build system, if you -are using Linux or Mac OS X. Enter the target directory of the -checkout command you used ('gmock-svn' or 'gmock-X.Y-svn' above) and -proceed with the following command: + [1] http://code.google.com/p/googlemock/downloads/list + +Once downloaded expand the archive using whichever tools you prefer +for that type. This will always result in a new directory with the +name "gmock-X.Y.Z" which contains all of the source code. Here are +some examples on Linux: + + tar -xvzf gmock-X.Y.Z.tar.gz + tar -xvjf gmock-X.Y.Z.tar.bz2 + unzip gmock-X.Y.Z.zip + +### SVN Checkout ### + +To check out the main branch (also known as the "trunk") of Google +Mock, run the following Subversion command: + + svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn + +If you are using a *nix system and plan to use the GNU Autotools build +system to build Google Mock (described below), you'll need to +configure it now. Otherwise you are done with getting the source +files. + +To prepare the Autotools build system, enter the target directory of +the checkout command you used ('gmock-svn') and proceed with the +following command: autoreconf -fvi -Once you have completed this step, you are ready to build the library. Note -that you should only need to complete this step once. The subsequent `make' -invocations will automatically re-generate the bits of the build system that -need to be changed. +Once you have completed this step, you are ready to build the library. +Note that you should only need to complete this step once. The +subsequent 'make' invocations will automatically re-generate the bits +of the build system that need to be changed. -If your system uses older versions of the autotools, the above command will -fail. You may need to explicitly specify a version to use. For instance, if you -have both GNU Automake 1.4 and 1.9 installed and `automake' would invoke the -1.4, use instead: +If your system uses older versions of the autotools, the above command +will fail. You may need to explicitly specify a version to use. For +instance, if you have both GNU Automake 1.4 and 1.9 installed and +'automake' would invoke the 1.4, use instead: AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi Make sure you're using the same version of automake and aclocal. -### Source Package: ### -Google Mock is also released in source packages which can be downloaded from -its Google Code download page[1]. Several different archive formats are -provided, but the only difference is the tools needed to extract their -contents, and the size of the resulting file. Download whichever you are most -comfortable with. +Setting up the Build +-------------------- - [1] Google Mock Downloads: http://code.google.com/p/googlemock/downloads/list +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. -Once downloaded expand the archive using whichever tools you prefer for that -type. This will always result in a new directory with the name "gmock-X.Y.Z" -which contains all of the source code. Here are some examples in Linux: +### Generic Build Instructions ### - tar -xvzf gmock-X.Y.Z.tar.gz - tar -xvjf gmock-X.Y.Z.tar.bz2 - unzip gmock-X.Y.Z.zip +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, ${GTEST_DIR}, ${GMOCK_DIR}/include, and ${GMOCK_DIR} + +in the header search path. Assuming a Linux-like system and gcc, +something like the following will do: + + g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -I${GMOCK_DIR}/include \ + -I${GMOCK_DIR} -c ${GTEST_DIR}/src/gtest-all.cc + g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -I${GMOCK_DIR}/include \ + -I${GMOCK_DIR} -c ${GMOCK_DIR}/src/gmock-all.cc + ar -rv libgmock.a gtest-all.o gmock-all.o + +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++ -I${GTEST_DIR}/include -I${GMOCK_DIR}/include \ + 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 to make +them go away. There are instructions in make/Makefile on how to do +it. + +### Windows ### + +The msvc/ directory contains VC++ 2005 projects for building Google +Mock and selected tests. + +Open msvc/gmock.sln and build the library and tests. 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 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. + +### Choosing a TR1 Tuple Library ### -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 @@ -146,104 +246,85 @@ 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 (this requirement is new in -Google Test 1.4.0 and Google Mock 1.2.0, so you may need to take care -of it when upgrading from an earlier version), or the two 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. +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. -Building the Source -------------------- -### Linux and Mac OS X (without Xcode) ### -There are two primary options for building the source at this point: build it -inside the source code tree, or in a separate directory. We recommend building -in a separate directory as that tends to produce both more consistent results -and be easier to clean up should anything go wrong, but both patterns are -supported. The only hard restriction is that while the build directory can be -a subdirectory of the source directory, the opposite is not possible and will -result in errors. Once you have selected where you wish to build Google Mock, -create the directory if necessary, and enter it. The following steps apply for -either approach by simply substituting the shell variable SRCDIR with "." for -building inside the source directory, and the relative path to the source -directory otherwise. - - ${SRCDIR}/configure # Standard GNU configure script, --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 +### Tweaking Google Test ### -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. +Most of Google Test's control macros apply to Google Mock as well. +Please see file ${GTEST_DIR}/README for how to tweak them. -### Windows ### -The msvc/ directory contains VC++ 2005 projects for building Google -Mock and selected tests. +Upgrading from an Earlier Version +--------------------------------- -If you want to use a version of Google Test other then the one bundled with -Google Mock, change the value of the GTestDir macro in gmock_config.vsprop -to point to the new location. +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. -Open msvc/gmock.sln and build the library and tests. 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 and select it. - * In Project Properties | Configuration Properties | General | Additional - Include Directories, type /include. +### Upgrading from 1.2.0 or Earlier ### -TODO(wan@google.com): update the .vsprops and .vcproj files such that the -last step is unnecessary. +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". -### Using GNU Make ### -The make/ directory contains a Makefile that you can use to build -Google Mock on systems where GNU make is available (e.g. Linux and Mac -OS X). It doesn't try to build Google Mock's own tests. Instead, it -just builds the Google Mock libraries and some sample tests. You can -use it as a starting point for your own Makefile. +### Upgrading from 1.4.0 or Earlier ### -If the default settings are correct for your environment, the -following commands should succeed: +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" section in file ${GTEST_DIR}/README for what +you may need to do. - cd ${SRCDIR}/make - make - ./gmock_test +If you have custom matchers defined using MatcherInterface or +MakePolymorphicMatcher(), you'll need to update their definitions to +use the new matcher API [2]. Matchers defined using MATCHER() or +MATCHER_P*() aren't affected. -If you see errors, try to tweak the contents of make/Makefile to make -them go away. There are instructions in make/Makefile on how to do -it. + [2] http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers, + http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers -### Using Your Own Build System ### -If none of the build solutions we provide works for you, or if you -prefer your own build system, you just need to compile -${GTEST_SRCDIR}/src/gtest-all.cc (where GTEST_SRCDIR is the root of -the Google Test source tree) and src/gmock-all.cc into a library and -link your tests with it. Assuming a Linux-like system and gcc, -something like the following will do: +Developing Google Mock +---------------------- - cd ${SRCDIR} - g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ - -c {GTEST_SRCDIR}/src/gtest-all.cc - g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ - -c src/gmock-all.cc - ar -rv libgmock.a gtest-all.o gmock-all.o - g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \ - path/to/your_test.cc libgmock.a -o your_test +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 in section "SVN Checkout" to configure Google Mock. +Then, create a build output directory and enter it. Next, + + ${GMOCK_DIR}/configure # Standard GNU configure script, --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. + +### Regenerating Source Files ### -Regenerating Source Files -------------------------- Some of Google Mock's source files are generated from templates (not in the C++ sense) using a script. A template file is named FOO.pump, where FOO is the name of the file it will generate. For example, the @@ -251,12 +332,21 @@ file include/gmock/gmock-generated-actions.h.pump is used to generate gmock-generated-actions.h in the same directory. Normally you don't need to worry about regenerating the source files, -unless you need to modify them (e.g. if you are working on a patch for -Google Mock). In that case, you should modify the corresponding .pump -files instead and run the 'pump' script (for Pump is Useful for Meta -Programming) to regenerate them. We are still working on releasing -the script and its documentation. If you need it now, please email -googlemock@googlegroups.com such that we know to make it happen -sooner. +unless you need to modify them. In that case, you should modify the +corresponding .pump files instead and run the 'pump' script (for Pump +is Useful for Meta Programming) to regenerate them. You can find +pump.py in the ${GTEST_DIR}/scripts/ directory. Read the Pump manual +[3] for how to use it. + + [3] http://code.google.com/p/googletest/wiki/PumpManual. + +### Contributing a Patch ### + +We welcome patches. Please read the Google Mock developer's guide [4] +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. + + [4] http://code.google.com/p/googlemock/wiki/DevGuide Happy testing! diff --git a/make/Makefile b/make/Makefile index ee0527e1..6386e5b2 100644 --- a/make/Makefile +++ b/make/Makefile @@ -27,15 +27,14 @@ GMOCK_DIR = .. USER_DIR = ../test # Flags passed to the preprocessor. -CPPFLAGS += -I$(GMOCK_DIR) -I$(GMOCK_DIR)/include \ - -I$(GTEST_DIR) -I$(GTEST_DIR)/include +CPPFLAGS += -I$(GTEST_DIR)/include -I$(GMOCK_DIR)/include # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra # All tests produced by this Makefile. Remember to add new tests you # created to the list. -TESTS = gmock_link_test gmock_test +TESTS = gmock_test # All Google Test headers. Usually you shouldn't change this # definition. @@ -73,13 +72,16 @@ GMOCK_SRCS_ = $(GMOCK_DIR)/src/*.cc $(GMOCK_HEADERS) # Google Test compile fast and for ordinary users their source rarely # changes. gtest-all.o : $(GTEST_SRCS_) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest-all.cc + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \ + -c $(GTEST_DIR)/src/gtest-all.cc gmock-all.o : $(GMOCK_SRCS_) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_DIR)/src/gmock-all.cc + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \ + -c $(GMOCK_DIR)/src/gmock-all.cc gmock_main.o : $(GMOCK_SRCS_) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_DIR)/src/gmock_main.cc + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \ + -c $(GMOCK_DIR)/src/gmock_main.cc gmock.a : gmock-all.o gtest-all.o $(AR) $(ARFLAGS) $@ $^ @@ -89,21 +91,8 @@ gmock_main.a : gmock-all.o gtest-all.o gmock_main.o # Builds a sample test. -gmock_link_test.o : $(USER_DIR)/gmock_link_test.cc \ - $(USER_DIR)/gmock_link_test.h $(GMOCK_HEADERS) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link_test.cc - -gmock_link2_test.o : $(USER_DIR)/gmock_link2_test.cc \ - $(USER_DIR)/gmock_link_test.h $(GMOCK_HEADERS) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link2_test.cc - -gmock_link_test : gmock_link_test.o gmock_link2_test.o gmock_main.a - $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ - -# Builds another sample test. - gmock_test.o : $(USER_DIR)/gmock_test.cc $(GMOCK_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_test.cc gmock_test : gmock_test.o gmock_main.a - $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ -- cgit v1.2.3 From 090c4830ddf39c0468f607f0d6b629ac6b4b0e4e Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 16 Apr 2010 16:21:17 +0000 Subject: Fixes a typo in README. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index f57b254d..8e4150aa 100644 --- a/README +++ b/README @@ -276,7 +276,7 @@ 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.2.0 or Earlier ### +### 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 -- cgit v1.2.3 From 33605ba45417979cff7254c1196dfee65a7275b3 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 22 Apr 2010 23:37:47 +0000 Subject: Adds Each(m) (by Wojtek Moczydlowski); removes scripts/test/Makefile (by Zhanyong Wan); pulls in gtest r424. --- Makefile.am | 4 +- include/gmock/gmock-matchers.h | 144 +++++++++++++++++++++++++++++++++++------ scripts/test/Makefile | 57 ---------------- test/gmock-matchers_test.cc | 102 +++++++++++++++++++++++++++-- 4 files changed, 219 insertions(+), 88 deletions(-) delete mode 100644 scripts/test/Makefile diff --git a/Makefile.am b/Makefile.am index 8e9b61c3..f0aa5c5c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,9 +137,7 @@ EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \ include/gmock/internal/gmock-generated-internal-utils.h.pump # Script for fusing Google Mock and Google Test source files. -EXTRA_DIST += \ - scripts/fuse_gmock_files.py \ - scripts/test/Makefile +EXTRA_DIST += scripts/fuse_gmock_files.py # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 66efecd4..7ca2f007 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1947,9 +1947,9 @@ class ContainerEqMatcher { GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; -// Implements Contains(element_matcher) for the given argument type Container. +// Holds the logic common to ContainsMatcherImpl and EachMatcherImpl. template -class ContainsMatcherImpl : public MatcherInterface { +class QuantifierMatcherImpl : public MatcherInterface { public: typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; typedef StlContainerView View; @@ -1958,44 +1958,97 @@ class ContainsMatcherImpl : public MatcherInterface { typedef typename StlContainer::value_type Element; template - explicit ContainsMatcherImpl(InnerMatcher inner_matcher) + explicit QuantifierMatcherImpl(InnerMatcher inner_matcher) : inner_matcher_( - testing::SafeMatcherCast(inner_matcher)) {} + testing::SafeMatcherCast(inner_matcher)) {} + + // Checks whether: + // * All elements in the container match, if all_elements_should_match. + // * Any element in the container matches, if !all_elements_should_match. + bool MatchAndExplainImpl(bool all_elements_should_match, + Container container, + MatchResultListener* listener) const { + StlContainerReference stl_container = View::ConstReference(container); + size_t i = 0; + for (typename StlContainer::const_iterator it = stl_container.begin(); + it != stl_container.end(); ++it, ++i) { + StringMatchResultListener inner_listener; + const bool matches = inner_matcher_.MatchAndExplain(*it, &inner_listener); + + if (matches != all_elements_should_match) { + *listener << "whose element #" << i + << (matches ? " matches" : " doesn't match"); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return !all_elements_should_match; + } + } + return all_elements_should_match; + } + + protected: + const Matcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(QuantifierMatcherImpl); +}; + +// Implements Contains(element_matcher) for the given argument type Container. +// Symmetric to EachMatcherImpl. +template +class ContainsMatcherImpl : public QuantifierMatcherImpl { + public: + template + explicit ContainsMatcherImpl(InnerMatcher inner_matcher) + : QuantifierMatcherImpl(inner_matcher) {} // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "contains at least one element that "; - inner_matcher_.DescribeTo(os); + this->inner_matcher_.DescribeTo(os); } - // Describes what the negation of this matcher does. virtual void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't contain any element that "; - inner_matcher_.DescribeTo(os); + this->inner_matcher_.DescribeTo(os); } virtual bool MatchAndExplain(Container container, MatchResultListener* listener) const { - StlContainerReference stl_container = View::ConstReference(container); - size_t i = 0; - for (typename StlContainer::const_iterator it = stl_container.begin(); - it != stl_container.end(); ++it, ++i) { - StringMatchResultListener inner_listener; - if (inner_matcher_.MatchAndExplain(*it, &inner_listener)) { - *listener << "whose element #" << i << " matches"; - PrintIfNotEmpty(inner_listener.str(), listener->stream()); - return true; - } - } - return false; + return this->MatchAndExplainImpl(false, container, listener); } private: - const Matcher inner_matcher_; - GTEST_DISALLOW_ASSIGN_(ContainsMatcherImpl); }; +// Implements Each(element_matcher) for the given argument type Container. +// Symmetric to ContainsMatcherImpl. +template +class EachMatcherImpl : public QuantifierMatcherImpl { + public: + template + explicit EachMatcherImpl(InnerMatcher inner_matcher) + : QuantifierMatcherImpl(inner_matcher) {} + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "only contains elements that "; + this->inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "contains some element that "; + this->inner_matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { + return this->MatchAndExplainImpl(true, container, listener); + } + + private: + GTEST_DISALLOW_ASSIGN_(EachMatcherImpl); +}; + // Implements polymorphic Contains(element_matcher). template class ContainsMatcher { @@ -2013,6 +2066,23 @@ class ContainsMatcher { GTEST_DISALLOW_ASSIGN_(ContainsMatcher); }; +// Implements polymorphic Each(element_matcher). +template +class EachMatcher { + public: + explicit EachMatcher(M m) : inner_matcher_(m) {} + + template + operator Matcher() const { + return MakeMatcher(new EachMatcherImpl(inner_matcher_)); + } + + private: + const M inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(EachMatcher); +}; + // Implements Key(inner_matcher) for the given argument pair type. // Key(inner_matcher) matches an std::pair whose 'first' field matches // inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an @@ -2855,6 +2925,38 @@ inline internal::ContainsMatcher Contains(M matcher) { return internal::ContainsMatcher(matcher); } +// Matches an STL-style container or a native array that contains only +// elements matching the given value or matcher. +// +// Each(m) is semantically equivalent to Not(Contains(Not(m))). Only +// the messages are different. +// +// Examples: +// ::std::set page_ids; +// // Each(m) matches an empty container, regardless of what m is. +// EXPECT_THAT(page_ids, Each(Eq(1))); +// EXPECT_THAT(page_ids, Each(Eq(77))); +// +// page_ids.insert(3); +// EXPECT_THAT(page_ids, Each(Gt(0))); +// EXPECT_THAT(page_ids, Not(Each(Gt(4)))); +// page_ids.insert(1); +// EXPECT_THAT(page_ids, Not(Each(Lt(2)))); +// +// ::std::map page_lengths; +// page_lengths[1] = 100; +// page_lengths[2] = 200; +// page_lengths[3] = 300; +// EXPECT_THAT(page_lengths, Not(Each(Pair(1, 100)))); +// EXPECT_THAT(page_lengths, Each(Key(Le(3)))); +// +// const char* user_ids[] = { "joe", "mike", "tom" }; +// EXPECT_THAT(user_ids, Not(Each(Eq(::std::string("tom"))))); +template +inline internal::EachMatcher Each(M matcher) { + return internal::EachMatcher(matcher); +} + // Key(inner_matcher) matches an std::pair whose 'first' field matches // inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an // std::map that contains at least one element whose key is >= 5. diff --git a/scripts/test/Makefile b/scripts/test/Makefile deleted file mode 100644 index 8edaea06..00000000 --- a/scripts/test/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# A Makefile for fusing Google Mock and building a sample test against it. -# -# SYNOPSIS: -# -# make [all] - makes everything. -# make TARGET - makes the given target. -# make check - makes everything and runs the built sample test. -# make clean - removes all files generated by make. - -# Points to the root of fused Google Mock, relative to where this file is. -FUSED_GMOCK_DIR = output - -# Paths to the fused gmock files. -FUSED_GTEST_H = $(FUSED_GMOCK_DIR)/gtest/gtest.h -FUSED_GMOCK_H = $(FUSED_GMOCK_DIR)/gmock/gmock.h -FUSED_GMOCK_GTEST_ALL_CC = $(FUSED_GMOCK_DIR)/gmock-gtest-all.cc - -# Where to find the gmock_test.cc. -GMOCK_TEST_CC = ../../test/gmock_test.cc - -# Where to find gmock_main.cc. -GMOCK_MAIN_CC = ../../src/gmock_main.cc - -# Flags passed to the preprocessor. -CPPFLAGS += -I$(FUSED_GMOCK_DIR) - -# Flags passed to the C++ compiler. -CXXFLAGS += -g - -all : gmock_test - -check : all - ./gmock_test - -clean : - rm -rf $(FUSED_GMOCK_DIR) gmock_test *.o - -$(FUSED_GTEST_H) : - ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) - -$(FUSED_GMOCK_H) : - ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) - -$(FUSED_GMOCK_GTEST_ALL_CC) : - ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) - -gmock-gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(FUSED_GMOCK_GTEST_ALL_CC) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GMOCK_GTEST_ALL_CC) - -gmock_main.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_MAIN_CC) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_MAIN_CC) - -gmock_test.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_TEST_CC) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_TEST_CC) - -gmock_test : gmock_test.o gmock-gtest-all.o gmock_main.o - $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 6d784f16..a7c217d4 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -65,8 +65,10 @@ using std::make_pair; using std::map; using std::multimap; using std::pair; +using std::set; using std::stringstream; using std::tr1::make_tuple; +using std::vector; using testing::A; using testing::AllArgs; using testing::AllOf; @@ -363,20 +365,20 @@ TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) { // Tests that MakePolymorphicMatcher() can construct a polymorphic // matcher from its implementation using the old API. -const int bar = 1; +const int g_bar = 1; class ReferencesBarOrIsZeroImpl { public: template bool MatchAndExplain(const T& x, MatchResultListener* /* listener */) const { const void* p = &x; - return p == &bar || x == 0; + return p == &g_bar || x == 0; } - void DescribeTo(::std::ostream* os) const { *os << "bar or zero"; } + void DescribeTo(::std::ostream* os) const { *os << "g_bar or zero"; } void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't reference bar and is not zero"; + *os << "doesn't reference g_bar and is not zero"; } }; @@ -391,15 +393,15 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) { Matcher m1 = ReferencesBarOrIsZero(); EXPECT_TRUE(m1.Matches(0)); // Verifies that the identity of a by-reference argument is preserved. - EXPECT_TRUE(m1.Matches(bar)); + EXPECT_TRUE(m1.Matches(g_bar)); EXPECT_FALSE(m1.Matches(1)); - EXPECT_EQ("bar or zero", Describe(m1)); + EXPECT_EQ("g_bar or zero", Describe(m1)); // Using a polymorphic matcher to match a value type. Matcher m2 = ReferencesBarOrIsZero(); EXPECT_TRUE(m2.Matches(0.0)); EXPECT_FALSE(m2.Matches(0.1)); - EXPECT_EQ("bar or zero", Describe(m2)); + EXPECT_EQ("g_bar or zero", Describe(m2)); } // Tests implementing a polymorphic matcher using MatchAndExplain(). @@ -3984,5 +3986,91 @@ TEST(MatcherTupleTest, ExplainsMatchFailure) { // explanation. } +// Tests Each(). + +TEST(EachTest, ExplainsMatchResultCorrectly) { + set a; // empty + + Matcher > m = Each(2); + EXPECT_EQ("", Explain(m, a)); + + Matcher n = Each(1); + + const int b[1] = { 1 }; + EXPECT_EQ("", Explain(n, b)); + + n = Each(3); + EXPECT_EQ("whose element #0 doesn't match", Explain(n, b)); + + a.insert(1); + a.insert(2); + a.insert(3); + m = Each(GreaterThan(0)); + EXPECT_EQ("", Explain(m, a)); + + m = Each(GreaterThan(10)); + EXPECT_EQ("whose element #0 doesn't match, which is 9 less than 10", + Explain(m, a)); +} + +TEST(EachTest, DescribesItselfCorrectly) { + Matcher > m = Each(1); + EXPECT_EQ("only contains elements that is equal to 1", Describe(m)); + + Matcher > m2 = Not(m); + EXPECT_EQ("contains some element that isn't equal to 1", Describe(m2)); +} + +TEST(EachTest, MatchesVectorWhenAllElementsMatch) { + vector some_vector; + EXPECT_THAT(some_vector, Each(1)); + some_vector.push_back(3); + EXPECT_THAT(some_vector, Not(Each(1))); + EXPECT_THAT(some_vector, Each(3)); + some_vector.push_back(1); + some_vector.push_back(2); + EXPECT_THAT(some_vector, Not(Each(3))); + EXPECT_THAT(some_vector, Each(Lt(3.5))); + + vector another_vector; + another_vector.push_back("fee"); + EXPECT_THAT(another_vector, Each(string("fee"))); + another_vector.push_back("fie"); + another_vector.push_back("foe"); + another_vector.push_back("fum"); + EXPECT_THAT(another_vector, Not(Each(string("fee")))); +} + +TEST(EachTest, MatchesMapWhenAllElementsMatch) { + map my_map; + const char* bar = "a string"; + my_map[bar] = 2; + EXPECT_THAT(my_map, Each(make_pair(bar, 2))); + + map another_map; + EXPECT_THAT(another_map, Each(make_pair(string("fee"), 1))); + another_map["fee"] = 1; + EXPECT_THAT(another_map, Each(make_pair(string("fee"), 1))); + another_map["fie"] = 2; + another_map["foe"] = 3; + another_map["fum"] = 4; + EXPECT_THAT(another_map, Not(Each(make_pair(string("fee"), 1)))); + EXPECT_THAT(another_map, Not(Each(make_pair(string("fum"), 1)))); + EXPECT_THAT(another_map, Each(Pair(_, Gt(0)))); +} + +TEST(EachTest, AcceptsMatcher) { + const int a[] = { 1, 2, 3 }; + EXPECT_THAT(a, Each(Gt(0))); + EXPECT_THAT(a, Not(Each(Gt(1)))); +} + +TEST(EachTest, WorksForNativeArrayAsTuple) { + const int a[] = { 1, 2 }; + const int* const pointer = a; + EXPECT_THAT(make_tuple(pointer, 2), Each(Gt(0))); + EXPECT_THAT(make_tuple(pointer, 2), Not(Each(Gt(1)))); +} + } // namespace gmock_matchers_test } // namespace testing -- cgit v1.2.3 From 54af9ba50a8ce03a4463faf45a61b47bdf79fefd Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 4 May 2010 16:05:11 +0000 Subject: Adds a synchronization test. --- test/gmock-spec-builders_test.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index e5fc2ec9..e22d8cf7 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -2358,9 +2358,23 @@ TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) { // action or as a default action without causing a dead lock. It // verifies that the action is not performed inside the critical // section. +TEST(SynchronizationTest, CanCallMockMethodInAction) { + MockA a; + MockC c; + ON_CALL(a, DoA(_)) + .WillByDefault(IgnoreResult(InvokeWithoutArgs(&c, + &MockC::NonVoidMethod))); + EXPECT_CALL(a, DoA(1)); + EXPECT_CALL(a, DoA(1)) + .WillOnce(Invoke(&a, &MockA::DoA)) + .RetiresOnSaturation(); + EXPECT_CALL(c, NonVoidMethod()); -void Helper(MockC* c) { - c->NonVoidMethod(); + a.DoA(1); + // This will match the second EXPECT_CALL() and trigger another a.DoA(1), + // which will in turn match the first EXPECT_CALL() and trigger a call to + // c.NonVoidMethod() that was specified by the ON_CALL() since the first + // EXPECT_CALL() did not specify an action. } } // namespace -- cgit v1.2.3 From 76c1c612e23d87874669faf0b1c8f74caa4a7eb4 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 5 May 2010 19:47:46 +0000 Subject: Fixes tests leaking altered values of GMOCK_FLAG(verbose) (issue 110). --- test/gmock-internal-utils_test.cc | 2 ++ test/gmock-nice-strict_test.cc | 2 ++ test/gmock-spec-builders_test.cc | 36 +++++++++++++++++++++--------------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index fc5d9e55..b8e05191 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -565,10 +565,12 @@ void TestLogWithSeverity(const string& verbosity, LogSeverity severity, // Tests that when the stack_frames_to_skip parameter is negative, // Log() doesn't include the stack trace in the output. TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { + const string saved_flag = GMOCK_FLAG(verbose); GMOCK_FLAG(verbose) = kInfoVerbosity; CaptureStdout(); Log(INFO, "Test log.\n", -1); EXPECT_STREQ("\nTest log.\n", GetCapturedStdout().c_str()); + GMOCK_FLAG(verbose) = saved_flag; } // Tests that in opt mode, a positive stack_frames_to_skip argument is diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index f6f278e8..0e52450d 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -137,6 +137,7 @@ TEST(NiceMockTest, NoWarningForUninterestingCallAfterDeath) { TEST(NiceMockTest, InfoForUninterestingCall) { NiceMock nice_foo; + const string saved_flag = GMOCK_FLAG(verbose); GMOCK_FLAG(verbose) = "info"; CaptureStdout(); nice_foo.DoThis(); @@ -147,6 +148,7 @@ TEST(NiceMockTest, InfoForUninterestingCall) { nice_foo.DoThat(true); EXPECT_THAT(GetCapturedStdout(), HasSubstr("Uninteresting mock function call")); + GMOCK_FLAG(verbose) = saved_flag; } #endif // GTEST_HAS_STREAM_REDIRECTION_ diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index e22d8cf7..ff30f02b 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1783,6 +1783,25 @@ class MockC { GTEST_DISALLOW_COPY_AND_ASSIGN_(MockC); }; +class VerboseFlagPreservingFixture : public testing::Test { + protected: + // The code needs to work when both ::string and ::std::string are defined + // and the flag is implemented as a testing::internal::String. In this + // case, without the call to c_str(), the compiler will complain that it + // cannot figure out what overload of string constructor to use. + // TODO(vladl@google.com): Use internal::string instead of String for + // string flags in Google Test. + VerboseFlagPreservingFixture() + : saved_verbose_flag_(GMOCK_FLAG(verbose).c_str()) {} + + ~VerboseFlagPreservingFixture() { GMOCK_FLAG(verbose) = saved_verbose_flag_; } + + private: + const string saved_verbose_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(VerboseFlagPreservingFixture); +}; + #if GTEST_HAS_STREAM_REDIRECTION_ // Tests that an uninteresting mock function call generates a warning @@ -1842,7 +1861,7 @@ TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { // Tests how the --gmock_verbose flag affects Google Mock's output. -class GMockVerboseFlagTest : public testing::Test { +class GMockVerboseFlagTest : public VerboseFlagPreservingFixture { public: // Verifies that the given Google Mock output is correct. (When // should_print is true, the output should match the given regex and @@ -1982,22 +2001,9 @@ class LogTestHelper { GTEST_DISALLOW_COPY_AND_ASSIGN_(LogTestHelper); }; -class GMockLogTest : public ::testing::Test { +class GMockLogTest : public VerboseFlagPreservingFixture { protected: - virtual void SetUp() { - // The code needs to work when both ::string and ::std::string are - // defined and the flag is implemented as a - // testing::internal::String. In this case, without the call to - // c_str(), the compiler will complain that it cannot figure out - // whether the String flag should be converted to a ::string or an - // ::std::string before being assigned to original_verbose_. - original_verbose_ = GMOCK_FLAG(verbose).c_str(); - } - - virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; } - LogTestHelper helper_; - string original_verbose_; }; TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsWarning) { -- cgit v1.2.3 From 02f7106557fde1f1075dc53d65ef1f7a11851f93 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 10 May 2010 17:14:29 +0000 Subject: Moves the universal printer from gmock to gtest (by Vlad Losev). --- Makefile.am | 5 +- include/gmock/gmock-actions.h | 9 +- include/gmock/gmock-generated-function-mockers.h | 22 +- .../gmock/gmock-generated-function-mockers.h.pump | 2 +- include/gmock/gmock-generated-matchers.h | 23 +- include/gmock/gmock-generated-matchers.h.pump | 5 +- include/gmock/gmock-matchers.h | 49 +- include/gmock/gmock-more-actions.h | 2 +- include/gmock/gmock-printers.h | 725 ------------- include/gmock/gmock-spec-builders.h | 1 - include/gmock/gmock.h | 1 - include/gmock/internal/gmock-internal-utils.h | 296 +----- include/gmock/internal/gmock-port.h | 137 --- scons/SConscript | 1 - scripts/gmock_doctor.py | 2 +- src/gmock-all.cc | 1 - src/gmock-printers.cc | 318 ------ test/gmock-actions_test.cc | 8 +- test/gmock-internal-utils_test.cc | 309 +----- test/gmock-port_test.cc | 123 +-- test/gmock-printers_test.cc | 1118 -------------------- test/gmock_all_test.cc | 1 - 22 files changed, 66 insertions(+), 3092 deletions(-) delete mode 100644 include/gmock/gmock-printers.h delete mode 100644 src/gmock-printers.cc delete mode 100644 test/gmock-printers_test.cc diff --git a/Makefile.am b/Makefile.am index f0aa5c5c..e2a46730 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,6 @@ pkginclude_HEADERS = include/gmock/gmock.h \ include/gmock/gmock-generated-nice-strict.h \ include/gmock/gmock-matchers.h \ include/gmock/gmock-more-actions.h \ - include/gmock/gmock-printers.h \ include/gmock/gmock-spec-builders.h pkginclude_internaldir = $(pkgincludedir)/internal @@ -92,7 +91,6 @@ GMOCK_SOURCE_INGLUDES = \ src/gmock-cardinalities.cc \ src/gmock-internal-utils.cc \ src/gmock-matchers.cc \ - src/gmock-printers.cc \ src/gmock-spec-builders.cc EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES) @@ -110,8 +108,7 @@ EXTRA_DIST += \ test/gmock-matchers_test.cc \ test/gmock-more-actions_test.cc \ test/gmock-nice-strict_test.cc \ - test/gmock-port_test.cc \ - test/gmock-printers_test.cc + test/gmock-port_test.cc # Python tests, which we don't run using autotools. EXTRA_DIST += \ diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 007ad9d3..9fe19644 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -43,7 +43,6 @@ #include #endif -#include #include #include @@ -477,7 +476,7 @@ class ReturnAction { // 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; - GMOCK_COMPILE_ASSERT_( + GTEST_COMPILE_ASSERT_( !internal::is_reference::value, use_ReturnRef_instead_of_Return_to_return_a_reference); return Action(new Impl(value_)); @@ -504,7 +503,7 @@ class ReturnAction { virtual Result Perform(const ArgumentTuple&) { return value_; } private: - GMOCK_COMPILE_ASSERT_(!internal::is_reference::value, + GTEST_COMPILE_ASSERT_(!internal::is_reference::value, Result_cannot_be_a_reference_type); Result value_; @@ -522,7 +521,7 @@ class ReturnNullAction { // Allows ReturnNull() to be used in any pointer-returning function. template static Result Perform(const ArgumentTuple&) { - GMOCK_COMPILE_ASSERT_(internal::is_pointer::value, + GTEST_COMPILE_ASSERT_(internal::is_pointer::value, ReturnNull_can_be_used_to_return_a_pointer_only); return NULL; } @@ -555,7 +554,7 @@ class ReturnRefAction { // 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. - GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + GTEST_COMPILE_ASSERT_(internal::is_reference::value, use_Return_instead_of_ReturnRef_to_return_a_value); return Action(new Impl(ref_)); } diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 3b2ede1e..58be7e19 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -344,7 +344,7 @@ using internal::FunctionMocker; // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD0_(tn, constness, ct, Method, F) \ GMOCK_RESULT_(tn, F) ct Method() constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 0, \ this_method_does_not_take_0_arguments); \ GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \ @@ -359,7 +359,7 @@ using internal::FunctionMocker; // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD1_(tn, constness, ct, Method, F) \ GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 1, \ this_method_does_not_take_1_argument); \ GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \ @@ -376,7 +376,7 @@ using internal::FunctionMocker; #define GMOCK_METHOD2_(tn, constness, ct, Method, F) \ GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ GMOCK_ARG_(tn, F, 2) gmock_a2) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 2, \ this_method_does_not_take_2_arguments); \ GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \ @@ -395,7 +395,7 @@ using internal::FunctionMocker; GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ GMOCK_ARG_(tn, F, 2) gmock_a2, \ GMOCK_ARG_(tn, F, 3) gmock_a3) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 3, \ this_method_does_not_take_3_arguments); \ GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \ @@ -417,7 +417,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 2) gmock_a2, \ GMOCK_ARG_(tn, F, 3) gmock_a3, \ GMOCK_ARG_(tn, F, 4) gmock_a4) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 4, \ this_method_does_not_take_4_arguments); \ GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \ @@ -442,7 +442,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 3) gmock_a3, \ GMOCK_ARG_(tn, F, 4) gmock_a4, \ GMOCK_ARG_(tn, F, 5) gmock_a5) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 5, \ this_method_does_not_take_5_arguments); \ GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \ @@ -469,7 +469,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 4) gmock_a4, \ GMOCK_ARG_(tn, F, 5) gmock_a5, \ GMOCK_ARG_(tn, F, 6) gmock_a6) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 6, \ this_method_does_not_take_6_arguments); \ GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \ @@ -498,7 +498,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 5) gmock_a5, \ GMOCK_ARG_(tn, F, 6) gmock_a6, \ GMOCK_ARG_(tn, F, 7) gmock_a7) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 7, \ this_method_does_not_take_7_arguments); \ GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \ @@ -529,7 +529,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 6) gmock_a6, \ GMOCK_ARG_(tn, F, 7) gmock_a7, \ GMOCK_ARG_(tn, F, 8) gmock_a8) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 8, \ this_method_does_not_take_8_arguments); \ GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \ @@ -562,7 +562,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 7) gmock_a7, \ GMOCK_ARG_(tn, F, 8) gmock_a8, \ GMOCK_ARG_(tn, F, 9) gmock_a9) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 9, \ this_method_does_not_take_9_arguments); \ GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \ @@ -598,7 +598,7 @@ using internal::FunctionMocker; GMOCK_ARG_(tn, F, 8) gmock_a8, \ GMOCK_ARG_(tn, F, 9) gmock_a9, \ GMOCK_ARG_(tn, F, 10) gmock_a10) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == 10, \ this_method_does_not_take_10_arguments); \ GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \ diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 619debd2..20a44541 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -132,7 +132,7 @@ $var matcher_as = [[$for j, \ // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, F) \ GMOCK_RESULT_(tn, F) ct Method($arg_as) constness { \ - GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \ + GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ tn ::testing::internal::Function::ArgumentTuple>::value == $i, \ this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \ diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 9e5bedea..90f3750e 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -42,7 +42,6 @@ #include #include #include -#include namespace testing { namespace internal { @@ -222,7 +221,7 @@ template { public: // ArgsTuple may have top-level const or reference modifiers. - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; @@ -315,7 +314,7 @@ class ElementsAreMatcher1 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -344,7 +343,7 @@ class ElementsAreMatcher2 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -372,7 +371,7 @@ class ElementsAreMatcher3 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -402,7 +401,7 @@ class ElementsAreMatcher4 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -434,7 +433,7 @@ class ElementsAreMatcher5 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -470,7 +469,7 @@ class ElementsAreMatcher6 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -508,7 +507,7 @@ class ElementsAreMatcher7 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -548,7 +547,7 @@ class ElementsAreMatcher8 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -591,7 +590,7 @@ class ElementsAreMatcher9 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -636,7 +635,7 @@ class ElementsAreMatcher10 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 07a51a36..2f325b04 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -44,7 +44,6 @@ $$ }} This line fixes auto-indentation of the following code in Emacs. #include #include #include -#include namespace testing { namespace internal { @@ -108,7 +107,7 @@ template class ArgsMatcherImpl : public MatcherInterface { public: // ArgsTuple may have top-level const or reference modifiers. - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; @@ -201,7 +200,7 @@ class ElementsAreMatcher$i { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 7ca2f007..fbbf5811 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -45,7 +45,6 @@ #include #include -#include #include #include #include @@ -419,20 +418,20 @@ class SafeMatcherCastImpl { template static inline Matcher Cast(const Matcher& matcher) { // Enforce that T can be implicitly converted to U. - GMOCK_COMPILE_ASSERT_((internal::ImplicitlyConvertible::value), + 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. - GMOCK_COMPILE_ASSERT_( + 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 GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT; - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) RawT; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(U)) RawU; const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; - GMOCK_COMPILE_ASSERT_( + GTEST_COMPILE_ASSERT_( kTIsOther || kUIsOther || (internal::LosslessArithmeticConvertible::value), conversion_of_arithmetic_types_must_be_lossless); @@ -566,7 +565,7 @@ bool TupleMatches(const MatcherTuple& matcher_tuple, using ::std::tr1::tuple_size; // Makes sure that matcher_tuple and value_tuple have the same // number of fields. - GMOCK_COMPILE_ASSERT_(tuple_size::value == + GTEST_COMPILE_ASSERT_(tuple_size::value == tuple_size::value, matcher_and_value_have_different_numbers_of_fields); return TuplePrefix::value>:: @@ -1604,8 +1603,8 @@ class PointeeMatcher { template class Impl : public MatcherInterface { public: - typedef typename PointeeOf::type Pointee; + typedef typename PointeeOf::type Pointee; explicit Impl(const InnerMatcher& matcher) : matcher_(MatcherCast(matcher)) {} @@ -1663,7 +1662,7 @@ class FieldMatcher { bool MatchAndExplain(const T& value, MatchResultListener* listener) const { return MatchAndExplainImpl( typename ::testing::internal:: - is_pointer::type(), + is_pointer::type(), value, listener); } @@ -1702,9 +1701,9 @@ class PropertyMatcher { public: // The property may have a reference type, so 'const PropertyType&' // may cause double references and fail to compile. That's why we - // need GMOCK_REFERENCE_TO_CONST, which works regardless of + // need GTEST_REFERENCE_TO_CONST, which works regardless of // PropertyType being a reference or not. - typedef GMOCK_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty; + typedef GTEST_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty; PropertyMatcher(PropertyType (Class::*property)() const, const Matcher& matcher) @@ -1724,7 +1723,7 @@ class PropertyMatcher { bool MatchAndExplain(const T&value, MatchResultListener* listener) const { return MatchAndExplainImpl( typename ::testing::internal:: - is_pointer::type(), + is_pointer::type(), value, listener); } @@ -1875,7 +1874,7 @@ class ContainerEqMatcher { // Makes sure the user doesn't instantiate this class template // with a const or reference type. testing::StaticAssertTypeEq(); + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container))>(); } void DescribeTo(::std::ostream* os) const { @@ -1890,9 +1889,9 @@ class ContainerEqMatcher { template bool MatchAndExplain(const LhsContainer& lhs, MatchResultListener* listener) const { - // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug + // GTEST_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug // that causes LhsContainer to be a const type sometimes. - typedef internal::StlContainerView + typedef internal::StlContainerView LhsView; typedef typename LhsView::type LhsStlContainer; StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); @@ -1951,7 +1950,7 @@ class ContainerEqMatcher { template class QuantifierMatcherImpl : public MatcherInterface { public: - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; @@ -2090,7 +2089,7 @@ class EachMatcher { template class KeyMatcherImpl : public MatcherInterface { public: - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(PairType)) RawPairType; typedef typename RawPairType::first_type KeyType; template @@ -2152,7 +2151,7 @@ class KeyMatcher { template class PairMatcherImpl : public MatcherInterface { public: - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(PairType)) RawPairType; typedef typename RawPairType::first_type FirstType; typedef typename RawPairType::second_type SecondType; @@ -2259,7 +2258,7 @@ class PairMatcher { template class ElementsAreMatcherImpl : public MatcherInterface { public: - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef internal::StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; @@ -2378,7 +2377,7 @@ class ElementsAreMatcher0 { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -2397,7 +2396,7 @@ class ElementsAreArrayMatcher { template operator Matcher() const { - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) + typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -2609,7 +2608,7 @@ inline PolymorphicMatcher< return MakePolymorphicMatcher( internal::PropertyMatcher( property, - MatcherCast(matcher))); + MatcherCast(matcher))); // The call to MatcherCast() is required for supporting inner // matchers of compatible types. For example, it allows // Property(&Foo::bar, m) @@ -2893,11 +2892,11 @@ Truly(Predicate pred) { // values and order differences are not explained.) template inline PolymorphicMatcher > + GTEST_REMOVE_CONST_(Container)> > ContainerEq(const Container& rhs) { // This following line is for working around a bug in MSVC 8.0, // which causes Container to be a const type sometimes. - typedef GMOCK_REMOVE_CONST_(Container) RawContainer; + typedef GTEST_REMOVE_CONST_(Container) RawContainer; return MakePolymorphicMatcher( internal::ContainerEqMatcher(rhs)); } diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index 6226392d..9a6fe969 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -162,7 +162,7 @@ ACTION_TEMPLATE(SetArgReferee, // Ensures that argument #k is a reference. If you get a compiler // error on the next line, you are using SetArgReferee(value) in // a mock function whose k-th (0-based) argument is not a reference. - GMOCK_COMPILE_ASSERT_(internal::is_reference::value, + GTEST_COMPILE_ASSERT_(internal::is_reference::value, SetArgReferee_must_be_used_with_a_reference_argument); ::std::tr1::get(args) = value; } diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h deleted file mode 100644 index d1cd03ca..00000000 --- a/include/gmock/gmock-printers.h +++ /dev/null @@ -1,725 +0,0 @@ -// 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 a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// A user can teach this function how to print a class type T by -// defining either operator<<() or PrintTo() in the namespace that -// defines T. More specifically, the FIRST defined function in the -// following list will be used (assuming T is defined in namespace -// foo): -// -// 1. foo::PrintTo(const T&, ostream*) -// 2. operator<<(ostream&, const T&) defined in either foo or the -// global namespace. -// -// If none of the above is defined, it will print the debug string of -// the value if it is a protocol buffer, or print the raw bytes in the -// value otherwise. -// -// To aid debugging: when T is a reference type, the address of the -// value is also printed; when T is a (const) char pointer, both the -// pointer value and the NUL-terminated string it points to are -// printed. -// -// We also provide some convenient wrappers: -// -// // Prints a value to a string. For a (const or not) char -// // pointer, the NUL-terminated string (but not the pointer) is -// // printed. -// std::string ::testing::PrintToString(const T& value); -// -// // Prints a value tersely: for a reference type, the referenced -// // value (but not the address) is printed; for a (const or not) char -// // pointer, the NUL-terminated string (but not the pointer) is -// // printed. -// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); -// -// // Prints value using the type inferred by the compiler. The difference -// // from UniversalTersePrint() is that this function prints both the -// // pointer and the NUL-terminated string for a (const or not) char pointer. -// void ::testing::internal::UniversalPrint(const T& value, ostream*); -// -// // Prints the fields of a tuple tersely to a string vector, one -// // element for each field. -// std::vector UniversalTersePrintTupleFieldsToStrings( -// const Tuple& value); -// -// Known limitation: -// -// The print primitives print the elements of an STL-style container -// using the compiler-inferred type of *iter where iter is a -// const_iterator of the container. When const_iterator is an input -// iterator but not a forward iterator, this inferred type may not -// match value_type, and the print output may be incorrect. In -// practice, this is rarely a problem as for most containers -// const_iterator is a forward iterator. We'll fix this if there's an -// actual need for it. Note that this fix cannot rely on value_type -// being defined as many user-defined container types don't have -// value_type. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ - -#include // NOLINT -#include -#include -#include -#include - -#include -#include -#include - -namespace testing { - -// Definitions in the 'internal' and 'internal2' name spaces are -// subject to change without notice. DO NOT USE THEM IN USER CODE! -namespace internal2 { - -// Prints the given number of bytes in the given object to the given -// ostream. -void PrintBytesInObjectTo(const unsigned char* obj_bytes, - size_t count, - ::std::ostream* os); - -// TypeWithoutFormatter::PrintValue(value, os) is called -// by the universal printer to print a value of type T when neither -// operator<< nor PrintTo() is defined for type T. When T is -// ProtocolMessage, proto2::Message, or a subclass of those, kIsProto -// will be true and the short debug string of the protocol message -// value will be printed; otherwise kIsProto will be false and the -// bytes in the value will be printed. -template -class TypeWithoutFormatter { - public: - static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), - sizeof(value), os); - } -}; - -// We print a protobuf using its ShortDebugString() when the string -// doesn't exceed this many characters; otherwise we print it using -// DebugString() for better readability. -const size_t kProtobufOneLinerMaxLength = 50; - -template -class TypeWithoutFormatter { - public: - static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); - ::std::operator<<(*os, "<" + pretty_str + ">"); - } -}; - -// Prints the given value to the given ostream. If the value is a -// protocol message, its short debug string is printed; otherwise the -// bytes in the value are printed. This is what -// UniversalPrinter::Print() does when it knows nothing about type -// T and T has no << operator. -// -// A user can override this behavior for a class type Foo by defining -// a << operator in the namespace where Foo is defined. -// -// We put this operator in namespace 'internal2' instead of 'internal' -// to simplify the implementation, as much code in 'internal' needs to -// use << in STL, which would conflict with our own << were it defined -// in 'internal'. -// -// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If -// we define it to take an std::ostream instead, we'll get an -// "ambiguous overloads" compiler error when trying to print a type -// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether -// operator<<(std::ostream&, const T&) or -// operator<<(std::basic_stream, const Foo&) is more -// specific. -template -::std::basic_ostream& operator<<( - ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value>:: - PrintValue(x, &os); - return os; -} - -} // namespace internal2 -} // namespace testing - -// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up -// magic needed for implementing UniversalPrinter won't work. -namespace testing_internal { - -// Used to print a value that is not an STL-style container when the -// user doesn't define PrintTo() for it. -template -void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { - // With the following statement, during unqualified name lookup, - // testing::internal2::operator<< appears as if it was declared in - // the nearest enclosing namespace that contains both - // ::testing_internal and ::testing::internal2, i.e. the global - // namespace. For more details, refer to the C++ Standard section - // 7.3.4-1 [namespace.udir]. This allows us to fall back onto - // testing::internal2::operator<< in case T doesn't come with a << - // operator. - // - // We cannot write 'using ::testing::internal2::operator<<;', which - // gcc 3.3 fails to compile due to a compiler bug. - using namespace ::testing::internal2; // NOLINT - - // Assuming T is defined in namespace foo, in the next statement, - // the compiler will consider all of: - // - // 1. foo::operator<< (thanks to Koenig look-up), - // 2. ::operator<< (as the current namespace is enclosed in ::), - // 3. testing::internal2::operator<< (thanks to the using statement above). - // - // The operator<< whose type matches T best will be picked. - // - // We deliberately allow #2 to be a candidate, as sometimes it's - // impossible to define #1 (e.g. when foo is ::std, defining - // anything in it is undefined behavior unless you are a compiler - // vendor.). - *os << value; -} - -} // namespace testing_internal - -namespace testing { -namespace internal { - -// UniversalPrinter::Print(value, ostream_ptr) prints the given -// value to the given ostream. The caller must ensure that -// 'ostream_ptr' is not NULL, or the behavior is undefined. -// -// We define UniversalPrinter as a class template (as opposed to a -// function template), as we need to partially specialize it for -// reference types, which cannot be done with function templates. -template -class UniversalPrinter; - -template -void UniversalPrint(const T& value, ::std::ostream* os); - -// Used to print an STL-style container when the user doesn't define -// a PrintTo() for it. -template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, - const C& container, ::std::ostream* os) { - const size_t kMaxCount = 32; // The maximum number of elements to print. - *os << '{'; - size_t count = 0; - for (typename C::const_iterator it = container.begin(); - it != container.end(); ++it, ++count) { - if (count > 0) { - *os << ','; - if (count == kMaxCount) { // Enough has been printed. - *os << " ..."; - break; - } - } - *os << ' '; - // We cannot call PrintTo(*it, os) here as PrintTo() doesn't - // handle *it being a native array. - internal::UniversalPrint(*it, os); - } - - if (count > 0) { - *os << ' '; - } - *os << '}'; -} - -// Used to print a pointer that is neither a char pointer nor a member -// pointer, when the user doesn't define PrintTo() for it. (A member -// variable pointer or member function pointer doesn't really point to -// a location in the address space. Their representation is -// implementation-defined. Therefore they will be printed as raw -// bytes.) -template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, - T* p, ::std::ostream* os) { - if (p == NULL) { - *os << "NULL"; - } else { - // We want to print p as a const void*. However, we cannot cast - // it to const void* directly, even using reinterpret_cast, as - // earlier versions of gcc (e.g. 3.4.5) cannot compile the cast - // when p is a function pointer. Casting to UInt64 first solves - // the problem. - *os << reinterpret_cast(reinterpret_cast(p)); - } -} - -// Used to print a non-container, non-pointer value when the user -// doesn't define PrintTo() for it. -template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, - const T& value, ::std::ostream* os) { - ::testing_internal::DefaultPrintNonContainerTo(value, os); -} - -// Prints the given value using the << operator if it has one; -// otherwise prints the bytes in it. This is what -// UniversalPrinter::Print() does when PrintTo() is not specialized -// or overloaded for type T. -// -// A user can override this behavior for a class type Foo by defining -// an overload of PrintTo() in the namespace where Foo is defined. We -// give the user this option as sometimes defining a << operator for -// Foo is not desirable (e.g. the coding style may prevent doing it, -// or there is already a << operator but it doesn't do what the user -// wants). -template -void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. - // - // Note that we check for container types here, prior to we check - // for protocol message types in our operator<<. The rationale is: - // - // For protocol messages, we want to give people a chance to - // override Google Mock's format by defining a PrintTo() or - // operator<<. For STL containers, other formats can be - // incompatible with Google Mock's format for the container - // elements; therefore we check for container types here to ensure - // that our format is used. - // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); -} - -// The following list of PrintTo() overloads tells -// UniversalPrinter::Print() how to print standard types (built-in -// types, strings, plain arrays, and pointers). - -// Overloads for various char types. -void PrintCharTo(char c, int char_code, ::std::ostream* os); -inline void PrintTo(unsigned char c, ::std::ostream* os) { - PrintCharTo(c, c, os); -} -inline void PrintTo(signed char c, ::std::ostream* os) { - PrintCharTo(c, c, os); -} -inline void PrintTo(char c, ::std::ostream* os) { - // When printing a plain char, we always treat it as unsigned. This - // way, the output won't be affected by whether the compiler thinks - // char is signed or not. - PrintTo(static_cast(c), os); -} - -// Overloads for other simple built-in types. -inline void PrintTo(bool x, ::std::ostream* os) { - *os << (x ? "true" : "false"); -} - -// Overload for wchar_t type. -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its decimal code (except for L'\0'). -// The L'\0' char is printed as "L'\\0'". The decimal code is printed -// as signed integer when wchar_t is implemented by the compiler -// as a signed type and is printed as an unsigned integer when wchar_t -// is implemented as an unsigned type. -void PrintTo(wchar_t wc, ::std::ostream* os); - -// Overloads for C strings. -void PrintTo(const char* s, ::std::ostream* os); -inline void PrintTo(char* s, ::std::ostream* os) { - PrintTo(implicit_cast(s), os); -} - -// MSVC can be configured to define wchar_t as a typedef of unsigned -// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native -// type. When wchar_t is a typedef, defining an overload for const -// wchar_t* would cause unsigned short* be printed as a wide string, -// possibly causing invalid memory accesses. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Overloads for wide C strings -void PrintTo(const wchar_t* s, ::std::ostream* os); -inline void PrintTo(wchar_t* s, ::std::ostream* os) { - PrintTo(implicit_cast(s), os); -} -#endif - -// Overload for C arrays. Multi-dimensional arrays are printed -// properly. - -// Prints the given number of elements in an array, without printing -// the curly braces. -template -void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { - UniversalPrinter::Print(a[0], os); - for (size_t i = 1; i != count; i++) { - *os << ", "; - UniversalPrinter::Print(a[i], os); - } -} - -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -void PrintStringTo(const ::std::string&s, ::std::ostream* os); -inline void PrintTo(const ::std::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} - -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_STD_WSTRING - -// Overload for ::std::tr1::tuple. Needed for printing function -// arguments, which are packed as tuples. - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os); - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo( - const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -// Overload for std::pair. -template -void PrintTo(const ::std::pair& value, ::std::ostream* os) { - *os << '('; - UniversalPrinter::Print(value.first, os); - *os << ", "; - UniversalPrinter::Print(value.second, os); - *os << ')'; -} - -// Implements printing a non-reference type T by letting the compiler -// pick the right overload of PrintTo() for T. -template -class UniversalPrinter { - public: - // MSVC warns about adding const to a function type, so we want to - // disable the warning. -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER - - // Note: we deliberately don't call this PrintTo(), as that name - // conflicts with ::testing::internal::PrintTo in the body of the - // function. - static void Print(const T& value, ::std::ostream* os) { - // By default, ::testing::internal::PrintTo() is used for printing - // the value. - // - // Thanks to Koenig look-up, if T is a class and has its own - // PrintTo() function defined in its namespace, that function will - // be visible here. Since it is more specific than the generic ones - // in ::testing::internal, it will be picked by the compiler in the - // following statement - exactly what we want. - PrintTo(value, os); - } - -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER -}; - -// UniversalPrintArray(begin, len, os) prints an array of 'len' -// elements, starting at address 'begin'. -template -void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { - if (len == 0) { - *os << "{}"; - } else { - *os << "{ "; - const size_t kThreshold = 18; - const size_t kChunkSize = 8; - // If the array has more than kThreshold elements, we'll have to - // omit some details by printing only the first and the last - // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. - if (len <= kThreshold) { - PrintRawArrayTo(begin, len, os); - } else { - PrintRawArrayTo(begin, kChunkSize, os); - *os << ", ..., "; - PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); - } - *os << " }"; - } -} -// This overload prints a (const) char array compactly. -void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os); - -// Implements printing an array type T[N]. -template -class UniversalPrinter { - public: - // Prints the given array, omitting some elements when there are too - // many. - static void Print(const T (&a)[N], ::std::ostream* os) { - UniversalPrintArray(a, N, os); - } -}; - -// Implements printing a reference type T&. -template -class UniversalPrinter { - public: - // MSVC warns about adding const to a function type, so we want to - // disable the warning. -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER - - static void Print(const T& value, ::std::ostream* os) { - // Prints the address of the value. We use reinterpret_cast here - // as static_cast doesn't compile when T is a function type. - *os << "@" << reinterpret_cast(&value) << " "; - - // Then prints the value itself. - UniversalPrinter::Print(value, os); - } - -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER -}; - -// Prints a value tersely: for a reference type, the referenced value -// (but not the address) is printed; for a (const) char pointer, the -// NUL-terminated string (but not the pointer) is printed. -template -void UniversalTersePrint(const T& value, ::std::ostream* os) { - UniversalPrinter::Print(value, os); -} -inline void UniversalTersePrint(const char* str, ::std::ostream* os) { - if (str == NULL) { - *os << "NULL"; - } else { - UniversalPrinter::Print(string(str), os); - } -} -inline void UniversalTersePrint(char* str, ::std::ostream* os) { - UniversalTersePrint(static_cast(str), os); -} - -// Prints a value using the type inferred by the compiler. The -// difference between this and UniversalTersePrint() is that for a -// (const) char pointer, this prints both the pointer and the -// NUL-terminated string. -template -void UniversalPrint(const T& value, ::std::ostream* os) { - UniversalPrinter::Print(value, os); -} - -typedef ::std::vector Strings; - -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. - -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - *os << ", "; - UniversalPrinter::type> - ::Print(::std::tr1::get(t), os); - } - - // Tersely prints the first N fields of a tuple to a string vector, - // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base cases. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; -template <> -template -void TuplePrefixPrinter<1>::PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); -} - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); - *os << ")"; -} - -// Prints the fields of a tuple tersely to a string vector, one -// element for each field. See the comment before -// UniversalTersePrint() for how we define "tersely". -template -Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { - Strings result; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - TersePrintPrefixToStrings(value, &result); - return result; -} - -} // namespace internal - -template -::std::string PrintToString(const T& value) { - ::std::stringstream ss; - internal::UniversalTersePrint(value, &ss); - return ss.str(); -} - -} // namespace testing - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 74a095da..67c7a697 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -69,7 +69,6 @@ #include #include #include -#include #include #include #include diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index daf52884..e3d5fd8e 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -63,7 +63,6 @@ #include #include #include -#include #include namespace testing { diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 0c33fdd0..69a23380 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -57,9 +57,6 @@ #define GMOCK_ATTRIBUTE_UNUSED_ #endif // __GNUC__ -class ProtocolMessage; -namespace proto2 { class Message; } - namespace testing { namespace internal { @@ -69,77 +66,6 @@ namespace internal { // "foo_bar_123" are converted to "foo bar 123". string ConvertIdentifierNameToWords(const char* id_name); -// Defining a variable of type CompileAssertTypesEqual will cause a -// compiler error iff T1 and T2 are different types. -template -struct CompileAssertTypesEqual; - -template -struct CompileAssertTypesEqual { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template -struct RemoveReference { typedef T type; }; // NOLINT -template -struct RemoveReference { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GMOCK_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template -struct RemoveConst { typedef T type; }; // NOLINT -template -struct RemoveConst { typedef T type; }; // NOLINT - -// MSVC 8.0 has a bug which causes the above definition to fail to -// remove the const in 'const int[3]'. The following specialization -// works around the bug. However, it causes trouble with gcc and thus -// needs to be conditionally compiled. -#ifdef _MSC_VER -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; -#endif // _MSC_VER - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GMOCK_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst::type - -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GMOCK_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GMOCK_REFERENCE_TO_CONST_(T) \ - GMOCK_ADD_REFERENCE_(const GMOCK_REMOVE_REFERENCE_(T)) - // PointeeOf::type is the type of a value pointed to by a // Pointer, which can be either a smart pointer or a raw pointer. The // following default implementation is for the case where Pointer is a @@ -174,53 +100,6 @@ struct LinkedPtrLessThan { } }; -// ImplicitlyConvertible::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static From MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4244) // Temporarily disables warning 4244. - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#pragma warning(pop) // Restores the warning state. -#else - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#endif // _MSV_VER -}; -template -const bool ImplicitlyConvertible::value; - // Symbian compilation can be done with wchar_t being either a native // type or a typedef. Using Google Mock with OpenC without wchar_t // should require the definition of _STLP_NO_WCHAR_T. @@ -385,32 +264,6 @@ struct LosslessArithmeticConvertible : public LosslessArithmeticConvertibleImpl< GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {}; // NOLINT -// IsAProtocolMessage::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. -template -struct IsAProtocolMessage - : public bool_constant< - ImplicitlyConvertible::value || - ImplicitlyConvertible::value> { -}; - -// When the compiler sees expression IsContainerTest(0), the first -// overload of IsContainerTest will be picked if C is an STL-style -// container class (since C::const_iterator* is a valid type and 0 can -// be converted to it), while the second overload will be picked -// otherwise (since C::const_iterator will be an invalid type in this -// case). Therefore, we can determine whether C is a container class -// by checking the type of IsContainerTest(0). The value of the -// expression is insignificant. -typedef int IsContainer; -template -IsContainer IsContainerTest(typename C::const_iterator*) { return 0; } - -typedef char IsNotContainer; -template -IsNotContainer IsContainerTest(...) { return '\0'; } - // This interface knows how to report a Google Mock failure (either // non-fatal or fatal). class FailureReporterInterface { @@ -514,149 +367,6 @@ inline T Invalid() { template <> inline void Invalid() {} -// Utilities for native arrays. - -// ArrayEq() compares two k-dimensional native arrays using the -// elements' operator==, where k can be any integer >= 0. When k is -// 0, ArrayEq() degenerates into comparing a single pair of values. - -template -bool ArrayEq(const T* lhs, size_t size, const U* rhs); - -// This generic version is used when k is 0. -template -inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } - -// This overload is used when k >= 1. -template -inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { - return internal::ArrayEq(lhs, N, rhs); -} - -// This helper reduces code bloat. If we instead put its logic inside -// the previous ArrayEq() function, arrays with different sizes would -// lead to different copies of the template code. -template -bool ArrayEq(const T* lhs, size_t size, const U* rhs) { - for (size_t i = 0; i != size; i++) { - if (!internal::ArrayEq(lhs[i], rhs[i])) - return false; - } - return true; -} - -// Finds the first element in the iterator range [begin, end) that -// equals elem. Element may be a native array type itself. -template -Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { - for (Iter it = begin; it != end; ++it) { - if (internal::ArrayEq(*it, elem)) - return it; - } - return end; -} - -// CopyArray() copies a k-dimensional native array using the elements' -// operator=, where k can be any integer >= 0. When k is 0, -// CopyArray() degenerates into copying a single value. - -template -void CopyArray(const T* from, size_t size, U* to); - -// This generic version is used when k is 0. -template -inline void CopyArray(const T& from, U* to) { *to = from; } - -// This overload is used when k >= 1. -template -inline void CopyArray(const T(&from)[N], U(*to)[N]) { - internal::CopyArray(from, N, *to); -} - -// This helper reduces code bloat. If we instead put its logic inside -// the previous CopyArray() function, arrays with different sizes -// would lead to different copies of the template code. -template -void CopyArray(const T* from, size_t size, U* to) { - for (size_t i = 0; i != size; i++) { - internal::CopyArray(from[i], to + i); - } -} - -// The relation between an NativeArray object (see below) and the -// native array it represents. -enum RelationToSource { - kReference, // The NativeArray references the native array. - kCopy // The NativeArray makes a copy of the native array and - // owns the copy. -}; - -// Adapts a native array to a read-only STL-style container. Instead -// of the complete STL container concept, this adaptor only implements -// members useful for Google Mock's container matchers. New members -// should be added as needed. To simplify the implementation, we only -// support Element being a raw type (i.e. having no top-level const or -// reference modifier). It's the client's responsibility to satisfy -// this requirement. Element can be an array type itself (hence -// multi-dimensional arrays are supported). -template -class NativeArray { - public: - // STL-style container typedefs. - typedef Element value_type; - typedef const Element* const_iterator; - - // Constructs from a native array. - NativeArray(const Element* array, size_t count, RelationToSource relation) { - Init(array, count, relation); - } - - // Copy constructor. - NativeArray(const NativeArray& rhs) { - Init(rhs.array_, rhs.size_, rhs.relation_to_source_); - } - - ~NativeArray() { - // Ensures that the user doesn't instantiate NativeArray with a - // const or reference type. - testing::StaticAssertTypeEq(); - if (relation_to_source_ == kCopy) - delete[] array_; - } - - // STL-style container methods. - size_t size() const { return size_; } - const_iterator begin() const { return array_; } - const_iterator end() const { return array_ + size_; } - bool operator==(const NativeArray& rhs) const { - return size() == rhs.size() && - ArrayEq(begin(), size(), rhs.begin()); - } - - private: - // Not implemented as we don't want to support assignment. - void operator=(const NativeArray& rhs); - - // Initializes this object; makes a copy of the input array if - // 'relation' is kCopy. - void Init(const Element* array, size_t a_size, RelationToSource relation) { - if (relation == kReference) { - array_ = array; - } else { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - } - size_ = a_size; - relation_to_source_ = relation; - } - - const Element* array_; - size_t size_; - RelationToSource relation_to_source_; -}; - // Given a raw type (i.e. having no top-level reference or const // modifier) RawContainer that's either an STL-style container or a // native array, class StlContainerView has the @@ -682,7 +392,7 @@ class StlContainerView { static const_reference ConstReference(const RawContainer& container) { // Ensures that RawContainer is not a const type. testing::StaticAssertTypeEq(); + GTEST_REMOVE_CONST_(RawContainer)>(); return container; } static type Copy(const RawContainer& container) { return container; } @@ -692,7 +402,7 @@ class StlContainerView { template class StlContainerView { public: - typedef GMOCK_REMOVE_CONST_(Element) RawElement; + typedef GTEST_REMOVE_CONST_(Element) RawElement; typedef internal::NativeArray type; // NativeArray can represent a native array either by value or by // reference (selected by a constructor argument), so 'const type' @@ -737,7 +447,7 @@ class StlContainerView { template class StlContainerView< ::std::tr1::tuple > { public: - typedef GMOCK_REMOVE_CONST_( + typedef GTEST_REMOVE_CONST_( typename internal::PointeeOf::type) RawElement; typedef internal::NativeArray type; typedef const type const_reference; diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 30115f23..b644eb4f 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -50,149 +50,12 @@ // tr1/tuple. gmock-port.h does this via gtest-port.h, which is // guaranteed to pull in the tuple header. -#if GTEST_OS_LINUX - -#endif // GTEST_OS_LINUX - -namespace testing { -namespace internal { - // For MS Visual C++, check the compiler version. At least VS 2003 is // required to compile Google Mock. #if defined(_MSC_VER) && _MSC_VER < 1310 #error "At least Visual C++ 2003 (7.1) is required to compile Google Mock." #endif -// Use implicit_cast as a safe version of static_cast for upcasting in -// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a -// const Foo*). When you use implicit_cast, the compiler checks that -// the cast is safe. Such explicit implicit_casts are necessary in -// surprisingly many situations where C++ demands an exact type match -// instead of an argument type convertable to a target type. -// -// The syntax for using implicit_cast is the same as for static_cast: -// -// implicit_cast(expr) -// -// implicit_cast would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -template -inline To implicit_cast(To x) { return x; } - -// When you upcast (that is, cast a pointer from type Foo to type -// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts -// always succeed. When you downcast (that is, cast a pointer from -// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because -// how do you know the pointer is really of type SubclassOfFoo? It -// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, -// when you downcast, you should use this macro. In debug mode, we -// use dynamic_cast<> to double-check the downcast is legal (we die -// if it's not). In normal mode, we do the efficient static_cast<> -// instead. Thus, it's important to test in debug mode to make sure -// the cast is legal! -// This is the only place in the code we should use dynamic_cast<>. -// In particular, you SHOULDN'T be using dynamic_cast<> in order to -// do RTTI (eg code like this: -// if (dynamic_cast(foo)) HandleASubclass1Object(foo); -// if (dynamic_cast(foo)) HandleASubclass2Object(foo); -// You should design the code some other way not to need this. -template // use like this: down_cast(foo); -inline To down_cast(From* f) { // so we only accept pointers - // Ensures that To is a sub-type of From *. This test is here only - // for compile-time type checking, and has no overhead in an - // optimized build at run-time, as it will be optimized away - // completely. - if (false) { - const To to = NULL; - ::testing::internal::implicit_cast(to); - } - -#if GTEST_HAS_RTTI - assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! -#endif - return static_cast(f); -} - -// The GMOCK_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// GMOCK_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// GMOCK_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -template -struct CompileAssert { -}; - -#define GMOCK_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(bool(expr))> \ - msg[bool(expr) ? 1 : -1] - -// Implementation details of GMOCK_COMPILE_ASSERT_: -// -// - GMOCK_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GMOCK_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GMOCK_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// GMOCK_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING - -} // namespace internal -} // namespace testing - // Macro for referencing flags. This is public as we want the user to // use this syntax to reference Google Mock flags. #define GMOCK_FLAG(name) FLAGS_gmock_##name diff --git a/scons/SConscript b/scons/SConscript index 764cd7bc..dedad37d 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -186,7 +186,6 @@ GtestTest(env, 'gmock-matchers_test', [gtest, gmock_main]) GtestTest(env, 'gmock-more-actions_test', [gtest, gmock_main]) GtestTest(env, 'gmock-nice-strict_test', [gtest, gmock_main]) GtestTest(env, 'gmock-port_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-printers_test', [gtest, gmock_main]) GtestTest(env, 'gmock-spec-builders_test', [gtest, gmock_main]) GtestTest(env, 'gmock_leak_test_', [gtest, gmock_main]) GtestTest(env, 'gmock_link_test', [gtest, gmock_main], diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index bc814ad9..fad4e340 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -203,7 +203,7 @@ def _IncompleteByReferenceArgumentDiagnoser(msg): """Diagnoses the IBRA disease, given the error messages by gcc.""" regex = (_FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-printers\.h.*error: invalid application of ' + r'.*gtest-printers\.h.*error: invalid application of ' r'\'sizeof\' to incomplete type \'(?P.*)\'') diagnosis = """ In order to mock this function, Google Mock needs to see the definition diff --git a/src/gmock-all.cc b/src/gmock-all.cc index c9223fce..76118d88 100644 --- a/src/gmock-all.cc +++ b/src/gmock-all.cc @@ -43,6 +43,5 @@ #include "src/gmock-cardinalities.cc" #include "src/gmock-internal-utils.cc" #include "src/gmock-matchers.cc" -#include "src/gmock-printers.cc" #include "src/gmock-spec-builders.cc" #include "src/gmock.cc" diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc deleted file mode 100644 index fd7d3055..00000000 --- a/src/gmock-printers.cc +++ /dev/null @@ -1,318 +0,0 @@ -// 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 a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// It uses the << operator when possible, and prints the bytes in the -// object otherwise. A user can override its behavior for a class -// type Foo by defining either operator<<(::std::ostream&, const Foo&) -// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that -// defines Foo. - -#include -#include -#include -#include // NOLINT -#include -#include - -namespace testing { - -namespace { - -using ::std::ostream; - -#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. -#define snprintf _snprintf -#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. -#define snprintf _snprintf_s -#elif _MSC_VER -#define snprintf _snprintf -#endif // GTEST_OS_WINDOWS_MOBILE - -// Prints a segment of bytes in the given object. -void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, - size_t count, ostream* os) { - char text[5] = ""; - for (size_t i = 0; i != count; i++) { - const size_t j = start + i; - if (i != 0) { - // Organizes the bytes into groups of 2 for easy parsing by - // human. - if ((j % 2) == 0) { - *os << " "; - } - } - snprintf(text, sizeof(text), "%02X", obj_bytes[j]); - *os << text; - } -} - -// Prints the bytes in the given value to the given ostream. -void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, - ostream* os) { - // Tells the user how big the object is. - *os << count << "-byte object <"; - - const size_t kThreshold = 132; - const size_t kChunkSize = 64; - // If the object size is bigger than kThreshold, we'll have to omit - // some details by printing only the first and the last kChunkSize - // bytes. - // TODO(wan): let the user control the threshold using a flag. - if (count < kThreshold) { - PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); - } else { - PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); - *os << " ... "; - // Rounds up to 2-byte boundary. - const size_t resume_pos = (count - kChunkSize + 1)/2*2; - PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); - } - *os << ">"; -} - -} // namespace - -namespace internal2 { - -// Delegates to PrintBytesInObjectToImpl() to print the bytes in the -// given object. The delegation simplifies the implementation, which -// uses the << operator and thus is easier done outside of the -// ::testing::internal namespace, which contains a << operator that -// sometimes conflicts with the one in STL. -void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, - ostream* os) { - PrintBytesInObjectToImpl(obj_bytes, count, os); -} - -} // namespace internal2 - -namespace internal { - -// Prints a wide char as a char literal without the quotes, escaping it -// when necessary. -static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { - switch (c) { - case L'\0': - *os << "\\0"; - break; - case L'\'': - *os << "\\'"; - break; - case L'\?': - *os << "\\?"; - break; - case L'\\': - *os << "\\\\"; - break; - case L'\a': - *os << "\\a"; - break; - case L'\b': - *os << "\\b"; - break; - case L'\f': - *os << "\\f"; - break; - case L'\n': - *os << "\\n"; - break; - case L'\r': - *os << "\\r"; - break; - case L'\t': - *os << "\\t"; - break; - case L'\v': - *os << "\\v"; - break; - default: - // Checks whether c is printable or not. Printable characters are in - // the range [0x20,0x7E]. - // We test the value of c directly instead of calling isprint(), as - // isprint() is buggy on Windows mobile. - if (0x20 <= c && c <= 0x7E) { - *os << static_cast(c); - } else { - // Buffer size enough for the maximum number of digits and \0. - char text[2 * sizeof(unsigned long) + 1] = ""; - snprintf(text, sizeof(text), "%lX", static_cast(c)); - *os << "\\x" << text; - } - } -} - -// Prints a char as if it's part of a string literal, escaping it when -// necessary. -static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { - switch (c) { - case L'\'': - *os << "'"; - break; - case L'"': - *os << "\\\""; - break; - default: - PrintAsWideCharLiteralTo(c, os); - } -} - -// Prints a char as a char literal without the quotes, escaping it -// when necessary. -static void PrintAsCharLiteralTo(char c, ostream* os) { - PrintAsWideCharLiteralTo(static_cast(c), os); -} - -// Prints a char as if it's part of a string literal, escaping it when -// necessary. -static void PrintAsStringLiteralTo(char c, ostream* os) { - PrintAsWideStringLiteralTo(static_cast(c), os); -} - -// Prints a char and its code. The '\0' char is printed as "'\\0'", -// other unprintable characters are also properly escaped using the -// standard C++ escape sequence. -void PrintCharTo(char c, int char_code, ostream* os) { - *os << "'"; - PrintAsCharLiteralTo(c, os); - *os << "'"; - if (c != '\0') - *os << " (" << char_code << ")"; -} - -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its decimal code (except for L'\0'). -// The L'\0' char is printed as "L'\\0'". The decimal code is printed -// as signed integer when wchar_t is implemented by the compiler -// as a signed type and is printed as an unsigned integer when wchar_t -// is implemented as an unsigned type. -void PrintTo(wchar_t wc, ostream* os) { - *os << "L'"; - PrintAsWideCharLiteralTo(wc, os); - *os << "'"; - if (wc != L'\0') { - // Type Int64 is used because it provides more storage than wchar_t thus - // when the compiler converts signed or unsigned implementation of wchar_t - // to Int64 it fills higher bits with either zeros or the sign bit - // passing it to operator <<() as either signed or unsigned integer. - *os << " (" << static_cast(wc) << ")"; - } -} - -// Prints the given array of characters to the ostream. -// The array starts at *begin, the length is len, it may include '\0' characters -// and may not be null-terminated. -static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { - *os << "\""; - for (size_t index = 0; index < len; ++index) { - PrintAsStringLiteralTo(begin[index], os); - } - *os << "\""; -} - -// Prints a (const) char array of 'len' elements, starting at address 'begin'. -void UniversalPrintArray(const char* begin, size_t len, ostream* os) { - PrintCharsAsStringTo(begin, len, os); -} - -// Prints the given array of wide characters to the ostream. -// The array starts at *begin, the length is len, it may include L'\0' -// characters and may not be null-terminated. -static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, - ostream* os) { - *os << "L\""; - for (size_t index = 0; index < len; ++index) { - PrintAsWideStringLiteralTo(begin[index], os); - } - *os << "\""; -} - -// Prints the given C string to the ostream. -void PrintTo(const char* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << implicit_cast(s) << " pointing to "; - PrintCharsAsStringTo(s, strlen(s), os); - } -} - -// MSVC compiler can be configured to define whar_t as a typedef -// of unsigned short. Defining an overload for const wchar_t* in that case -// would cause pointers to unsigned shorts be printed as wide strings, -// possibly accessing more memory than intended and causing invalid -// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when -// wchar_t is implemented as a native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Prints the given wide C string to the ostream. -void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << implicit_cast(s) << " pointing to "; - PrintWideCharsAsStringTo(s, wcslen(s), os); - } -} -#endif // wchar_t is native - -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} - -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintWideCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { - PrintWideCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_STD_WSTRING - -} // namespace internal - -} // namespace testing diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index a2c6fe11..8391e5fe 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -74,9 +74,9 @@ using testing::SetArgumentPointee; using testing::SetErrnoAndReturn; #endif -#if GMOCK_HAS_PROTOBUF_ +#if GTEST_HAS_PROTOBUF_ using testing::internal::TestMessage; -#endif // GMOCK_HAS_PROTOBUF_ +#endif // GTEST_HAS_PROTOBUF_ // Tests that BuiltInDefaultValue::Get() returns NULL. TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) { @@ -689,7 +689,7 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointee) { EXPECT_EQ('a', ch); } -#if GMOCK_HAS_PROTOBUF_ +#if GTEST_HAS_PROTOBUF_ // Tests that SetArgumentPointee(proto_buffer) sets the v1 protobuf // variable pointed to by the N-th (0-based) argument to proto_buffer. @@ -786,7 +786,7 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferBaseType) { EXPECT_EQ("hi", dest.string_field()); } -#endif // GMOCK_HAS_PROTOBUF_ +#endif // GTEST_HAS_PROTOBUF_ // Sample functions and functors for testing Invoke() and etc. int Nullary() { return 1; } diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index b8e05191..4309f7c8 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -96,102 +96,6 @@ TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameIsMixture) { ConvertIdentifierNameToWords("_Chapter11Section_1_")); } -// Tests that CompileAssertTypesEqual compiles when the type arguments are -// equal. -TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { - CompileAssertTypesEqual(); - CompileAssertTypesEqual(); -} - -// Tests that RemoveReference does not affect non-reference types. -TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) { - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); -} - -// Tests that RemoveReference removes reference from reference types. -TEST(RemoveReferenceTest, RemovesReference) { - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); -} - -// Tests GMOCK_REMOVE_REFERENCE_. - -template -void TestGMockRemoveReference() { - CompileAssertTypesEqual(); -} - -TEST(RemoveReferenceTest, MacroVersion) { - TestGMockRemoveReference(); - TestGMockRemoveReference(); -} - - -// Tests that RemoveConst does not affect non-const types. -TEST(RemoveConstTest, DoesNotAffectNonConstType) { - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); -} - -// Tests that RemoveConst removes const from const types. -TEST(RemoveConstTest, RemovesConst) { - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); -} - -// Tests GMOCK_REMOVE_CONST_. - -template -void TestGMockRemoveConst() { - CompileAssertTypesEqual(); -} - -TEST(RemoveConstTest, MacroVersion) { - TestGMockRemoveConst(); - TestGMockRemoveConst(); - TestGMockRemoveConst(); -} - -// Tests that AddReference does not affect reference types. -TEST(AddReferenceTest, DoesNotAffectReferenceType) { - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); -} - -// Tests that AddReference adds reference to non-reference types. -TEST(AddReferenceTest, AddsReference) { - CompileAssertTypesEqual::type>(); - CompileAssertTypesEqual::type>(); -} - -// Tests GMOCK_ADD_REFERENCE_. - -template -void TestGMockAddReference() { - CompileAssertTypesEqual(); -} - -TEST(AddReferenceTest, MacroVersion) { - TestGMockAddReference(); - TestGMockAddReference(); -} - -// Tests GMOCK_REFERENCE_TO_CONST_. - -template -void TestGMockReferenceToConst() { - CompileAssertTypesEqual(); -} - -TEST(GMockReferenceToConstTest, Works) { - TestGMockReferenceToConst(); - TestGMockReferenceToConst(); - TestGMockReferenceToConst(); - TestGMockReferenceToConst(); -} - TEST(PointeeOfTest, WorksForSmartPointers) { CompileAssertTypesEqual >::type>(); @@ -217,38 +121,11 @@ TEST(GetRawPointerTest, WorksForRawPointers) { EXPECT_EQ(&n, GetRawPointer(&n)); } +// Tests KindOf. + class Base {}; class Derived : public Base {}; -// Tests that ImplicitlyConvertible::value is a compile-time constant. -TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { - GMOCK_COMPILE_ASSERT_((ImplicitlyConvertible::value), const_true); - GMOCK_COMPILE_ASSERT_((!ImplicitlyConvertible::value), - const_false); -} - -// Tests that ImplicitlyConvertible::value is true when T1 can -// be implicitly converted to T2. -TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) { - EXPECT_TRUE((ImplicitlyConvertible::value)); - EXPECT_TRUE((ImplicitlyConvertible::value)); - EXPECT_TRUE((ImplicitlyConvertible::value)); - EXPECT_TRUE((ImplicitlyConvertible::value)); - EXPECT_TRUE((ImplicitlyConvertible::value)); - EXPECT_TRUE((ImplicitlyConvertible::value)); -} - -// Tests that ImplicitlyConvertible::value is false when T1 -// cannot be implicitly converted to T2. -TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { - EXPECT_FALSE((ImplicitlyConvertible::value)); - EXPECT_FALSE((ImplicitlyConvertible::value)); - EXPECT_FALSE((ImplicitlyConvertible::value)); - EXPECT_FALSE((ImplicitlyConvertible::value)); -} - -// Tests KindOf. - TEST(KindOfTest, Bool) { EXPECT_EQ(kBool, GMOCK_KIND_OF_(bool)); // NOLINT } @@ -382,46 +259,6 @@ TEST(LosslessArithmeticConvertibleTest, FloatingPointToFloatingPoint) { } } -// Tests that IsAProtocolMessage::value is a compile-time constant. -TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { - GMOCK_COMPILE_ASSERT_(IsAProtocolMessage::value, const_true); - GMOCK_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); -} - -// Tests that IsAProtocolMessage::value is true when T is -// ProtocolMessage or a sub-class of it. -TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { - EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); - EXPECT_TRUE(IsAProtocolMessage::value); -#if GMOCK_HAS_PROTOBUF_ - EXPECT_TRUE(IsAProtocolMessage::value); -#endif // GMOCK_HAS_PROTOBUF_ -} - -// Tests that IsAProtocolMessage::value is false when T is neither -// ProtocolMessage nor a sub-class of it. -TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { - EXPECT_FALSE(IsAProtocolMessage::value); - EXPECT_FALSE(IsAProtocolMessage::value); -} - -// Tests IsContainerTest. - -class NonContainer {}; - -TEST(IsContainerTestTest, WorksForNonContainer) { - EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); - EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); - EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); -} - -TEST(IsContainerTestTest, WorksForContainer) { - EXPECT_EQ(sizeof(IsContainer), - sizeof(IsContainerTest >(0))); - EXPECT_EQ(sizeof(IsContainer), - sizeof(IsContainerTest >(0))); -} - // Tests the TupleMatches() template function. TEST(TupleMatchesTest, WorksForSize0) { @@ -737,148 +574,6 @@ TEST(OnCallTest, LogsAnythingArgument) { #endif // GTEST_HAS_STREAM_REDIRECTION_ -// Tests ArrayEq(). - -TEST(ArrayEqTest, WorksForDegeneratedArrays) { - EXPECT_TRUE(ArrayEq(5, 5L)); - EXPECT_FALSE(ArrayEq('a', 0)); -} - -TEST(ArrayEqTest, WorksForOneDimensionalArrays) { - const int a[] = { 0, 1 }; - long b[] = { 0, 1 }; - EXPECT_TRUE(ArrayEq(a, b)); - EXPECT_TRUE(ArrayEq(a, 2, b)); - - b[0] = 2; - EXPECT_FALSE(ArrayEq(a, b)); - EXPECT_FALSE(ArrayEq(a, 1, b)); -} - -TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { - const char a[][3] = { "hi", "lo" }; - const char b[][3] = { "hi", "lo" }; - const char c[][3] = { "hi", "li" }; - - EXPECT_TRUE(ArrayEq(a, b)); - EXPECT_TRUE(ArrayEq(a, 2, b)); - - EXPECT_FALSE(ArrayEq(a, c)); - EXPECT_FALSE(ArrayEq(a, 2, c)); -} - -// Tests ArrayAwareFind(). - -TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { - const char a[] = "hello"; - EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); - EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); -} - -TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { - int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; - const int b[2] = { 2, 3 }; - EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); - - const int c[2] = { 6, 7 }; - EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); -} - -// Tests CopyArray(). - -TEST(CopyArrayTest, WorksForDegeneratedArrays) { - int n = 0; - CopyArray('a', &n); - EXPECT_EQ('a', n); -} - -TEST(CopyArrayTest, WorksForOneDimensionalArrays) { - const char a[3] = "hi"; - int b[3]; - CopyArray(a, &b); - EXPECT_TRUE(ArrayEq(a, b)); - - int c[3]; - CopyArray(a, 3, c); - EXPECT_TRUE(ArrayEq(a, c)); -} - -TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { - const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; - int b[2][3]; - CopyArray(a, &b); - EXPECT_TRUE(ArrayEq(a, b)); - - int c[2][3]; - CopyArray(a, 2, c); - EXPECT_TRUE(ArrayEq(a, c)); -} - -// Tests NativeArray. - -TEST(NativeArrayTest, ConstructorFromArrayWorks) { - const int a[3] = { 0, 1, 2 }; - NativeArray na(a, 3, kReference); - EXPECT_EQ(3U, na.size()); - EXPECT_EQ(a, na.begin()); -} - -TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { - typedef int Array[2]; - Array* a = new Array[1]; - (*a)[0] = 0; - (*a)[1] = 1; - NativeArray na(*a, 2, kCopy); - EXPECT_NE(*a, na.begin()); - delete[] a; - EXPECT_EQ(0, na.begin()[0]); - EXPECT_EQ(1, na.begin()[1]); - - // We rely on the heap checker to verify that na deletes the copy of - // array. -} - -TEST(NativeArrayTest, TypeMembersAreCorrect) { - StaticAssertTypeEq::value_type>(); - StaticAssertTypeEq::value_type>(); - - StaticAssertTypeEq::const_iterator>(); - StaticAssertTypeEq::const_iterator>(); -} - -TEST(NativeArrayTest, MethodsWork) { - const int a[3] = { 0, 1, 2 }; - NativeArray na(a, 3, kCopy); - ASSERT_EQ(3U, na.size()); - EXPECT_EQ(3, na.end() - na.begin()); - - NativeArray::const_iterator it = na.begin(); - EXPECT_EQ(0, *it); - ++it; - EXPECT_EQ(1, *it); - it++; - EXPECT_EQ(2, *it); - ++it; - EXPECT_EQ(na.end(), it); - - EXPECT_THAT(na, Eq(na)); - - NativeArray na2(a, 3, kReference); - EXPECT_THAT(na, Eq(na2)); - - const int b1[3] = { 0, 1, 1 }; - const int b2[4] = { 0, 1, 2, 3 }; - EXPECT_THAT(na, Not(Eq(NativeArray(b1, 3, kReference)))); - EXPECT_THAT(na, Not(Eq(NativeArray(b2, 4, kCopy)))); -} - -TEST(NativeArrayTest, WorksForTwoDimensionalArray) { - const char a[2][3] = { "hi", "lo" }; - NativeArray na(a, 2, kReference); - ASSERT_EQ(2U, na.size()); - EXPECT_EQ(a, na.begin()); -} - // Tests StlContainerView. TEST(StlContainerViewTest, WorksForStlContainer) { diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 054313b7..a84eb9ea 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -39,126 +39,5 @@ // NOTE: if this file is left without tests for some reason, put a dummy // test here to make references to symbols in the gtest library and avoid // 'undefined symbol' linker errors in gmock_main: -// -// TEST(DummyTest, Dummy) {} - -namespace testing { -namespace internal { -// Needed to avoid name collisions in gmock_all_test.cc. -namespace gmock_port_test { - -class Base { - public: - // Copy constructor and assignment operator do exactly what we need, so we - // use them. - Base() : member_(0) {} - explicit Base(int n) : member_(n) {} - virtual ~Base() {} - int member() { return member_; } - - private: - int member_; -}; - -class Derived : public Base { - public: - explicit Derived(int n) : Base(n) {} -}; - -TEST(ImplicitCastTest, ConvertsPointers) { - Derived derived(0); - EXPECT_TRUE(&derived == ::testing::internal::implicit_cast(&derived)); -} - -TEST(ImplicitCastTest, CanUseInheritance) { - Derived derived(1); - Base base = ::testing::internal::implicit_cast(derived); - EXPECT_EQ(derived.member(), base.member()); -} - -class Castable { - public: - Castable(bool* converted) : converted_(converted) {} - operator Base() { - *converted_ = true; - return Base(); - } - - private: - bool* converted_; -}; - -TEST(ImplicitCastTest, CanUseNonConstCastOperator) { - bool converted = false; - Castable castable(&converted); - Base base = ::testing::internal::implicit_cast(castable); - EXPECT_TRUE(converted); -} - -class ConstCastable { - public: - ConstCastable(bool* converted) : converted_(converted) {} - operator Base() const { - *converted_ = true; - return Base(); - } - - private: - bool* converted_; -}; - -TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { - bool converted = false; - const ConstCastable const_castable(&converted); - Base base = ::testing::internal::implicit_cast(const_castable); - EXPECT_TRUE(converted); -} - -class ConstAndNonConstCastable { - public: - ConstAndNonConstCastable(bool* converted, bool* const_converted) - : converted_(converted), const_converted_(const_converted) {} - operator Base() { - *converted_ = true; - return Base(); - } - operator Base() const { - *const_converted_ = true; - return Base(); - } - - private: - bool* converted_; - bool* const_converted_; -}; - -TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { - bool converted = false; - bool const_converted = false; - ConstAndNonConstCastable castable(&converted, &const_converted); - Base base = ::testing::internal::implicit_cast(castable); - EXPECT_TRUE(converted); - EXPECT_FALSE(const_converted); - - converted = false; - const_converted = false; - const ConstAndNonConstCastable const_castable(&converted, &const_converted); - base = ::testing::internal::implicit_cast(const_castable); - EXPECT_FALSE(converted); - EXPECT_TRUE(const_converted); -} - -class To { - public: - To(bool* converted) { *converted = true; } // NOLINT -}; - -TEST(ImplicitCastTest, CanUseImplicitConstructor) { - bool converted = false; - To to = ::testing::internal::implicit_cast(&converted); - EXPECT_TRUE(converted); -} -} // namespace gmock_port_test -} // namespace internal -} // namespace testing +TEST(DummyTest, Dummy) {} diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc deleted file mode 100644 index 92c8413c..00000000 --- a/test/gmock-printers_test.cc +++ /dev/null @@ -1,1118 +0,0 @@ -// 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 tests the universal value printer. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// hash_map and hash_set are available on Windows. -#if GTEST_OS_WINDOWS -#define GMOCK_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. -#include // NOLINT -#define GMOCK_HAS_HASH_SET_ 1 // Indicates that hash_set is available. -#include // NOLINT -#endif // GTEST_OS_WINDOWS - -// Some user-defined types for testing the universal value printer. - -// A user-defined unprintable class template in the global namespace. -template -class UnprintableTemplateInGlobal { - public: - UnprintableTemplateInGlobal() : value_() {} - private: - T value_; -}; - -// A user-defined streamable type in the global namespace. -class StreamableInGlobal { - public: - virtual ~StreamableInGlobal() {} -}; - -inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { - os << "StreamableInGlobal"; -} - -namespace foo { - -// A user-defined unprintable type in a user namespace. -class UnprintableInFoo { - public: - UnprintableInFoo() : x_(0x12EF), y_(0xAB34), z_(0) {} - private: - testing::internal::Int32 x_; - testing::internal::Int32 y_; - double z_; -}; - -// A user-defined printable type in a user-chosen namespace. -struct PrintableViaPrintTo { - PrintableViaPrintTo() : value() {} - int value; -}; - -void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { - *os << "PrintableViaPrintTo: " << x.value; -} - -// A user-defined printable class template in a user-chosen namespace. -template -class PrintableViaPrintToTemplate { - public: - explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} - - const T& value() const { return value_; } - private: - T value_; -}; - -template -void PrintTo(const PrintableViaPrintToTemplate& x, ::std::ostream* os) { - *os << "PrintableViaPrintToTemplate: " << x.value(); -} - -// A user-defined streamable class template in a user namespace. -template -class StreamableTemplateInFoo { - public: - StreamableTemplateInFoo() : value_() {} - - const T& value() const { return value_; } - private: - T value_; -}; - -template -inline ::std::ostream& operator<<(::std::ostream& os, - const StreamableTemplateInFoo& x) { - return os << "StreamableTemplateInFoo: " << x.value(); -} - -} // namespace foo - -namespace testing { -namespace gmock_printers_test { - -using ::std::deque; -using ::std::list; -using ::std::make_pair; -using ::std::map; -using ::std::multimap; -using ::std::multiset; -using ::std::pair; -using ::std::set; -using ::std::tr1::make_tuple; -using ::std::tr1::tuple; -using ::std::vector; -using ::testing::ElementsAre; -using ::testing::PrintToString; -using ::testing::StartsWith; -using ::testing::internal::NativeArray; -using ::testing::internal::Strings; -using ::testing::internal::UniversalTersePrint; -using ::testing::internal::UniversalPrint; -using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; -using ::testing::internal::UniversalPrinter; -using ::testing::internal::kReference; -using ::testing::internal::string; - -#if GTEST_OS_WINDOWS -// MSVC defines the following classes in the ::stdext namespace while -// gcc defines them in the :: namespace. Note that they are not part -// of the C++ standard. - -using ::stdext::hash_map; -using ::stdext::hash_set; -using ::stdext::hash_multimap; -using ::stdext::hash_multiset; - -#endif // GTEST_OS_WINDOWS - -// Prints a value to a string using the universal value printer. This -// is a helper for testing UniversalPrinter::Print() for various types. -template -string Print(const T& value) { - ::std::stringstream ss; - UniversalPrinter::Print(value, &ss); - return ss.str(); -} - -// Prints a value passed by reference to a string, using the universal -// value printer. This is a helper for testing -// UniversalPrinter::Print() for various types. -template -string PrintByRef(const T& value) { - ::std::stringstream ss; - UniversalPrinter::Print(value, &ss); - return ss.str(); -} - -// Tests printing various char types. - -// char. -TEST(PrintCharTest, PlainChar) { - EXPECT_EQ("'\\0'", Print('\0')); - EXPECT_EQ("'\\'' (39)", Print('\'')); - EXPECT_EQ("'\"' (34)", Print('"')); - EXPECT_EQ("'\\?' (63)", Print('\?')); - EXPECT_EQ("'\\\\' (92)", Print('\\')); - EXPECT_EQ("'\\a' (7)", Print('\a')); - EXPECT_EQ("'\\b' (8)", Print('\b')); - EXPECT_EQ("'\\f' (12)", Print('\f')); - EXPECT_EQ("'\\n' (10)", Print('\n')); - EXPECT_EQ("'\\r' (13)", Print('\r')); - EXPECT_EQ("'\\t' (9)", Print('\t')); - EXPECT_EQ("'\\v' (11)", Print('\v')); - EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); - EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); - EXPECT_EQ("' ' (32)", Print(' ')); - EXPECT_EQ("'a' (97)", Print('a')); -} - -// signed char. -TEST(PrintCharTest, SignedChar) { - EXPECT_EQ("'\\0'", Print(static_cast('\0'))); - EXPECT_EQ("'\\xCE' (-50)", - Print(static_cast(-50))); -} - -// unsigned char. -TEST(PrintCharTest, UnsignedChar) { - EXPECT_EQ("'\\0'", Print(static_cast('\0'))); - EXPECT_EQ("'b' (98)", - Print(static_cast('b'))); -} - -// Tests printing other simple, built-in types. - -// bool. -TEST(PrintBuiltInTypeTest, Bool) { - EXPECT_EQ("false", Print(false)); - EXPECT_EQ("true", Print(true)); -} - -// wchar_t. -TEST(PrintBuiltInTypeTest, Wchar_t) { - EXPECT_EQ("L'\\0'", Print(L'\0')); - EXPECT_EQ("L'\\'' (39)", Print(L'\'')); - EXPECT_EQ("L'\"' (34)", Print(L'"')); - EXPECT_EQ("L'\\?' (63)", Print(L'\?')); - EXPECT_EQ("L'\\\\' (92)", Print(L'\\')); - EXPECT_EQ("L'\\a' (7)", Print(L'\a')); - EXPECT_EQ("L'\\b' (8)", Print(L'\b')); - EXPECT_EQ("L'\\f' (12)", Print(L'\f')); - EXPECT_EQ("L'\\n' (10)", Print(L'\n')); - EXPECT_EQ("L'\\r' (13)", Print(L'\r')); - EXPECT_EQ("L'\\t' (9)", Print(L'\t')); - EXPECT_EQ("L'\\v' (11)", Print(L'\v')); - EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); - EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); - EXPECT_EQ("L' ' (32)", Print(L' ')); - EXPECT_EQ("L'a' (97)", Print(L'a')); - EXPECT_EQ("L'\\x576' (1398)", Print(L'\x576')); - EXPECT_EQ("L'\\xC74D' (51021)", Print(L'\xC74D')); -} - -// Test that Int64 provides more storage than wchar_t. -TEST(PrintTypeSizeTest, Wchar_t) { - EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); -} - -// Various integer types. -TEST(PrintBuiltInTypeTest, Integer) { - EXPECT_EQ("'\\xFF' (255)", Print(static_cast(255))); // uint8 - EXPECT_EQ("'\\x80' (-128)", Print(static_cast(-128))); // int8 - EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 - EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 - EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 - EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 - EXPECT_EQ("18446744073709551615", - Print(static_cast(-1))); // uint64 - EXPECT_EQ("-9223372036854775808", - Print(static_cast(1) << 63)); // int64 -} - -// Size types. -TEST(PrintBuiltInTypeTest, Size_t) { - EXPECT_EQ("1", Print(sizeof('a'))); // size_t. -#if !GTEST_OS_WINDOWS - // Windows has no ssize_t type. - EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. -#endif // !GTEST_OS_WINDOWS -} - -// Floating-points. -TEST(PrintBuiltInTypeTest, FloatingPoints) { - EXPECT_EQ("1.5", Print(1.5f)); // float - EXPECT_EQ("-2.5", Print(-2.5)); // double -} - -// Since ::std::stringstream::operator<<(const void *) formats the pointer -// output differently with different compilers, we have to create the expected -// output first and use it as our expectation. -static string PrintPointer(const void *p) { - ::std::stringstream expected_result_stream; - expected_result_stream << p; - return expected_result_stream.str(); -} - -// Tests printing C strings. - -// const char*. -TEST(PrintCStringTest, Const) { - const char* p = "World"; - EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); -} - -// char*. -TEST(PrintCStringTest, NonConst) { - char p[] = "Hi"; - EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", - Print(static_cast(p))); -} - -// NULL C string. -TEST(PrintCStringTest, Null) { - const char* p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// Tests that C strings are escaped properly. -TEST(PrintCStringTest, EscapesProperly) { - const char* p = "'\"\?\\\a\b\f\n\r\t\v\x7F\xFF a"; - EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"\\?\\\\\\a\\b\\f" - "\\n\\r\\t\\v\\x7F\\xFF a\"", - Print(p)); -} - - - -// MSVC compiler can be configured to define whar_t as a typedef -// of unsigned short. Defining an overload for const wchar_t* in that case -// would cause pointers to unsigned shorts be printed as wide strings, -// possibly accessing more memory than intended and causing invalid -// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when -// wchar_t is implemented as a native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - -// const wchar_t*. -TEST(PrintWideCStringTest, Const) { - const wchar_t* p = L"World"; - EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); -} - -// wchar_t*. -TEST(PrintWideCStringTest, NonConst) { - wchar_t p[] = L"Hi"; - EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", - Print(static_cast(p))); -} - -// NULL wide C string. -TEST(PrintWideCStringTest, Null) { - const wchar_t* p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// Tests that wide C strings are escaped properly. -TEST(PrintWideCStringTest, EscapesProperly) { - const wchar_t* p = L"'\"\?\\\a\b\f\n\r\t\v\xD3\x576\x8D3\xC74D a"; - EXPECT_EQ(PrintPointer(p) + " pointing to L\"'\\\"\\?\\\\\\a\\b\\f" - "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", - Print(p)); -} -#endif // native wchar_t - -// Tests printing pointers to other char types. - -// signed char*. -TEST(PrintCharPointerTest, SignedChar) { - signed char* p = reinterpret_cast(0x1234); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// const signed char*. -TEST(PrintCharPointerTest, ConstSignedChar) { - signed char* p = reinterpret_cast(0x1234); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// unsigned char*. -TEST(PrintCharPointerTest, UnsignedChar) { - unsigned char* p = reinterpret_cast(0x1234); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// const unsigned char*. -TEST(PrintCharPointerTest, ConstUnsignedChar) { - const unsigned char* p = reinterpret_cast(0x1234); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// Tests printing pointers to simple, built-in types. - -// bool*. -TEST(PrintPointerToBuiltInTypeTest, Bool) { - bool* p = reinterpret_cast(0xABCD); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// void*. -TEST(PrintPointerToBuiltInTypeTest, Void) { - void* p = reinterpret_cast(0xABCD); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// const void*. -TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { - const void* p = reinterpret_cast(0xABCD); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// Tests printing pointers to pointers. -TEST(PrintPointerToPointerTest, IntPointerPointer) { - int** p = reinterpret_cast(0xABCD); - EXPECT_EQ(PrintPointer(p), Print(p)); - p = NULL; - EXPECT_EQ("NULL", Print(p)); -} - -// Tests printing (non-member) function pointers. - -void MyFunction(int /* n */) {} - -TEST(PrintPointerTest, NonMemberFunctionPointer) { - // We cannot directly cast &MyFunction to const void* because the - // standard disallows casting between pointers to functions and - // pointers to objects, and some compilers (e.g. GCC 3.4) enforce - // this limitation. - EXPECT_EQ( - PrintPointer(reinterpret_cast( - reinterpret_cast(&MyFunction))), - Print(&MyFunction)); - int (*p)(bool) = NULL; // NOLINT - EXPECT_EQ("NULL", Print(p)); -} - -// Tests printing member variable pointers. Although they are called -// pointers, they don't point to a location in the address space. -// Their representation is implementation-defined. Thus they will be -// printed as raw bytes. - -struct Foo { - public: - virtual ~Foo() {} - int MyMethod(char x) { return x + 1; } - virtual char MyVirtualMethod(int /* n */) { return 'a'; } - - int value; -}; - -TEST(PrintPointerTest, MemberVariablePointer) { - EXPECT_THAT(Print(&Foo::value), - StartsWith(Print(sizeof(&Foo::value)) + "-byte object ")); - int (Foo::*p) = NULL; // NOLINT - EXPECT_THAT(Print(p), - StartsWith(Print(sizeof(p)) + "-byte object ")); -} - -// Tests printing member function pointers. Although they are called -// pointers, they don't point to a location in the address space. -// Their representation is implementation-defined. Thus they will be -// printed as raw bytes. -TEST(PrintPointerTest, MemberFunctionPointer) { - EXPECT_THAT(Print(&Foo::MyMethod), - StartsWith(Print(sizeof(&Foo::MyMethod)) + "-byte object ")); - EXPECT_THAT(Print(&Foo::MyVirtualMethod), - StartsWith(Print(sizeof((&Foo::MyVirtualMethod))) - + "-byte object ")); - int (Foo::*p)(char) = NULL; // NOLINT - EXPECT_THAT(Print(p), - StartsWith(Print(sizeof(p)) + "-byte object ")); -} - -// Tests printing C arrays. - -// The difference between this and Print() is that it ensures that the -// argument is a reference to an array. -template -string PrintArrayHelper(T (&a)[N]) { - return Print(a); -} - -// One-dimensional array. -TEST(PrintArrayTest, OneDimensionalArray) { - int a[5] = { 1, 2, 3, 4, 5 }; - EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); -} - -// Two-dimensional array. -TEST(PrintArrayTest, TwoDimensionalArray) { - int a[2][5] = { - { 1, 2, 3, 4, 5 }, - { 6, 7, 8, 9, 0 } - }; - EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); -} - -// Array of const elements. -TEST(PrintArrayTest, ConstArray) { - const bool a[1] = { false }; - EXPECT_EQ("{ false }", PrintArrayHelper(a)); -} - -// Char array. -TEST(PrintArrayTest, CharArray) { - // Array a contains '\0' in the middle and doesn't end with '\0'. - char a[3] = { 'H', '\0', 'i' }; - EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a)); -} - -// Const char array. -TEST(PrintArrayTest, ConstCharArray) { - const char a[4] = "\0Hi"; - EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a)); -} - -// Array of objects. -TEST(PrintArrayTest, ObjectArray) { - string a[3] = { "Hi", "Hello", "Ni hao" }; - EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); -} - -// Array with many elements. -TEST(PrintArrayTest, BigArray) { - int a[100] = { 1, 2, 3 }; - EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", - PrintArrayHelper(a)); -} - -// Tests printing ::string and ::std::string. - -#if GTEST_HAS_GLOBAL_STRING -// ::string. -TEST(PrintStringTest, StringInGlobalNamespace) { - const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; - const ::string str(s, sizeof(s)); - EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", - Print(str)); -} -#endif // GTEST_HAS_GLOBAL_STRING - -// ::std::string. -TEST(PrintStringTest, StringInStdNamespace) { - const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; - const ::std::string str(s, sizeof(s)); - EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", - Print(str)); -} - -// Tests printing ::wstring and ::std::wstring. - -#if GTEST_HAS_GLOBAL_WSTRING -// ::wstring. -TEST(PrintWideStringTest, StringInGlobalNamespace) { - const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; - const ::wstring str(s, sizeof(s)/sizeof(wchar_t)); - EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" - "\\xD3\\x576\\x8D3\\xC74D a\\0\"", - Print(str)); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -// ::std::wstring. -TEST(PrintWideStringTest, StringInStdNamespace) { - const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; - const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); - EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" - "\\xD3\\x576\\x8D3\\xC74D a\\0\"", - Print(str)); -} -#endif // GTEST_HAS_STD_WSTRING - -// Tests printing types that support generic streaming (i.e. streaming -// to std::basic_ostream for any valid Char and -// CharTraits types). - -// Tests printing a non-template type that supports generic streaming. - -class AllowsGenericStreaming {}; - -template -std::basic_ostream& operator<<( - std::basic_ostream& os, - const AllowsGenericStreaming& /* a */) { - return os << "AllowsGenericStreaming"; -} - -TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { - AllowsGenericStreaming a; - EXPECT_EQ("AllowsGenericStreaming", Print(a)); -} - -// Tests printing a template type that supports generic streaming. - -template -class AllowsGenericStreamingTemplate {}; - -template -std::basic_ostream& operator<<( - std::basic_ostream& os, - const AllowsGenericStreamingTemplate& /* a */) { - return os << "AllowsGenericStreamingTemplate"; -} - -TEST(PrintTypeWithGenericStreamingTest, TemplateType) { - AllowsGenericStreamingTemplate a; - EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); -} - -// Tests printing a type that supports generic streaming and can be -// implicitly converted to another printable type. - -template -class AllowsGenericStreamingAndImplicitConversionTemplate { - public: - operator bool() const { return false; } -}; - -template -std::basic_ostream& operator<<( - std::basic_ostream& os, - const AllowsGenericStreamingAndImplicitConversionTemplate& /* a */) { - return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; -} - -TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { - AllowsGenericStreamingAndImplicitConversionTemplate a; - EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); -} - -// Tests printing STL containers. - -TEST(PrintStlContainerTest, EmptyDeque) { - deque empty; - EXPECT_EQ("{}", Print(empty)); -} - -TEST(PrintStlContainerTest, NonEmptyDeque) { - deque non_empty; - non_empty.push_back(1); - non_empty.push_back(3); - EXPECT_EQ("{ 1, 3 }", Print(non_empty)); -} - -#if GMOCK_HAS_HASH_MAP_ - -TEST(PrintStlContainerTest, OneElementHashMap) { - hash_map map1; - map1[1] = 'a'; - EXPECT_EQ("{ (1, 'a' (97)) }", Print(map1)); -} - -TEST(PrintStlContainerTest, HashMultiMap) { - hash_multimap map1; - map1.insert(make_pair(5, true)); - map1.insert(make_pair(5, false)); - - // Elements of hash_multimap can be printed in any order. - const string result = Print(map1); - EXPECT_TRUE(result == "{ (5, true), (5, false) }" || - result == "{ (5, false), (5, true) }") - << " where Print(map1) returns \"" << result << "\"."; -} - -#endif // GMOCK_HAS_HASH_MAP_ - -#if GMOCK_HAS_HASH_SET_ - -TEST(PrintStlContainerTest, HashSet) { - hash_set set1; - set1.insert("hello"); - EXPECT_EQ("{ \"hello\" }", Print(set1)); -} - -TEST(PrintStlContainerTest, HashMultiSet) { - const int kSize = 5; - int a[kSize] = { 1, 1, 2, 5, 1 }; - hash_multiset set1(a, a + kSize); - - // Elements of hash_multiset can be printed in any order. - const string result = Print(set1); - const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. - - // Verifies the result matches the expected pattern; also extracts - // the numbers in the result. - ASSERT_EQ(expected_pattern.length(), result.length()); - std::vector numbers; - for (size_t i = 0; i != result.length(); i++) { - if (expected_pattern[i] == 'd') { - ASSERT_TRUE(isdigit(result[i]) != 0); - numbers.push_back(result[i] - '0'); - } else { - EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " - << result; - } - } - - // Makes sure the result contains the right numbers. - std::sort(numbers.begin(), numbers.end()); - std::sort(a, a + kSize); - EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); -} - -#endif // GMOCK_HAS_HASH_SET_ - -TEST(PrintStlContainerTest, List) { - const char* a[] = { - "hello", - "world" - }; - const list strings(a, a + 2); - EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); -} - -TEST(PrintStlContainerTest, Map) { - map map1; - map1[1] = true; - map1[5] = false; - map1[3] = true; - EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); -} - -TEST(PrintStlContainerTest, MultiMap) { - multimap map1; - map1.insert(make_pair(true, 0)); - map1.insert(make_pair(true, 1)); - map1.insert(make_pair(false, 2)); - EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); -} - -TEST(PrintStlContainerTest, Set) { - const unsigned int a[] = { 3, 0, 5 }; - set set1(a, a + 3); - EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); -} - -TEST(PrintStlContainerTest, MultiSet) { - const int a[] = { 1, 1, 2, 5, 1 }; - multiset set1(a, a + 5); - EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); -} - -TEST(PrintStlContainerTest, Pair) { - pair p(true, 5); - EXPECT_EQ("(true, 5)", Print(p)); -} - -TEST(PrintStlContainerTest, Vector) { - vector v; - v.push_back(1); - v.push_back(2); - EXPECT_EQ("{ 1, 2 }", Print(v)); -} - -TEST(PrintStlContainerTest, LongSequence) { - const int a[100] = { 1, 2, 3 }; - const vector v(a, a + 100); - EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " - "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v)); -} - -TEST(PrintStlContainerTest, NestedContainer) { - const int a1[] = { 1, 2 }; - const int a2[] = { 3, 4, 5 }; - const list l1(a1, a1 + 2); - const list l2(a2, a2 + 3); - - vector > v; - v.push_back(l1); - v.push_back(l2); - EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); -} - -TEST(PrintStlContainerTest, OneDimensionalNativeArray) { - const int a[3] = { 1, 2, 3 }; - NativeArray b(a, 3, kReference); - EXPECT_EQ("{ 1, 2, 3 }", Print(b)); -} - -TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { - const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; - NativeArray b(a, 2, kReference); - EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); -} - -// Tests printing tuples. - -// Tuples of various arities. -TEST(PrintTupleTest, VariousSizes) { - tuple<> t0; - EXPECT_EQ("()", Print(t0)); - - tuple t1(5); - EXPECT_EQ("(5)", Print(t1)); - - tuple t2('a', true); - EXPECT_EQ("('a' (97), true)", Print(t2)); - - tuple t3(false, 2, 3); - EXPECT_EQ("(false, 2, 3)", Print(t3)); - - tuple t4(false, 2, 3, 4); - EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); - - tuple t5(false, 2, 3, 4, true); - EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); - - tuple t6(false, 2, 3, 4, true, 6); - EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); - - tuple t7(false, 2, 3, 4, true, 6, 7); - EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); - - tuple t8( - false, 2, 3, 4, true, 6, 7, true); - EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); - - tuple t9( - false, 2, 3, 4, true, 6, 7, true, 9); - EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); - - const char* const str = "8"; - tuple - t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, NULL, "10"); - EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + - " pointing to \"8\", NULL, \"10\")", - Print(t10)); -} - -// Nested tuples. -TEST(PrintTupleTest, NestedTuple) { - tuple, char> nested(make_tuple(5, true), 'a'); - EXPECT_EQ("((5, true), 'a' (97))", Print(nested)); -} - -// Tests printing user-defined unprintable types. - -// Unprintable types in the global namespace. -TEST(PrintUnprintableTypeTest, InGlobalNamespace) { - EXPECT_EQ("1-byte object <00>", - Print(UnprintableTemplateInGlobal())); -} - -// Unprintable types in a user namespace. -TEST(PrintUnprintableTypeTest, InUserNamespace) { - EXPECT_EQ("16-byte object ", - Print(::foo::UnprintableInFoo())); -} - -// Unprintable types are that too big to be printed completely. - -struct Big { - Big() { memset(array, 0, sizeof(array)); } - char array[257]; -}; - -TEST(PrintUnpritableTypeTest, BigObject) { - EXPECT_EQ("257-byte object <0000 0000 0000 0000 0000 0000 " - "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " - "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " - "0000 0000 0000 0000 0000 0000 ... 0000 0000 0000 " - "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " - "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " - "0000 0000 0000 0000 0000 0000 0000 0000 00>", - Print(Big())); -} - -// Tests printing user-defined streamable types. - -// Streamable types in the global namespace. -TEST(PrintStreamableTypeTest, InGlobalNamespace) { - EXPECT_EQ("StreamableInGlobal", - Print(StreamableInGlobal())); -} - -// Printable template types in a user namespace. -TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { - EXPECT_EQ("StreamableTemplateInFoo: 0", - Print(::foo::StreamableTemplateInFoo())); -} - -// Tests printing user-defined types that have a PrintTo() function. -TEST(PrintPrintableTypeTest, InUserNamespace) { - EXPECT_EQ("PrintableViaPrintTo: 0", - Print(::foo::PrintableViaPrintTo())); -} - -// Tests printing user-defined class template that have a PrintTo() function. -TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { - EXPECT_EQ("PrintableViaPrintToTemplate: 5", - Print(::foo::PrintableViaPrintToTemplate(5))); -} - -#if GMOCK_HAS_PROTOBUF_ - -// Tests printing a protocol message. -TEST(PrintProtocolMessageTest, PrintsShortDebugString) { - testing::internal::TestMessage msg; - msg.set_member("yes"); - EXPECT_EQ("", Print(msg)); -} - -// Tests printing a short proto2 message. -TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) { - testing::internal::FooMessage msg; - msg.set_int_field(2); - msg.set_string_field("hello"); - EXPECT_PRED2(RE::FullMatch, Print(msg), - ""); -} - -// Tests printing a long proto2 message. -TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong) { - testing::internal::FooMessage msg; - msg.set_int_field(2); - msg.set_string_field("hello"); - msg.add_names("peter"); - msg.add_names("paul"); - msg.add_names("mary"); - EXPECT_PRED2(RE::FullMatch, Print(msg), - "<\n" - "int_field:\\s*2\n" - "string_field:\\s*\"hello\"\n" - "names:\\s*\"peter\"\n" - "names:\\s*\"paul\"\n" - "names:\\s*\"mary\"\n" - ">"); -} - -#endif // GMOCK_HAS_PROTOBUF_ - -// Tests that the universal printer prints both the address and the -// value of a reference. -TEST(PrintReferenceTest, PrintsAddressAndValue) { - int n = 5; - EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); - - int a[2][3] = { - { 0, 1, 2 }, - { 3, 4, 5 } - }; - EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", - PrintByRef(a)); - - const ::foo::UnprintableInFoo x; - EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " - "", - PrintByRef(x)); -} - -// Tests that the universal printer prints a function pointer passed by -// reference. -TEST(PrintReferenceTest, HandlesFunctionPointer) { - void (*fp)(int n) = &MyFunction; - const string fp_pointer_string = - PrintPointer(reinterpret_cast(&fp)); - // We cannot directly cast &MyFunction to const void* because the - // standard disallows casting between pointers to functions and - // pointers to objects, and some compilers (e.g. GCC 3.4) enforce - // this limitation. - const string fp_string = PrintPointer(reinterpret_cast( - reinterpret_cast(fp))); - EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, - PrintByRef(fp)); -} - -// Tests that the universal printer prints a member function pointer -// passed by reference. -TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { - int (Foo::*p)(char ch) = &Foo::MyMethod; - EXPECT_THAT(PrintByRef(p), - StartsWith("@" + PrintPointer(reinterpret_cast(&p)) - + " " + Print(sizeof(p)) + "-byte object ")); - - char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; - EXPECT_THAT(PrintByRef(p2), - StartsWith("@" + PrintPointer(reinterpret_cast(&p2)) - + " " + Print(sizeof(p2)) + "-byte object ")); -} - -// Tests that the universal printer prints a member variable pointer -// passed by reference. -TEST(PrintReferenceTest, HandlesMemberVariablePointer) { - int (Foo::*p) = &Foo::value; // NOLINT - EXPECT_THAT(PrintByRef(p), - StartsWith("@" + PrintPointer(&p) - + " " + Print(sizeof(p)) + "-byte object ")); -} - -TEST(PrintToStringTest, WorksForScalar) { - EXPECT_EQ("123", PrintToString(123)); -} - -TEST(PrintToStringTest, WorksForPointerToConstChar) { - const char* p = "hello"; - EXPECT_EQ("\"hello\"", PrintToString(p)); -} - -TEST(PrintToStringTest, WorksForPointerToNonConstChar) { - char s[] = "hello"; - char* p = s; - EXPECT_EQ("\"hello\"", PrintToString(p)); -} - -TEST(PrintToStringTest, WorksForArray) { - int n[3] = { 1, 2, 3 }; - EXPECT_EQ("{ 1, 2, 3 }", PrintToString(n)); -} - -TEST(UniversalTersePrintTest, WorksForNonReference) { - ::std::stringstream ss; - UniversalTersePrint(123, &ss); - EXPECT_EQ("123", ss.str()); -} - -TEST(UniversalTersePrintTest, WorksForReference) { - const int& n = 123; - ::std::stringstream ss; - UniversalTersePrint(n, &ss); - EXPECT_EQ("123", ss.str()); -} - -TEST(UniversalTersePrintTest, WorksForCString) { - const char* s1 = "abc"; - ::std::stringstream ss1; - UniversalTersePrint(s1, &ss1); - EXPECT_EQ("\"abc\"", ss1.str()); - - char* s2 = const_cast(s1); - ::std::stringstream ss2; - UniversalTersePrint(s2, &ss2); - EXPECT_EQ("\"abc\"", ss2.str()); - - const char* s3 = NULL; - ::std::stringstream ss3; - UniversalTersePrint(s3, &ss3); - EXPECT_EQ("NULL", ss3.str()); -} - -TEST(UniversalPrintTest, WorksForNonReference) { - ::std::stringstream ss; - UniversalPrint(123, &ss); - EXPECT_EQ("123", ss.str()); -} - -TEST(UniversalPrintTest, WorksForReference) { - const int& n = 123; - ::std::stringstream ss; - UniversalPrint(n, &ss); - EXPECT_EQ("123", ss.str()); -} - -TEST(UniversalPrintTest, WorksForCString) { - const char* s1 = "abc"; - ::std::stringstream ss1; - UniversalPrint(s1, &ss1); - EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str())); - - char* s2 = const_cast(s1); - ::std::stringstream ss2; - UniversalPrint(s2, &ss2); - EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str())); - - const char* s3 = NULL; - ::std::stringstream ss3; - UniversalPrint(s3, &ss3); - EXPECT_EQ("NULL", ss3.str()); -} - - -TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) { - EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple()), - ElementsAre()); -} - -TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple) { - EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple(1)), - ElementsAre("1")); -} - -TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple) { - EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a')), - ElementsAre("1", "'a' (97)")); -} - -TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely) { - const int n = 1; - EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings( - tuple(n, "a")), - ElementsAre("1", "\"a\"")); -} - -} // namespace gmock_printers_test -} // namespace testing diff --git a/test/gmock_all_test.cc b/test/gmock_all_test.cc index 73612591..691aac84 100644 --- a/test/gmock_all_test.cc +++ b/test/gmock_all_test.cc @@ -44,6 +44,5 @@ #include "test/gmock-more-actions_test.cc" #include "test/gmock-nice-strict_test.cc" #include "test/gmock-port_test.cc" -#include "test/gmock-printers_test.cc" #include "test/gmock-spec-builders_test.cc" #include "test/gmock_test.cc" -- cgit v1.2.3 From e2e8ba401d198d1a8304c652e997505609b62696 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 13 May 2010 18:16:03 +0000 Subject: Renames test script flags. --- include/gmock/gmock-matchers.h | 27 ++++++++--------- include/gmock/gmock-more-actions.h | 10 +++++++ include/gmock/gmock-spec-builders.h | 5 ++-- run_tests.py | 1 - test/gmock_output_test.py | 2 +- test/gmock_test_utils.py | 60 ++----------------------------------- 6 files changed, 29 insertions(+), 76 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index fbbf5811..7f84761e 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -702,11 +702,11 @@ class AnythingMatcher { } \ virtual void DescribeTo(::std::ostream* os) const { \ *os << relation " "; \ - UniversalPrinter::Print(rhs_, os); \ + UniversalPrint(rhs_, os); \ } \ virtual void DescribeNegationTo(::std::ostream* os) const { \ *os << negated_relation " "; \ - UniversalPrinter::Print(rhs_, os); \ + UniversalPrint(rhs_, os); \ } \ private: \ Rhs rhs_; \ @@ -910,7 +910,7 @@ class StrEqualityMatcher { if (!case_sensitive_) { *os << "(ignoring case) "; } - UniversalPrinter::Print(string_, os); + UniversalPrint(string_, os); } const StringType string_; @@ -947,12 +947,12 @@ class HasSubstrMatcher { // Describes what this matcher matches. void DescribeTo(::std::ostream* os) const { *os << "has substring "; - UniversalPrinter::Print(substring_, os); + UniversalPrint(substring_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "has no substring "; - UniversalPrinter::Print(substring_, os); + UniversalPrint(substring_, os); } private: @@ -988,12 +988,12 @@ class StartsWithMatcher { void DescribeTo(::std::ostream* os) const { *os << "starts with "; - UniversalPrinter::Print(prefix_, os); + UniversalPrint(prefix_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't start with "; - UniversalPrinter::Print(prefix_, os); + UniversalPrint(prefix_, os); } private: @@ -1028,12 +1028,12 @@ class EndsWithMatcher { void DescribeTo(::std::ostream* os) const { *os << "ends with "; - UniversalPrinter::Print(suffix_, os); + UniversalPrint(suffix_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't end with "; - UniversalPrinter::Print(suffix_, os); + UniversalPrint(suffix_, os); } private: @@ -1879,11 +1879,11 @@ class ContainerEqMatcher { void DescribeTo(::std::ostream* os) const { *os << "equals "; - UniversalPrinter::Print(rhs_, os); + UniversalPrint(rhs_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "does not equal "; - UniversalPrinter::Print(rhs_, os); + UniversalPrint(rhs_, os); } template @@ -1913,8 +1913,7 @@ class ContainerEqMatcher { *os << "which has these unexpected elements: "; printed_header = true; } - UniversalPrinter:: - Print(*it, os); + UniversalPrint(*it, os); } } @@ -1932,7 +1931,7 @@ class ContainerEqMatcher { << " doesn't have these expected elements: "; printed_header2 = true; } - UniversalPrinter::Print(*it, os); + UniversalPrint(*it, os); } } } diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index 9a6fe969..6d686cd1 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -198,7 +198,17 @@ ACTION_TEMPLATE(DeleteArg, // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS + +// Suppresses the 'unreachable code' warning that VC generates in opt modes. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4702) // Temporarily disables warning 4702. +#endif ACTION_P(Throw, exception) { throw exception; } +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif + #endif // GTEST_HAS_EXCEPTIONS #ifdef _MSC_VER diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 67c7a697..7038c2e4 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1268,6 +1268,7 @@ class ActionResultHolder { // Prints the held value as an action's result to os. void PrintAsActionResult(::std::ostream* os) const { *os << "\n Returns: "; + // T may be a reference type, so we don't use UniversalPrint(). UniversalPrinter::Print(value_, os); } @@ -1539,7 +1540,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { *os << "Uninteresting mock function call - "; DescribeDefaultActionTo(args, os); *os << " Function call: " << Name(); - UniversalPrinter::Print(args, os); + UniversalPrint(args, os); } // Critical section: We must find the matching expectation and the @@ -1775,7 +1776,7 @@ typename Function::Result FunctionMockerBase::InvokeWith( } ss << " Function call: " << Name(); - UniversalPrinter::Print(args, &ss); + UniversalPrint(args, &ss); // In case the action deletes a piece of the expectation, we // generate the message beforehand. diff --git a/run_tests.py b/run_tests.py index 42dc14bf..5e7b308f 100755 --- a/run_tests.py +++ b/run_tests.py @@ -68,7 +68,6 @@ def _Main(): options, args = run_tests_util.ParseArgs('gtest') test_runner = run_tests_util.TestRunner( script_dir=SCRIPT_DIR, - build_dir_var_name='GMOCK_BUILD_DIR', injected_build_dir_finder=GetGmockBuildDir) tests = test_runner.GetTestsToRun(args, options.configurations, diff --git a/test/gmock_output_test.py b/test/gmock_output_test.py index 614a58fa..eced8a81 100755 --- a/test/gmock_output_test.py +++ b/test/gmock_output_test.py @@ -32,7 +32,7 @@ """Tests the text output of Google C++ Mocking Framework. SYNOPSIS - gmock_output_test.py --gmock_build_dir=BUILD/DIR --gengolden + gmock_output_test.py --build_dir=BUILD/DIR --gengolden # where BUILD/DIR contains the built gmock_output_test_ file. gmock_output_test.py --gengolden gmock_output_test.py diff --git a/test/gmock_test_utils.py b/test/gmock_test_utils.py index fa896a47..ac3d67ae 100755 --- a/test/gmock_test_utils.py +++ b/test/gmock_test_utils.py @@ -51,62 +51,10 @@ sys.path.append(GTEST_TESTS_UTIL_DIR) import gtest_test_utils # pylint: disable-msg=C6204 -# Initially maps a flag to its default value. After -# _ParseAndStripGMockFlags() is called, maps a flag to its actual -# value. -_flag_map = {'gmock_source_dir': os.path.dirname(sys.argv[0]), - 'gmock_build_dir': os.path.dirname(sys.argv[0])} -_gmock_flags_are_parsed = False - - -def _ParseAndStripGMockFlags(argv): - """Parses and strips Google Test flags from argv. This is idempotent.""" - - global _gmock_flags_are_parsed - if _gmock_flags_are_parsed: - return - - _gmock_flags_are_parsed = True - for flag in _flag_map: - # The environment variable overrides the default value. - if flag.upper() in os.environ: - _flag_map[flag] = os.environ[flag.upper()] - - # The command line flag overrides the environment variable. - i = 1 # Skips the program name. - while i < len(argv): - prefix = '--' + flag + '=' - if argv[i].startswith(prefix): - _flag_map[flag] = argv[i][len(prefix):] - del argv[i] - break - else: - # We don't increment i in case we just found a --gmock_* flag - # and removed it from argv. - i += 1 - - -def GetFlag(flag): - """Returns the value of the given flag.""" - - # In case GetFlag() is called before Main(), we always call - # _ParseAndStripGMockFlags() here to make sure the --gmock_* flags - # are parsed. - _ParseAndStripGMockFlags(sys.argv) - - return _flag_map[flag] - - def GetSourceDir(): """Returns the absolute path of the directory where the .py files are.""" - return os.path.abspath(GetFlag('gmock_source_dir')) - - -def GetBuildDir(): - """Returns the absolute path of the directory where the test binaries are.""" - - return os.path.abspath(GetFlag('gmock_build_dir')) + return gtest_test_utils.GetSourceDir() def GetTestExecutablePath(executable_name): @@ -122,7 +70,7 @@ def GetTestExecutablePath(executable_name): The absolute path of the test binary. """ - return gtest_test_utils.GetTestExecutablePath(executable_name, GetBuildDir()) + return gtest_test_utils.GetTestExecutablePath(executable_name) def GetExitStatus(exit_code): @@ -160,8 +108,4 @@ TestCase = gtest_test_utils.TestCase def Main(): """Runs the unit test.""" - # We must call _ParseAndStripGMockFlags() before calling - # gtest_test_utils.Main(). Otherwise unittest.main it calls will be - # confused by the --gmock_* flags. - _ParseAndStripGMockFlags(sys.argv) gtest_test_utils.Main() -- cgit v1.2.3 From 0f3f5012d81da1f6dcb589e0e11ae8e345a642b3 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 13 May 2010 18:19:26 +0000 Subject: Adds CMake build script. --- CMakeLists.txt | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..9c3b5edd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,155 @@ +######################################################################## +# Experimental CMake build script for Google Mock. +# +# Consider this a prototype. It will change drastically. For now, +# this is only for people on the cutting edge. +# +# 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) + +# Forses BUILD_SHARED_LIBS to OFF as Google Mock currently does not support +# working in a DLL. +# TODO(vladl@google.com): Implement building gMock as a DLL. +set(BUILD_SHARED_LIBS OFF) + +option(gmock_build_tests "Build all of Google Mock's own tests." OFF) + +# A directory to find Google Test sources. +if (EXISTS gtest/CMakeLists.txt) + set(gtest_dir gtest) +else() + set(gtest_dir ../gtest) +endif() + +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() + +# Defines functions and variables used by Google Mock. +include("${gtest_dir}/cmake/internal_utils.cmake") + +# Google Test also calls this function from add_subdirectory, +# although its changes will not affect things at the current scope. +fix_default_settings() # Defined in internal_utils.cmake. + +# 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") + +# 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}") + +######################################################################## +# +# 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}" src/gmock-all.cc) +target_link_libraries(gmock gtest) + +cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc) +target_link_libraries(gmock_main gmock) + +######################################################################## +# +# 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-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_stress_test gmock) + cxx_test(gmock_test gmock_main) + + # 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) + 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-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_test_with_flags(gmock_use_own_tuple_test "${cxx_use_own_tuple}" + gmock_main_use_own_tuple test/gmock-spec-builders_test.cc) + + ############################################################ + # 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() -- cgit v1.2.3 From ab5b77c179009b787d71ff934eaf4a0db6c24814 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 17 May 2010 19:32:48 +0000 Subject: Implements Pointwise(). --- include/gmock/gmock-generated-matchers.h | 32 ++-- include/gmock/gmock-generated-matchers.h.pump | 5 +- include/gmock/gmock-matchers.h | 184 +++++++++++++++++++---- test/gmock-generated-matchers_test.cc | 9 +- test/gmock-matchers_test.cc | 204 +++++++++++++++++++++----- test/gmock_output_test_golden.txt | 6 +- 6 files changed, 344 insertions(+), 96 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 90f3750e..2790e06c 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -221,7 +221,7 @@ template { public: // ArgsTuple may have top-level const or reference modifiers. - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; @@ -314,8 +314,7 @@ class ElementsAreMatcher1 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -343,8 +342,7 @@ class ElementsAreMatcher2 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -371,8 +369,7 @@ class ElementsAreMatcher3 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -401,8 +398,7 @@ class ElementsAreMatcher4 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -433,8 +429,7 @@ class ElementsAreMatcher5 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -469,8 +464,7 @@ class ElementsAreMatcher6 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -507,8 +501,7 @@ class ElementsAreMatcher7 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -547,8 +540,7 @@ class ElementsAreMatcher8 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -590,8 +582,7 @@ class ElementsAreMatcher9 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -635,8 +626,7 @@ class ElementsAreMatcher10 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 2f325b04..db498ec0 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -107,7 +107,7 @@ template class ArgsMatcherImpl : public MatcherInterface { public: // ArgsTuple may have top-level const or reference modifiers. - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; @@ -200,8 +200,7 @@ class ElementsAreMatcher$i { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 7f84761e..2a42bf94 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -43,6 +43,7 @@ #include // NOLINT #include #include +#include #include #include @@ -427,8 +428,8 @@ class SafeMatcherCastImpl { 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_CONST_(GTEST_REMOVE_REFERENCE_(T)) RawT; - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(U)) RawU; + 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_( @@ -1095,38 +1096,46 @@ class MatchesRegexMatcher { // // We define this as a macro in order to eliminate duplicated source // code. -#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op) \ +#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \ class name##2Matcher { \ public: \ + template \ + operator Matcher< ::std::tr1::tuple >() const { \ + return MakeMatcher(new Impl< ::std::tr1::tuple >); \ + } \ template \ operator Matcher&>() const { \ - return MakeMatcher(new Impl); \ + return MakeMatcher(new Impl&>); \ } \ private: \ - template \ - class Impl : public MatcherInterface&> { \ + template \ + class Impl : public MatcherInterface { \ public: \ virtual bool MatchAndExplain( \ - const ::std::tr1::tuple& args, \ + Tuple args, \ MatchResultListener* /* listener */) const { \ return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ } \ virtual void DescribeTo(::std::ostream* os) const { \ - *os << "are a pair (x, y) where x " #op " y"; \ + *os << "are " relation; \ } \ virtual void DescribeNegationTo(::std::ostream* os) const { \ - *os << "are a pair (x, y) where x " #op " y is false"; \ + *os << "aren't " relation; \ } \ }; \ } // Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ge, >=); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Gt, >); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Le, <=); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Lt, <); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==, "an equal pair"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Ge, >=, "a pair where the first >= the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Gt, >, "a pair where the first > the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Le, <=, "a pair where the first <= the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( + Lt, <, "a pair where the first < the second"); +GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "an unequal pair"); #undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ @@ -1873,8 +1882,8 @@ class ContainerEqMatcher { explicit ContainerEqMatcher(const Container& rhs) : rhs_(View::Copy(rhs)) { // Makes sure the user doesn't instantiate this class template // with a const or reference type. - testing::StaticAssertTypeEq(); + (void)testing::StaticAssertTypeEq(); } void DescribeTo(::std::ostream* os) const { @@ -1945,11 +1954,121 @@ class ContainerEqMatcher { GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; +// Implements Pointwise(tuple_matcher, rhs_container). tuple_matcher +// must be able to be safely cast to Matcher >, where T1 and T2 are the types of elements in the LHS +// container and the RHS container respectively. +template +class PointwiseMatcher { + public: + typedef internal::StlContainerView RhsView; + typedef typename RhsView::type RhsStlContainer; + typedef typename RhsStlContainer::value_type RhsValue; + + // Like ContainerEq, we make a copy of rhs in case the elements in + // it are modified after this matcher is created. + PointwiseMatcher(const TupleMatcher& tuple_matcher, const RhsContainer& rhs) + : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) { + // Makes sure the user doesn't instantiate this class template + // with a const or reference type. + (void)testing::StaticAssertTypeEq(); + } + + template + operator Matcher() const { + return MakeMatcher(new Impl(tuple_matcher_, rhs_)); + } + + template + class Impl : public MatcherInterface { + public: + typedef internal::StlContainerView< + GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView; + typedef typename LhsView::type LhsStlContainer; + typedef typename LhsView::const_reference LhsStlContainerReference; + typedef typename LhsStlContainer::value_type LhsValue; + // We pass the LHS value and the RHS value to the inner matcher by + // reference, as they may be expensive to copy. We must use tuple + // instead of pair here, as a pair cannot hold references (C++ 98, + // 20.2.2 [lib.pairs]). + typedef std::tr1::tuple InnerMatcherArg; + + Impl(const TupleMatcher& tuple_matcher, const RhsStlContainer& rhs) + // mono_tuple_matcher_ holds a monomorphic version of the tuple matcher. + : mono_tuple_matcher_(SafeMatcherCast(tuple_matcher)), + rhs_(rhs) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "contains " << rhs_.size() + << " values, where each value and its corresponding value in "; + UniversalPrinter::Print(rhs_, os); + *os << " "; + mono_tuple_matcher_.DescribeTo(os); + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't contain exactly " << rhs_.size() + << " values, or contains a value x at some index i" + << " where x and the i-th value of "; + UniversalPrint(rhs_, os); + *os << " "; + mono_tuple_matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(LhsContainer lhs, + MatchResultListener* listener) const { + LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + const size_t actual_size = lhs_stl_container.size(); + if (actual_size != rhs_.size()) { + *listener << "which contains " << actual_size << " values"; + return false; + } + + typename LhsStlContainer::const_iterator left = lhs_stl_container.begin(); + typename RhsStlContainer::const_iterator right = rhs_.begin(); + for (size_t i = 0; i != actual_size; ++i, ++left, ++right) { + const InnerMatcherArg value_pair(*left, *right); + + if (listener->IsInterested()) { + StringMatchResultListener inner_listener; + if (!mono_tuple_matcher_.MatchAndExplain( + value_pair, &inner_listener)) { + *listener << "where the value pair ("; + UniversalPrint(*left, listener->stream()); + *listener << ", "; + UniversalPrint(*right, listener->stream()); + *listener << ") at index #" << i << " don't match"; + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return false; + } + } else { + if (!mono_tuple_matcher_.Matches(value_pair)) + return false; + } + } + + return true; + } + + private: + const Matcher mono_tuple_matcher_; + const RhsStlContainer rhs_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + private: + const TupleMatcher tuple_matcher_; + const RhsStlContainer rhs_; + + GTEST_DISALLOW_ASSIGN_(PointwiseMatcher); +}; + // Holds the logic common to ContainsMatcherImpl and EachMatcherImpl. template class QuantifierMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; @@ -2088,7 +2207,7 @@ class EachMatcher { template class KeyMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType; typedef typename RawPairType::first_type KeyType; template @@ -2150,7 +2269,7 @@ class KeyMatcher { template class PairMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType; typedef typename RawPairType::first_type FirstType; typedef typename RawPairType::second_type SecondType; @@ -2257,7 +2376,7 @@ class PairMatcher { template class ElementsAreMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef internal::StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; @@ -2376,8 +2495,7 @@ class ElementsAreMatcher0 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -2395,8 +2513,7 @@ class ElementsAreArrayMatcher { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -2900,6 +3017,23 @@ inline PolymorphicMatcher(rhs)); } +// Matches an STL-style container or a native array that contains the +// same number of elements as in rhs, where its i-th element and rhs's +// i-th element (as a pair) satisfy the given pair matcher, for all i. +// TupleMatcher must be able to be safely cast to Matcher >, where T1 and T2 are the types of elements in the +// LHS container and the RHS container respectively. +template +inline internal::PointwiseMatcher +Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) { + // This following line is for working around a bug in MSVC 8.0, + // which causes Container to be a const type sometimes. + typedef GTEST_REMOVE_CONST_(Container) RawContainer; + return internal::PointwiseMatcher( + tuple_matcher, rhs); +} + // Matches an STL-style container or a native array that contains at // least one element matching the given value or matcher. // diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 12479af4..eebca8a0 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -192,7 +192,8 @@ TEST(ArgsTest, AcceptsTenTemplateArgs) { TEST(ArgsTest, DescirbesSelfCorrectly) { const Matcher > m = Args<2, 0>(Lt()); - EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair (x, y) where x < y", + EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair where " + "the first < the second", Describe(m)); } @@ -200,14 +201,14 @@ TEST(ArgsTest, DescirbesNestedArgsCorrectly) { const Matcher&> m = Args<0, 2, 3>(Args<2, 0>(Lt())); EXPECT_EQ("are a tuple whose fields (#0, #2, #3) are a tuple " - "whose fields (#2, #0) are a pair (x, y) where x < y", + "whose fields (#2, #0) are a pair where the first < the second", Describe(m)); } TEST(ArgsTest, DescribesNegationCorrectly) { const Matcher > m = Args<1, 0>(Gt()); - EXPECT_EQ("are a tuple whose fields (#1, #0) are a pair (x, y) " - "where x > y is false", + EXPECT_EQ("are a tuple whose fields (#1, #0) aren't a pair " + "where the first > the second", DescribeNegation(m)); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index a7c217d4..3b151dbd 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -61,13 +61,18 @@ bool SkipPrefix(const char* prefix, const char** pstr); namespace gmock_matchers_test { +using std::list; using std::make_pair; using std::map; using std::multimap; +using std::multiset; +using std::ostream; using std::pair; using std::set; using std::stringstream; +using std::tr1::get; using std::tr1::make_tuple; +using std::tr1::tuple; using std::vector; using testing::A; using testing::AllArgs; @@ -104,6 +109,7 @@ using testing::Not; using testing::NotNull; using testing::Pair; using testing::Pointee; +using testing::Pointwise; using testing::PolymorphicMatcher; using testing::Property; using testing::Ref; @@ -144,7 +150,7 @@ class GreaterThanMatcher : public MatcherInterface { public: explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - virtual void DescribeTo(::std::ostream* os) const { + virtual void DescribeTo(ostream* os) const { *os << "is > " << rhs_; } @@ -189,9 +195,9 @@ string DescribeNegation(const Matcher& m) { // Returns the reason why x matches, or doesn't match, m. template string Explain(const MatcherType& m, const Value& x) { - stringstream ss; - m.ExplainMatchResultTo(x, &ss); - return ss.str(); + StringMatchResultListener listener; + ExplainMatchResult(m, x, &listener); + return listener.str(); } TEST(MatchResultListenerTest, StreamingWorks) { @@ -228,7 +234,7 @@ class EvenMatcherImpl : public MatcherInterface { return x % 2 == 0; } - virtual void DescribeTo(::std::ostream* os) const { + virtual void DescribeTo(ostream* os) const { *os << "is an even number"; } @@ -258,7 +264,7 @@ class NewEvenMatcherImpl : public MatcherInterface { return match; } - virtual void DescribeTo(::std::ostream* os) const { + virtual void DescribeTo(ostream* os) const { *os << "is an even number"; } }; @@ -375,9 +381,9 @@ class ReferencesBarOrIsZeroImpl { return p == &g_bar || x == 0; } - void DescribeTo(::std::ostream* os) const { *os << "g_bar or zero"; } + void DescribeTo(ostream* os) const { *os << "g_bar or zero"; } - void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(ostream* os) const { *os << "doesn't reference g_bar and is not zero"; } }; @@ -408,9 +414,9 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) { class PolymorphicIsEvenImpl { public: - void DescribeTo(::std::ostream* os) const { *os << "is even"; } + void DescribeTo(ostream* os) const { *os << "is even"; } - void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(ostream* os) const { *os << "is odd"; } @@ -1150,7 +1156,7 @@ TEST(KeyTest, SafelyCastsInnerMatcher) { } TEST(KeyTest, InsideContainsUsingMap) { - std::map container; + map container; container.insert(make_pair(1, 'a')); container.insert(make_pair(2, 'b')); container.insert(make_pair(4, 'c')); @@ -1159,7 +1165,7 @@ TEST(KeyTest, InsideContainsUsingMap) { } TEST(KeyTest, InsideContainsUsingMultimap) { - std::multimap container; + multimap container; container.insert(make_pair(1, 'a')); container.insert(make_pair(2, 'b')); container.insert(make_pair(4, 'c')); @@ -1268,7 +1274,7 @@ TEST(PairTest, SafelyCastsInnerMatchers) { } TEST(PairTest, InsideContainsUsingMap) { - std::map container; + map container; container.insert(make_pair(1, 'a')); container.insert(make_pair(2, 'b')); container.insert(make_pair(4, 'c')); @@ -1761,7 +1767,7 @@ TEST(Eq2Test, MatchesEqualArguments) { // Tests that Eq() describes itself properly. TEST(Eq2Test, CanDescribeSelf) { Matcher m = Eq(); - EXPECT_EQ("are a pair (x, y) where x == y", Describe(m)); + EXPECT_EQ("are an equal pair", Describe(m)); } // Tests that Ge() matches a 2-tuple where the first field >= the @@ -1776,7 +1782,7 @@ TEST(Ge2Test, MatchesGreaterThanOrEqualArguments) { // Tests that Ge() describes itself properly. TEST(Ge2Test, CanDescribeSelf) { Matcher m = Ge(); - EXPECT_EQ("are a pair (x, y) where x >= y", Describe(m)); + EXPECT_EQ("are a pair where the first >= the second", Describe(m)); } // Tests that Gt() matches a 2-tuple where the first field > the @@ -1791,7 +1797,7 @@ TEST(Gt2Test, MatchesGreaterThanArguments) { // Tests that Gt() describes itself properly. TEST(Gt2Test, CanDescribeSelf) { Matcher m = Gt(); - EXPECT_EQ("are a pair (x, y) where x > y", Describe(m)); + EXPECT_EQ("are a pair where the first > the second", Describe(m)); } // Tests that Le() matches a 2-tuple where the first field <= the @@ -1806,7 +1812,7 @@ TEST(Le2Test, MatchesLessThanOrEqualArguments) { // Tests that Le() describes itself properly. TEST(Le2Test, CanDescribeSelf) { Matcher m = Le(); - EXPECT_EQ("are a pair (x, y) where x <= y", Describe(m)); + EXPECT_EQ("are a pair where the first <= the second", Describe(m)); } // Tests that Lt() matches a 2-tuple where the first field < the @@ -1821,7 +1827,7 @@ TEST(Lt2Test, MatchesLessThanArguments) { // Tests that Lt() describes itself properly. TEST(Lt2Test, CanDescribeSelf) { Matcher m = Lt(); - EXPECT_EQ("are a pair (x, y) where x < y", Describe(m)); + EXPECT_EQ("are a pair where the first < the second", Describe(m)); } // Tests that Ne() matches a 2-tuple where the first field != the @@ -1836,7 +1842,7 @@ TEST(Ne2Test, MatchesUnequalArguments) { // Tests that Ne() describes itself properly. TEST(Ne2Test, CanDescribeSelf) { Matcher m = Ne(); - EXPECT_EQ("are a pair (x, y) where x != y", Describe(m)); + EXPECT_EQ("are an unequal pair", Describe(m)); } // Tests that Not(m) matches any value that doesn't match m. @@ -3338,11 +3344,11 @@ class DivisibleByImpl { return (n % divider_) == 0; } - void DescribeTo(::std::ostream* os) const { + void DescribeTo(ostream* os) const { *os << "is divisible by " << divider_; } - void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(ostream* os) const { *os << "is not divisible by " << divider_; } @@ -3444,10 +3450,10 @@ template class ContainerEqTest : public testing::Test {}; typedef testing::Types< - std::set, - std::vector, - std::multiset, - std::list > + set, + vector, + multiset, + list > ContainerEqTestTypes; TYPED_TEST_CASE(ContainerEqTest, ContainerEqTestTypes); @@ -3515,9 +3521,9 @@ TYPED_TEST(ContainerEqTest, DuplicateDifference) { TEST(ContainerEqExtraTest, MultipleValuesMissing) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {2, 1, 5}; - std::vector my_set(vals, vals + 6); - std::vector test_set(test_vals, test_vals + 3); - const Matcher > m = ContainerEq(my_set); + vector my_set(vals, vals + 6); + vector test_set(test_vals, test_vals + 3); + const Matcher > m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); EXPECT_EQ("which doesn't have these expected elements: 3, 8", Explain(m, test_set)); @@ -3528,9 +3534,9 @@ TEST(ContainerEqExtraTest, MultipleValuesMissing) { TEST(ContainerEqExtraTest, MultipleValuesAdded) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {1, 2, 92, 3, 5, 8, 46}; - std::list my_set(vals, vals + 6); - std::list test_set(test_vals, test_vals + 7); - const Matcher&> m = ContainerEq(my_set); + list my_set(vals, vals + 6); + list test_set(test_vals, test_vals + 7); + const Matcher&> m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); EXPECT_EQ("which has these unexpected elements: 92, 46", Explain(m, test_set)); @@ -3540,9 +3546,9 @@ TEST(ContainerEqExtraTest, MultipleValuesAdded) { TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {1, 2, 3, 92, 46}; - std::list my_set(vals, vals + 6); - std::list test_set(test_vals, test_vals + 5); - const Matcher > m = ContainerEq(my_set); + list my_set(vals, vals + 6); + list test_set(test_vals, test_vals + 5); + const Matcher > m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); EXPECT_EQ("which has these unexpected elements: 92, 46,\n" "and doesn't have these expected elements: 5, 8", @@ -3554,9 +3560,9 @@ TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) { TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {1, 2, 3, 5, 8}; - std::vector my_set(vals, vals + 6); - std::vector test_set(test_vals, test_vals + 5); - const Matcher > m = ContainerEq(my_set); + vector my_set(vals, vals + 6); + vector test_set(test_vals, test_vals + 5); + const Matcher > m = ContainerEq(my_set); EXPECT_TRUE(m.Matches(my_set)); EXPECT_FALSE(m.Matches(test_set)); // There is nothing to report when both sets contain all the same values. @@ -3566,15 +3572,15 @@ TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) { // Tests that ContainerEq works for non-trivial associative containers, // like maps. TEST(ContainerEqExtraTest, WorksForMaps) { - std::map my_map; + map my_map; my_map[0] = "a"; my_map[1] = "b"; - std::map test_map; + map test_map; test_map[0] = "aa"; test_map[1] = "b"; - const Matcher&> m = ContainerEq(my_map); + const Matcher&> m = ContainerEq(my_map); EXPECT_TRUE(m.Matches(my_map)); EXPECT_FALSE(m.Matches(test_map)); @@ -4072,5 +4078,123 @@ TEST(EachTest, WorksForNativeArrayAsTuple) { EXPECT_THAT(make_tuple(pointer, 2), Not(Each(Gt(1)))); } +// For testing Pointwise(). +class IsHalfOfMatcher { + public: + template + bool MatchAndExplain(const tuple& a_pair, + MatchResultListener* listener) const { + if (get<0>(a_pair) == get<1>(a_pair)/2) { + *listener << "where the second is " << get<1>(a_pair); + return true; + } else { + *listener << "where the second/2 is " << get<1>(a_pair)/2; + return false; + } + } + + void DescribeTo(ostream* os) const { + *os << "are a pair where the first is half of the second"; + } + + void DescribeNegationTo(ostream* os) const { + *os << "are a pair where the first isn't half of the second"; + } +}; + +PolymorphicMatcher IsHalfOf() { + return MakePolymorphicMatcher(IsHalfOfMatcher()); +} + +TEST(PointwiseTest, DescribesSelf) { + vector rhs; + rhs.push_back(1); + rhs.push_back(2); + rhs.push_back(3); + const Matcher&> m = Pointwise(IsHalfOf(), rhs); + EXPECT_EQ("contains 3 values, where each value and its corresponding value " + "in { 1, 2, 3 } are a pair where the first is half of the second", + Describe(m)); + EXPECT_EQ("doesn't contain exactly 3 values, or contains a value x at some " + "index i where x and the i-th value of { 1, 2, 3 } are a pair " + "where the first isn't half of the second", + DescribeNegation(m)); +} + +TEST(PointwiseTest, MakesCopyOfRhs) { + list rhs; + rhs.push_back(2); + rhs.push_back(4); + + int lhs[] = { 1, 2 }; + const Matcher m = Pointwise(IsHalfOf(), rhs); + EXPECT_THAT(lhs, m); + + // Changing rhs now shouldn't affect m, which made a copy of rhs. + rhs.push_back(6); + EXPECT_THAT(lhs, m); +} + +TEST(PointwiseTest, WorksForLhsNativeArray) { + const int lhs[] = { 1, 2, 3 }; + vector rhs; + rhs.push_back(2); + rhs.push_back(4); + rhs.push_back(6); + EXPECT_THAT(lhs, Pointwise(Lt(), rhs)); + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs))); +} + +TEST(PointwiseTest, WorksForRhsNativeArray) { + const int rhs[] = { 1, 2, 3 }; + vector lhs; + lhs.push_back(2); + lhs.push_back(4); + lhs.push_back(6); + EXPECT_THAT(lhs, Pointwise(Gt(), rhs)); + EXPECT_THAT(lhs, Not(Pointwise(Lt(), rhs))); +} + +TEST(PointwiseTest, RejectsWrongSize) { + const double lhs[2] = { 1, 2 }; + const int rhs[1] = { 0 }; + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs))); + EXPECT_EQ("which contains 2 values", + Explain(Pointwise(Gt(), rhs), lhs)); + + const int rhs2[3] = { 0, 1, 2 }; + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs2))); +} + +TEST(PointwiseTest, RejectsWrongContent) { + const double lhs[3] = { 1, 2, 3 }; + const int rhs[3] = { 2, 6, 4 }; + EXPECT_THAT(lhs, Not(Pointwise(IsHalfOf(), rhs))); + EXPECT_EQ("where the value pair (2, 6) at index #1 don't match, " + "where the second/2 is 3", + Explain(Pointwise(IsHalfOf(), rhs), lhs)); +} + +TEST(PointwiseTest, AcceptsCorrectContent) { + const double lhs[3] = { 1, 2, 3 }; + const int rhs[3] = { 2, 4, 6 }; + EXPECT_THAT(lhs, Pointwise(IsHalfOf(), rhs)); + EXPECT_EQ("", Explain(Pointwise(IsHalfOf(), rhs), lhs)); +} + +TEST(PointwiseTest, AllowsMonomorphicInnerMatcher) { + const double lhs[3] = { 1, 2, 3 }; + const int rhs[3] = { 2, 4, 6 }; + const Matcher > m1 = IsHalfOf(); + EXPECT_THAT(lhs, Pointwise(m1, rhs)); + EXPECT_EQ("", Explain(Pointwise(m1, rhs), lhs)); + + // This type works as a tuple can be + // implicitly cast to tuple. + const Matcher > m2 = IsHalfOf(); + EXPECT_THAT(lhs, Pointwise(m2, rhs)); + EXPECT_EQ("", Explain(Pointwise(m2, rhs), lhs)); +} + } // namespace gmock_matchers_test } // namespace testing diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index 382dc8cc..a7ff5630 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -151,7 +151,7 @@ FILE:#: pre-requisite #1 [ RUN ] GMockOutputTest.UnsatisfiedWith FILE:#: Failure Actual function call count doesn't match EXPECT_CALL(foo_, Bar2(_, _))... - Expected args: are a pair (x, y) where x >= y + Expected args: are a pair where the first >= the second Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.UnsatisfiedWith @@ -190,7 +190,7 @@ Unexpected mock function call - returning default value. Google Mock tried the following 1 expectation, but it didn't match: FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... - Expected args: are a pair (x, y) where x >= y + Expected args: are a pair where the first >= the second Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active @@ -206,7 +206,7 @@ Google Mock tried the following 1 expectation, but it didn't match: FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... Expected arg #0: is >= 2 Actual: 1 - Expected args: are a pair (x, y) where x >= y + Expected args: are a pair where the first >= the second Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active -- cgit v1.2.3 From 0a781df32a66029c4703d647cfd447e9467a7400 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 20 May 2010 22:17:28 +0000 Subject: Fixes build failure on Windows/CMake (issue 111). --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c3b5edd..186a710d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(BUILD_SHARED_LIBS OFF) option(gmock_build_tests "Build all of Google Mock's own tests." OFF) # A directory to find Google Test sources. -if (EXISTS gtest/CMakeLists.txt) +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") set(gtest_dir gtest) else() set(gtest_dir ../gtest) -- cgit v1.2.3 From b4140808f98ff09c43ca1ddaa8ff13bc47cd0089 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 8 Jun 2010 22:53:57 +0000 Subject: Replaces Python-style interpolation with arbitrary C++ string expression in MATCHER* descriptions. --- include/gmock/gmock-generated-matchers.h | 397 ++++++++++++++------------ include/gmock/gmock-generated-matchers.h.pump | 64 +++-- include/gmock/gmock-matchers.h | 42 +-- src/gmock-matchers.cc | 111 +------ test/gmock-generated-matchers_test.cc | 97 ++----- test/gmock-matchers_test.cc | 291 +------------------ 6 files changed, 289 insertions(+), 713 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 2790e06c..2cc5746e 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -946,25 +946,29 @@ ElementsAreArray(const T (&array)[N]) { // Describing Parameterized Matchers // ================================= // -// When defining a parameterized matcher, you can use Python-style -// interpolations in the description string to refer to the parameter -// values. We support the following syntax 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]") { +// 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 a failure that contains the message: +// 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 @@ -973,10 +977,13 @@ ElementsAreArray(const T (&array)[N]) { // MATCHER_P2(InClosedRange, low, hi, "") { ... } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); // -// would generate a failure that contains the text: +// 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 // =========================== @@ -1065,33 +1072,36 @@ ElementsAreArray(const T (&array)[N]) { template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - gmock_Impl(const ::testing::internal::Interpolations& gmock_interp)\ - : gmock_interp_(gmock_interp) {}\ + gmock_Impl()\ + {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple<>());\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::tuple<>()));\ + }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ - new gmock_Impl(gmock_interp_));\ + new gmock_Impl());\ }\ name##Matcher() {\ - const char* gmock_param_names[] = { NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##Matcher);\ };\ inline name##Matcher name() {\ @@ -1110,36 +1120,38 @@ ElementsAreArray(const T (&array)[N]) { template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - explicit gmock_Impl(p0##_type gmock_p0, \ - const ::testing::internal::Interpolations& gmock_interp)\ - : p0(gmock_p0), gmock_interp_(gmock_interp) {}\ + 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 {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple(p0));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::tuple(p0)));\ + }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ - new gmock_Impl(p0, gmock_interp_));\ + new gmock_Impl(p0));\ }\ name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ - const char* gmock_param_names[] = { #p0, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP);\ };\ template \ @@ -1160,39 +1172,41 @@ ElementsAreArray(const T (&array)[N]) { template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ - const ::testing::internal::Interpolations& gmock_interp)\ - : p0(gmock_p0), p1(gmock_p1), gmock_interp_(gmock_interp) {}\ + 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 {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple(p0, p1));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::tuple(p0, p1)));\ + }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ - new gmock_Impl(p0, p1, gmock_interp_));\ + new gmock_Impl(p0, p1));\ }\ name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ p1(gmock_p1) {\ - const char* gmock_param_names[] = { #p0, #p1, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\ };\ template \ @@ -1215,43 +1229,44 @@ ElementsAreArray(const T (&array)[N]) { template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - const ::testing::internal::Interpolations& gmock_interp)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - gmock_interp_(gmock_interp) {}\ + 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 {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple(p0, p1, \ - p2));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *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;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::tuple(p0, p1, \ + p2)));\ + }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, gmock_interp_));\ + 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\ };\ template \ @@ -1276,46 +1291,47 @@ ElementsAreArray(const T (&array)[N]) { 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, \ - const ::testing::internal::Interpolations& gmock_interp)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - gmock_interp_(gmock_interp) {}\ + 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 {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple(p0, p1, p2, p3));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *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;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, gmock_interp_));\ + 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\ };\ template {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, \ - const ::testing::internal::Interpolations& gmock_interp)\ + p3##_type gmock_p3, p4##_type gmock_p4)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4), gmock_interp_(gmock_interp) {}\ + p4(gmock_p4) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple(p0, p1, p2, p3, p4));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *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;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, gmock_interp_));\ + 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1386,7 +1405,6 @@ ElementsAreArray(const T (&array)[N]) { p3##_type p3;\ p4##_type p4;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\ };\ template {\ 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, \ - const ::testing::internal::Interpolations& gmock_interp)\ + 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), gmock_interp_(gmock_interp) {}\ + 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 {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple(p0, p1, p2, p3, p4, p5));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1435,22 +1450,28 @@ ElementsAreArray(const T (&array)[N]) { p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, gmock_interp_));\ + 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1459,7 +1480,6 @@ ElementsAreArray(const T (&array)[N]) { p4##_type p4;\ p5##_type p5;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\ };\ template (p0, p1, p2, p3, p4, p5, \ - p6));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1513,24 +1528,30 @@ ElementsAreArray(const T (&array)[N]) { p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, gmock_interp_));\ + 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ - NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1540,7 +1561,6 @@ ElementsAreArray(const T (&array)[N]) { p5##_type p5;\ p6##_type p6;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\ };\ template (p0, p1, p2, \ - p3, p4, p5, p6, p7));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1598,15 +1613,24 @@ ElementsAreArray(const T (&array)[N]) { p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, \ - gmock_interp_));\ + 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, \ @@ -1614,10 +1638,6 @@ ElementsAreArray(const T (&array)[N]) { 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ - #p7, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1628,7 +1648,6 @@ ElementsAreArray(const T (&array)[N]) { p6##_type p6;\ p7##_type p7;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\ };\ template (p0, p1, p2, p3, p4, p5, p6, p7, p8));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1689,15 +1704,24 @@ ElementsAreArray(const T (&array)[N]) { p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, \ - gmock_interp_));\ + 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, \ @@ -1705,10 +1729,6 @@ ElementsAreArray(const T (&array)[N]) { 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ - #p7, #p8, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1720,7 +1740,6 @@ ElementsAreArray(const T (&array)[N]) { p7##_type p7;\ p8##_type p8;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\ };\ template (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1785,15 +1800,24 @@ ElementsAreArray(const T (&array)[N]) { p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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, \ - gmock_interp_));\ + 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, \ @@ -1801,10 +1825,6 @@ ElementsAreArray(const T (&array)[N]) { 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) {\ - const char* gmock_param_names[] = { #p0, #p1, #p2, #p3, #p4, #p5, #p6, \ - #p7, #p8, #p9, NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\ p0##_type p0;\ p1##_type p1;\ @@ -1817,7 +1837,6 @@ ElementsAreArray(const T (&array)[N]) { p8##_type p8;\ p9##_type p9;\ private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\ };\ template \ ]]]] $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, ]] -const ::testing::internal::Interpolations& gmock_interp]] -$var impl_inits = [[ : $for j [[p$j(gmock_p$j), ]]gmock_interp_(gmock_interp)]] +$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_and_interp = [[$for j [[p$j, ]]gmock_interp_]] $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]]]] @@ -559,28 +564,31 @@ $var param_field_decls2 = [[$for j virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ - const ::testing::internal::Strings& gmock_printed_params = \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::std::tr1::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]]));\ - *gmock_os << ::testing::internal::FormatMatcherDescription(\ - #name, description, gmock_interp_, gmock_printed_params);\ + *gmock_os << FormatDescription(false);\ + }\ + virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ + *gmock_os << FormatDescription(true);\ }\$param_field_decls - const ::testing::internal::Interpolations gmock_interp_;\ 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(\ + ::std::tr1::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_and_interp));\ + new gmock_Impl($params));\ }\ $class_name($ctor_param_list)$inits {\ - const char* gmock_param_names[] = { $for j [[#p$j, ]]NULL };\ - gmock_interp_ = ::testing::internal::ValidateMatcherDescription(\ - gmock_param_names, ("" description ""));\ }\$param_field_decls2 private:\ - ::testing::internal::Interpolations gmock_interp_;\ GTEST_DISALLOW_ASSIGN_($class_name);\ };\$template inline $class_name$param_types name($param_types_and_names) {\ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 2a42bf94..315e1f56 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2527,41 +2527,13 @@ class ElementsAreArrayMatcher { GTEST_DISALLOW_ASSIGN_(ElementsAreArrayMatcher); }; -// Constants denoting interpolations in a matcher description string. -const int kTupleInterpolation = -1; // "%(*)s" -const int kPercentInterpolation = -2; // "%%" -const int kInvalidInterpolation = -3; // "%" followed by invalid text - -// Records the location and content of an interpolation. -struct Interpolation { - Interpolation(const char* start, const char* end, int param) - : start_pos(start), end_pos(end), param_index(param) {} - - // Points to the start of the interpolation (the '%' character). - const char* start_pos; - // Points to the first character after the interpolation. - const char* end_pos; - // 0-based index of the interpolated matcher parameter; - // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%". - int param_index; -}; - -typedef ::std::vector Interpolations; - -// Parses a matcher description string and returns a vector of -// interpolations that appear in the string; generates non-fatal -// failures iff 'description' is an invalid matcher description. -// 'param_names' is a NULL-terminated array of parameter names in the -// order they appear in the MATCHER_P*() parameter list. -Interpolations ValidateMatcherDescription( - const char* param_names[], const char* description); - -// Returns the actual matcher description, given the matcher name, -// user-supplied description template string, interpolations in the -// string, and the printed values of the matcher parameters. -string FormatMatcherDescription( - const char* matcher_name, const char* description, - const Interpolations& interp, const Strings& param_values); +// Returns the description for a matcher defined using the MATCHER*() +// macro where the user-supplied description string is "", if +// 'negation' is false; otherwise returns the description of the +// negation of the matcher. 'param_values' contains a list of strings +// that are the print-out of the matcher's parameters. +string FormatMatcherDescription(bool negation, const char* matcher_name, + const Strings& param_values); } // namespace internal diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc index 0abca708..89007d9f 100644 --- a/src/gmock-matchers.cc +++ b/src/gmock-matchers.cc @@ -65,74 +65,6 @@ Matcher::Matcher(const char* s) { namespace internal { -// Utilities for validating and formatting description strings in the -// MATCHER*() macros. - -// Returns the 0-based index of the given parameter in the -// NULL-terminated parameter array; if the parameter is "*", returns -// kTupleInterpolation; if it's not found in the list, returns -// kInvalidInterpolation. -int GetParamIndex(const char* param_names[], const string& param_name) { - if (param_name == "*") - return kTupleInterpolation; - - for (int i = 0; param_names[i] != NULL; i++) { - if (param_name == param_names[i]) - return i; - } - return kInvalidInterpolation; -} - -// Helper function used by ValidateMatcherDescription() to format -// error messages. -string FormatMatcherDescriptionSyntaxError(const char* description, - const char* error_pos) { - ::std::stringstream ss; - ss << "Syntax error at index " << (error_pos - description) - << " in matcher description \"" << description << "\": "; - return ss.str(); -} - -// Parses a matcher description string and returns a vector of -// interpolations that appear in the string; generates non-fatal -// failures iff 'description' is an invalid matcher description. -// 'param_names' is a NULL-terminated array of parameter names in the -// order they appear in the MATCHER_P*() parameter list. -Interpolations ValidateMatcherDescription( - const char* param_names[], const char* description) { - Interpolations interps; - for (const char* p = description; *p != '\0';) { - if (SkipPrefix("%%", &p)) { - interps.push_back(Interpolation(p - 2, p, kPercentInterpolation)); - } else if (SkipPrefix("%(", &p)) { - const char* const q = strstr(p, ")s"); - if (q == NULL) { - // TODO(wan@google.com): change the source file location in - // the failure to point to where the MATCHER*() macro is used. - ADD_FAILURE() << FormatMatcherDescriptionSyntaxError(description, p - 2) - << "an interpolation must end with \")s\", " - << "but \"" << (p - 2) << "\" does not."; - } else { - const string param_name(p, q); - const int param_index = GetParamIndex(param_names, param_name); - if (param_index == kInvalidInterpolation) { - ADD_FAILURE() << FormatMatcherDescriptionSyntaxError(description, p) - << "\"" << param_name - << "\" is an invalid parameter name."; - } else { - interps.push_back(Interpolation(p - 2, q + 2, param_index)); - p = q + 2; - } - } - } else { - EXPECT_NE(*p, '%') << FormatMatcherDescriptionSyntaxError(description, p) - << "use \"%%\" instead of \"%\" to print \"%\"."; - ++p; - } - } - return interps; -} - // Joins a vector of strings as if they are fields of a tuple; returns // the joined string. string JoinAsTuple(const Strings& fields) { @@ -152,38 +84,17 @@ string JoinAsTuple(const Strings& fields) { } } -// Returns the actual matcher description, given the matcher name, -// user-supplied description template string, interpolations in the -// string, and the printed values of the matcher parameters. -string FormatMatcherDescription( - const char* matcher_name, const char* description, - const Interpolations& interp, const Strings& param_values) { - string result; - if (*description == '\0') { - // When the user supplies an empty description, we calculate one - // from the matcher name. - result = ConvertIdentifierNameToWords(matcher_name); - if (param_values.size() >= 1) - result += " " + JoinAsTuple(param_values); - } else { - // The end position of the last interpolation. - const char* last_interp_end = description; - for (size_t i = 0; i < interp.size(); i++) { - result.append(last_interp_end, interp[i].start_pos); - const int param_index = interp[i].param_index; - if (param_index == kTupleInterpolation) { - result += JoinAsTuple(param_values); - } else if (param_index == kPercentInterpolation) { - result += '%'; - } else if (param_index != kInvalidInterpolation) { - result += param_values[param_index]; - } - last_interp_end = interp[i].end_pos; - } - result += last_interp_end; - } - - return result; +// Returns the description for a matcher defined using the MATCHER*() +// macro where the user-supplied description string is "", if +// 'negation' is false; otherwise returns the description of the +// negation of the matcher. 'param_values' contains a list of strings +// that are the print-out of the matcher's parameters. +string FormatMatcherDescription(bool negation, const char* matcher_name, + const Strings& param_values) { + string result = ConvertIdentifierNameToWords(matcher_name); + if (param_values.size() >= 1) + result += " " + JoinAsTuple(param_values); + return negation ? "not (" + result + ")" : result; } } // namespace internal diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index eebca8a0..3a028040 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -72,6 +72,7 @@ using testing::MatchResultListener; using testing::Ne; using testing::Not; using testing::Pointee; +using testing::PrintToString; using testing::Ref; using testing::StaticAssertTypeEq; using testing::StrEq; @@ -603,9 +604,8 @@ TEST(MatcherMacroTest, Works) { EXPECT_EQ("", Explain(m, 7)); } -// Tests explaining match result in a MATCHER* macro. - -MATCHER(IsEven2, "is even") { +// This also tests that the description string can reference 'negation'. +MATCHER(IsEven2, negation ? "is odd" : "is even") { if ((arg % 2) == 0) { // Verifies that we can stream to result_listener, a listener // supplied by the MATCHER macro implicitly. @@ -617,7 +617,11 @@ MATCHER(IsEven2, "is even") { } } -MATCHER_P2(EqSumOf, x, y, "") { +// This also tests that the description string can reference matcher +// parameters. +MATCHER_P2(EqSumOf, x, y, + string(negation ? "doesn't equal" : "equals") + " the sum of " + + PrintToString(x) + " and " + PrintToString(y)) { if (arg == (x + y)) { *result_listener << "OK"; return true; @@ -631,6 +635,19 @@ MATCHER_P2(EqSumOf, x, y, "") { } } +// Tests that the matcher description can reference 'negation' and the +// matcher parameters. +TEST(MatcherMacroTest, DescriptionCanReferenceNegationAndParameters) { + const Matcher m1 = IsEven2(); + EXPECT_EQ("is even", Describe(m1)); + EXPECT_EQ("is odd", DescribeNegation(m1)); + + const Matcher m2 = EqSumOf(5, 9); + EXPECT_EQ("equals the sum of 5 and 9", Describe(m2)); + EXPECT_EQ("doesn't equal the sum of 5 and 9", DescribeNegation(m2)); +} + +// Tests explaining match result in a MATCHER* macro. TEST(MatcherMacroTest, CanExplainMatchResult) { const Matcher m1 = IsEven2(); EXPECT_EQ("OK", Explain(m1, 4)); @@ -641,29 +658,6 @@ TEST(MatcherMacroTest, CanExplainMatchResult) { EXPECT_EQ("diff == -1", Explain(m2, 4)); } -// Tests that the description string supplied to MATCHER() must be -// valid. - -MATCHER(HasBadDescription, "Invalid%") { - // Uses arg to suppress "unused parameter" warning. - return arg==arg; -} - -TEST(MatcherMacroTest, - CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { - EXPECT_NONFATAL_FAILURE( - HasBadDescription(), - "Syntax error at index 7 in matcher description \"Invalid%\": " - "use \"%%\" instead of \"%\" to print \"%\"."); -} - -MATCHER(HasGoodDescription, "good") { return arg==arg; } - -TEST(MatcherMacroTest, AcceptsValidDescription) { - const Matcher m = HasGoodDescription(); - EXPECT_EQ("good", Describe(m)); -} - // Tests that the body of MATCHER() can reference the type of the // value being matched. @@ -723,29 +717,6 @@ TEST(MatcherPMacroTest, Works) { EXPECT_EQ("", Explain(m, 5)); } -// Tests that the description string supplied to MATCHER_P() must be -// valid. - -MATCHER_P(HasBadDescription1, n, "not %(m)s good") { - return arg > n; -} - -TEST(MatcherPMacroTest, - CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { - EXPECT_NONFATAL_FAILURE( - HasBadDescription1(2), - "Syntax error at index 6 in matcher description \"not %(m)s good\": " - "\"m\" is an invalid parameter name."); -} - - -MATCHER_P(HasGoodDescription1, n, "good %(n)s") { return arg==arg; } - -TEST(MatcherPMacroTest, AcceptsValidDescription) { - const Matcher m = HasGoodDescription1(5); - EXPECT_EQ("good 5", Describe(m)); -} - // Tests that the description is calculated correctly from the matcher name. MATCHER_P(_is_Greater_Than32and_, n, "") { return arg > 32 && arg > n; } @@ -789,32 +760,6 @@ TEST(MatcherPMacroTest, WorksWhenExplicitlyInstantiatedWithReference) { } -// Tests that the description string supplied to MATCHER_Pn() must be -// valid. - -MATCHER_P2(HasBadDescription2, m, n, "not %(good") { - return arg > m + n; -} - -TEST(MatcherPnMacroTest, - CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { - EXPECT_NONFATAL_FAILURE( - HasBadDescription2(3, 4), - "Syntax error at index 4 in matcher description \"not %(good\": " - "an interpolation must end with \")s\", but \"%(good\" does not."); -} - -MATCHER_P2(HasComplexDescription, foo, bar, - "is as complex as %(foo)s %(bar)s (i.e. %(*)s or %%%(foo)s!)") { - return arg==arg; -} - -TEST(MatcherPnMacroTest, AcceptsValidDescription) { - Matcher m = HasComplexDescription(100, "ducks"); - EXPECT_EQ("is as complex as 100 \"ducks\" (i.e. (100, \"ducks\") or %100!)", - Describe(m)); -} - // Tests that the body of MATCHER_Pn() can reference the parameter // types. diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 3b151dbd..dd2534f0 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -52,11 +52,7 @@ namespace testing { namespace internal { -string FormatMatcherDescriptionSyntaxError(const char* description, - const char* error_pos); -int GetParamIndex(const char* param_names[], const string& param_name); string JoinAsTuple(const Strings& fields); -bool SkipPrefix(const char* prefix, const char** pstr); } // namespace internal namespace gmock_matchers_test { @@ -126,21 +122,13 @@ using testing::_; using testing::internal::DummyMatchResultListener; using testing::internal::ExplainMatchFailureTupleTo; using testing::internal::FloatingEqMatcher; -using testing::internal::FormatMatcherDescriptionSyntaxError; -using testing::internal::GetParamIndex; -using testing::internal::Interpolation; -using testing::internal::Interpolations; +using testing::internal::FormatMatcherDescription; using testing::internal::JoinAsTuple; using testing::internal::RE; -using testing::internal::SkipPrefix; using testing::internal::StreamMatchResultListener; using testing::internal::String; using testing::internal::StringMatchResultListener; using testing::internal::Strings; -using testing::internal::ValidateMatcherDescription; -using testing::internal::kInvalidInterpolation; -using testing::internal::kPercentInterpolation; -using testing::internal::kTupleInterpolation; using testing::internal::linked_ptr; using testing::internal::scoped_ptr; using testing::internal::string; @@ -3643,176 +3631,6 @@ TEST(ContainerEqExtraTest, CopiesNativeArrayParameter) { EXPECT_THAT(a1, m); } -// Tests GetParamIndex(). - -TEST(GetParamIndexTest, WorksForEmptyParamList) { - const char* params[] = { NULL }; - EXPECT_EQ(kTupleInterpolation, GetParamIndex(params, "*")); - EXPECT_EQ(kInvalidInterpolation, GetParamIndex(params, "a")); -} - -TEST(GetParamIndexTest, RecognizesStar) { - const char* params[] = { "a", "b", NULL }; - EXPECT_EQ(kTupleInterpolation, GetParamIndex(params, "*")); -} - -TEST(GetParamIndexTest, RecognizesKnownParam) { - const char* params[] = { "foo", "bar", NULL }; - EXPECT_EQ(0, GetParamIndex(params, "foo")); - EXPECT_EQ(1, GetParamIndex(params, "bar")); -} - -TEST(GetParamIndexTest, RejectsUnknownParam) { - const char* params[] = { "foo", "bar", NULL }; - EXPECT_EQ(kInvalidInterpolation, GetParamIndex(params, "foobar")); -} - -// Tests SkipPrefix(). - -TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { - const char* const str = "hello"; - - const char* p = str; - EXPECT_TRUE(SkipPrefix("", &p)); - EXPECT_EQ(str, p); - - p = str; - EXPECT_TRUE(SkipPrefix("hell", &p)); - EXPECT_EQ(str + 4, p); -} - -TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { - const char* const str = "world"; - - const char* p = str; - EXPECT_FALSE(SkipPrefix("W", &p)); - EXPECT_EQ(str, p); - - p = str; - EXPECT_FALSE(SkipPrefix("world!", &p)); - EXPECT_EQ(str, p); -} - -// Tests FormatMatcherDescriptionSyntaxError(). -TEST(FormatMatcherDescriptionSyntaxErrorTest, FormatsCorrectly) { - const char* const description = "hello%world"; - EXPECT_EQ("Syntax error at index 5 in matcher description \"hello%world\": ", - FormatMatcherDescriptionSyntaxError(description, description + 5)); -} - -// Tests ValidateMatcherDescription(). - -TEST(ValidateMatcherDescriptionTest, AcceptsEmptyDescription) { - const char* params[] = { "foo", "bar", NULL }; - EXPECT_THAT(ValidateMatcherDescription(params, ""), - ElementsAre()); -} - -TEST(ValidateMatcherDescriptionTest, - AcceptsNonEmptyDescriptionWithNoInterpolation) { - const char* params[] = { "foo", "bar", NULL }; - EXPECT_THAT(ValidateMatcherDescription(params, "a simple description"), - ElementsAre()); -} - -// The MATCHER*() 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 - -// We use MATCHER_P3() to define a matcher for testing -// ValidateMatcherDescription(); otherwise we'll end up with much -// plumbing code. This is not circular as -// ValidateMatcherDescription() doesn't affect whether the matcher -// matches a value or not. -MATCHER_P3(EqInterpolation, start, end, index, "equals Interpolation%(*)s") { - return arg.start_pos == start && arg.end_pos == end && - arg.param_index == index; -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -TEST(ValidateMatcherDescriptionTest, AcceptsPercentInterpolation) { - const char* params[] = { "foo", NULL }; - const char* const desc = "one %%"; - EXPECT_THAT(ValidateMatcherDescription(params, desc), - ElementsAre(EqInterpolation(desc + 4, desc + 6, - kPercentInterpolation))); -} - -TEST(ValidateMatcherDescriptionTest, AcceptsTupleInterpolation) { - const char* params[] = { "foo", "bar", "baz", NULL }; - const char* const desc = "%(*)s after"; - EXPECT_THAT(ValidateMatcherDescription(params, desc), - ElementsAre(EqInterpolation(desc, desc + 5, - kTupleInterpolation))); -} - -TEST(ValidateMatcherDescriptionTest, AcceptsParamInterpolation) { - const char* params[] = { "foo", "bar", "baz", NULL }; - const char* const desc = "a %(bar)s."; - EXPECT_THAT(ValidateMatcherDescription(params, desc), - ElementsAre(EqInterpolation(desc + 2, desc + 9, 1))); -} - -TEST(ValidateMatcherDescriptionTest, AcceptsMultiplenterpolations) { - const char* params[] = { "foo", "bar", "baz", NULL }; - const char* const desc = "%(baz)s %(foo)s %(bar)s"; - EXPECT_THAT(ValidateMatcherDescription(params, desc), - ElementsAre(EqInterpolation(desc, desc + 7, 2), - EqInterpolation(desc + 8, desc + 15, 0), - EqInterpolation(desc + 16, desc + 23, 1))); -} - -TEST(ValidateMatcherDescriptionTest, AcceptsRepeatedParams) { - const char* params[] = { "foo", "bar", NULL }; - const char* const desc = "%(foo)s and %(foo)s"; - EXPECT_THAT(ValidateMatcherDescription(params, desc), - ElementsAre(EqInterpolation(desc, desc + 7, 0), - EqInterpolation(desc + 12, desc + 19, 0))); -} - -TEST(ValidateMatcherDescriptionTest, RejectsUnknownParam) { - const char* params[] = { "a", "bar", NULL }; - EXPECT_NONFATAL_FAILURE({ - EXPECT_THAT(ValidateMatcherDescription(params, "%(foo)s"), - ElementsAre()); - }, "Syntax error at index 2 in matcher description \"%(foo)s\": " - "\"foo\" is an invalid parameter name."); -} - -TEST(ValidateMatcherDescriptionTest, RejectsUnfinishedParam) { - const char* params[] = { "a", "bar", NULL }; - EXPECT_NONFATAL_FAILURE({ - EXPECT_THAT(ValidateMatcherDescription(params, "%(foo)"), - ElementsAre()); - }, "Syntax error at index 0 in matcher description \"%(foo)\": " - "an interpolation must end with \")s\", but \"%(foo)\" does not."); - - EXPECT_NONFATAL_FAILURE({ - EXPECT_THAT(ValidateMatcherDescription(params, "x%(a"), - ElementsAre()); - }, "Syntax error at index 1 in matcher description \"x%(a\": " - "an interpolation must end with \")s\", but \"%(a\" does not."); -} - -TEST(ValidateMatcherDescriptionTest, RejectsSinglePercent) { - const char* params[] = { "a", NULL }; - EXPECT_NONFATAL_FAILURE({ - EXPECT_THAT(ValidateMatcherDescription(params, "a %."), - ElementsAre()); - }, "Syntax error at index 2 in matcher description \"a %.\": " - "use \"%%\" instead of \"%\" to print \"%\"."); - -} - // Tests JoinAsTuple(). TEST(JoinAsTupleTest, JoinsEmptyTuple) { @@ -3839,118 +3657,21 @@ TEST(JoinAsTupleTest, JoinsTenTuple) { TEST(FormatMatcherDescriptionTest, WorksForEmptyDescription) { EXPECT_EQ("is even", - FormatMatcherDescription("IsEven", "", Interpolations(), - Strings())); + FormatMatcherDescription(false, "IsEven", Strings())); + EXPECT_EQ("not (is even)", + FormatMatcherDescription(true, "IsEven", Strings())); const char* params[] = { "5" }; EXPECT_EQ("equals 5", - FormatMatcherDescription("Equals", "", Interpolations(), + FormatMatcherDescription(false, "Equals", Strings(params, params + 1))); const char* params2[] = { "5", "8" }; EXPECT_EQ("is in range (5, 8)", - FormatMatcherDescription("IsInRange", "", Interpolations(), + FormatMatcherDescription(false, "IsInRange", Strings(params2, params2 + 2))); } -TEST(FormatMatcherDescriptionTest, WorksForDescriptionWithNoInterpolation) { - EXPECT_EQ("is positive", - FormatMatcherDescription("Gt0", "is positive", Interpolations(), - Strings())); - - const char* params[] = { "5", "6" }; - EXPECT_EQ("is negative", - FormatMatcherDescription("Lt0", "is negative", Interpolations(), - Strings(params, params + 2))); -} - -TEST(FormatMatcherDescriptionTest, - WorksWhenDescriptionStartsWithInterpolation) { - const char* params[] = { "5" }; - const char* const desc = "%(num)s times bigger"; - const Interpolation interp[] = { Interpolation(desc, desc + 7, 0) }; - EXPECT_EQ("5 times bigger", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 1), - Strings(params, params + 1))); -} - -TEST(FormatMatcherDescriptionTest, - WorksWhenDescriptionEndsWithInterpolation) { - const char* params[] = { "5", "6" }; - const char* const desc = "is bigger than %(y)s"; - const Interpolation interp[] = { Interpolation(desc + 15, desc + 20, 1) }; - EXPECT_EQ("is bigger than 6", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 1), - Strings(params, params + 2))); -} - -TEST(FormatMatcherDescriptionTest, - WorksWhenDescriptionStartsAndEndsWithInterpolation) { - const char* params[] = { "5", "6" }; - const char* const desc = "%(x)s <= arg <= %(y)s"; - const Interpolation interp[] = { - Interpolation(desc, desc + 5, 0), - Interpolation(desc + 16, desc + 21, 1) - }; - EXPECT_EQ("5 <= arg <= 6", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 2), - Strings(params, params + 2))); -} - -TEST(FormatMatcherDescriptionTest, - WorksWhenDescriptionDoesNotStartOrEndWithInterpolation) { - const char* params[] = { "5.2" }; - const char* const desc = "has %(x)s cents"; - const Interpolation interp[] = { Interpolation(desc + 4, desc + 9, 0) }; - EXPECT_EQ("has 5.2 cents", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 1), - Strings(params, params + 1))); -} - -TEST(FormatMatcherDescriptionTest, - WorksWhenDescriptionContainsMultipleInterpolations) { - const char* params[] = { "5", "6" }; - const char* const desc = "in %(*)s or [%(x)s, %(y)s]"; - const Interpolation interp[] = { - Interpolation(desc + 3, desc + 8, kTupleInterpolation), - Interpolation(desc + 13, desc + 18, 0), - Interpolation(desc + 20, desc + 25, 1) - }; - EXPECT_EQ("in (5, 6) or [5, 6]", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 3), - Strings(params, params + 2))); -} - -TEST(FormatMatcherDescriptionTest, - WorksWhenDescriptionContainsRepeatedParams) { - const char* params[] = { "9" }; - const char* const desc = "in [-%(x)s, %(x)s]"; - const Interpolation interp[] = { - Interpolation(desc + 5, desc + 10, 0), - Interpolation(desc + 12, desc + 17, 0) - }; - EXPECT_EQ("in [-9, 9]", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 2), - Strings(params, params + 1))); -} - -TEST(FormatMatcherDescriptionTest, - WorksForDescriptionWithInvalidInterpolation) { - const char* params[] = { "9" }; - const char* const desc = "> %(x)s %(x)"; - const Interpolation interp[] = { Interpolation(desc + 2, desc + 7, 0) }; - EXPECT_EQ("> 9 %(x)", - FormatMatcherDescription("Foo", desc, - Interpolations(interp, interp + 1), - Strings(params, params + 1))); -} - // Tests PolymorphicMatcher::mutable_impl(). TEST(PolymorphicMatcherTest, CanAccessMutableImpl) { PolymorphicMatcher m(DivisibleByImpl(42)); -- cgit v1.2.3 From 02c1505ebfaadbc34b4cb85546796521d6f0e634 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 9 Jun 2010 19:21:30 +0000 Subject: =?UTF-8?q?Increases=20the=20maximum=20arity=20of=20AllOf()=20and?= =?UTF-8?q?=20AnyOf()=20to=2010,=20by=20Marcus=20B=C3=B6rger.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/gmock/gmock-generated-matchers.h | 184 ++++++++++++++++++++++++++ include/gmock/gmock-generated-matchers.h.pump | 46 +++++++ include/gmock/gmock-matchers.h | 76 ----------- test/gmock-matchers_test.cc | 51 +++++++ 4 files changed, 281 insertions(+), 76 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 2cc5746e..cb610543 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -849,6 +849,190 @@ ElementsAreArray(const T (&array)[N]) { return internal::ElementsAreArrayMatcher(array, N); } +// AllOf(m1, m2, ..., mk) matches any value that matches all of the given +// sub-matchers. + +template +inline internal::BothOfMatcher +AllOf(Matcher1 m1, Matcher2 m2) { + return internal::BothOfMatcher(m1, m2); +} + +template +inline internal::BothOfMatcher > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { + return AllOf(m1, AllOf(m2, m3)); +} + +template +inline internal::BothOfMatcher > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { + return AllOf(m1, AllOf(m2, m3, m4)); +} + +template +inline internal::BothOfMatcher > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { + return AllOf(m1, AllOf(m2, m3, m4, m5)); +} + +template +inline internal::BothOfMatcher > > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6) { + return AllOf(m1, AllOf(m2, m3, m4, m5, m6)); +} + +template +inline internal::BothOfMatcher > > > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7) { + return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7)); +} + +template +inline internal::BothOfMatcher > > > > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7, Matcher8 m8) { + return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7, m8)); +} + +template +inline internal::BothOfMatcher > > > > > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9) { + return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7, m8, m9)); +} + +template +inline internal::BothOfMatcher > > > > > > > > +AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9, Matcher10 m10) { + return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7, m8, m9, m10)); +} + +// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given +// sub-matchers. + +template +inline internal::EitherOfMatcher +AnyOf(Matcher1 m1, Matcher2 m2) { + return internal::EitherOfMatcher(m1, m2); +} + +template +inline internal::EitherOfMatcher > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { + return AnyOf(m1, AnyOf(m2, m3)); +} + +template +inline internal::EitherOfMatcher > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { + return AnyOf(m1, AnyOf(m2, m3, m4)); +} + +template +inline internal::EitherOfMatcher > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5)); +} + +template +inline internal::EitherOfMatcher > > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6)); +} + +template +inline internal::EitherOfMatcher > > > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7)); +} + +template +inline internal::EitherOfMatcher > > > > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7, Matcher8 m8) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7, m8)); +} + +template +inline internal::EitherOfMatcher > > > > > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7, m8, m9)); +} + +template +inline internal::EitherOfMatcher > > > > > > > > +AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, + Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9, Matcher10 m10) { + return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7, m8, m9, m10)); +} + } // namespace testing // The MATCHER* family of macros can be used in a namespace scope to diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 9f19fb8b..02e3c980 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -302,6 +302,52 @@ ElementsAreArray(const T (&array)[N]) { return internal::ElementsAreArrayMatcher(array, N); } +// AllOf(m1, m2, ..., mk) matches any value that matches all of the given +// sub-matchers. + +$range i 2..n +$for i [[ +$range j 1..i +$range k 1..i-1 + +template <$for j, [[typename Matcher$j]]> +inline $for k[[internal::BothOfMatcher ]] + +AllOf($for j, [[Matcher$j m$j]]) { + +$if i == 2 [[ + return internal::BothOfMatcher(m1, m2); +]] $else [[ + return AllOf(m1, AllOf($for k, [[m$(k + 1)]])); +]] + +} + +]] + +// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given +// sub-matchers. + +$range i 2..n +$for i [[ +$range j 1..i +$range k 1..i-1 + +template <$for j, [[typename Matcher$j]]> +inline $for k[[internal::EitherOfMatcher ]] + +AnyOf($for j, [[Matcher$j m$j]]) { + +$if i == 2 [[ + return internal::EitherOfMatcher(m1, m2); +]] $else [[ + return AnyOf(m1, AnyOf($for k, [[m$(k + 1)]])); +]] + +} + +]] + } // namespace testing $$ } // This Pump meta comment fixes auto-indentation in Emacs. It will not $$ // show up in the generated code. diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 315e1f56..9f268d64 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2889,82 +2889,6 @@ inline internal::NotMatcher Not(InnerMatcher m) { return internal::NotMatcher(m); } -// Creates a matcher that matches any value that matches all of the -// given matchers. -// -// For now we only support up to 5 matchers. Support for more -// matchers can be added as needed, or the user can use nested -// AllOf()s. -template -inline internal::BothOfMatcher -AllOf(Matcher1 m1, Matcher2 m2) { - return internal::BothOfMatcher(m1, m2); -} - -template -inline internal::BothOfMatcher > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { - return AllOf(m1, AllOf(m2, m3)); -} - -template -inline internal::BothOfMatcher > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { - return AllOf(m1, AllOf(m2, m3, m4)); -} - -template -inline internal::BothOfMatcher > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { - return AllOf(m1, AllOf(m2, m3, m4, m5)); -} - -// Creates a matcher that matches any value that matches at least one -// of the given matchers. -// -// For now we only support up to 5 matchers. Support for more -// matchers can be added as needed, or the user can use nested -// AnyOf()s. -template -inline internal::EitherOfMatcher -AnyOf(Matcher1 m1, Matcher2 m2) { - return internal::EitherOfMatcher(m1, m2); -} - -template -inline internal::EitherOfMatcher > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { - return AnyOf(m1, AnyOf(m2, m3)); -} - -template -inline internal::EitherOfMatcher > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { - return AnyOf(m1, AnyOf(m2, m3, m4)); -} - -template -inline internal::EitherOfMatcher > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5)); -} - // Returns a matcher that matches anything that satisfies the given // predicate. The predicate can be any unary function or functor // whose return type can be implicitly converted to bool. diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index dd2534f0..f7a49c34 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -1857,6 +1857,16 @@ TEST(NotTest, NotMatcherSafelyCastsMonomorphicMatchers) { Matcher m3 = Not(m); } +// Helper to allow easy testing of AllOf matchers with num parameters. +void AllOfMatches(int num, const Matcher& m) { + SCOPED_TRACE(Describe(m)); + EXPECT_TRUE(m.Matches(0)); + for (int i = 1; i <= num; ++i) { + EXPECT_FALSE(m.Matches(i)); + } + EXPECT_TRUE(m.Matches(num + 1)); +} + // Tests that AllOf(m1, ..., mn) matches any value that matches all of // the given matchers. TEST(AllOfTest, MatchesWhenAllMatch) { @@ -1884,6 +1894,23 @@ TEST(AllOfTest, MatchesWhenAllMatch) { EXPECT_TRUE(m.Matches(0)); EXPECT_TRUE(m.Matches(1)); EXPECT_FALSE(m.Matches(3)); + + // The following tests for varying number of sub-matchers. Due to the way + // the sub-matchers are handled it is enough to test every sub-matcher once + // with sub-matchers using the same matcher type. Varying matcher types are + // checked for above. + AllOfMatches(2, AllOf(Ne(1), Ne(2))); + AllOfMatches(3, AllOf(Ne(1), Ne(2), Ne(3))); + AllOfMatches(4, AllOf(Ne(1), Ne(2), Ne(3), Ne(4))); + AllOfMatches(5, AllOf(Ne(1), Ne(2), Ne(3), Ne(4), Ne(5))); + AllOfMatches(6, AllOf(Ne(1), Ne(2), Ne(3), Ne(4), Ne(5), Ne(6))); + AllOfMatches(7, AllOf(Ne(1), Ne(2), Ne(3), Ne(4), Ne(5), Ne(6), Ne(7))); + AllOfMatches(8, AllOf(Ne(1), Ne(2), Ne(3), Ne(4), Ne(5), Ne(6), Ne(7), + Ne(8))); + AllOfMatches(9, AllOf(Ne(1), Ne(2), Ne(3), Ne(4), Ne(5), Ne(6), Ne(7), + Ne(8), Ne(9))); + AllOfMatches(10, AllOf(Ne(1), Ne(2), Ne(3), Ne(4), Ne(5), Ne(6), Ne(7), Ne(8), + Ne(9), Ne(10))); } // Tests that AllOf(m1, ..., mn) describes itself properly. @@ -2006,6 +2033,16 @@ TEST(AllOfTest, ExplainsResult) { EXPECT_EQ("which is 5 less than 20", Explain(m, 15)); } +// Helper to allow easy testing of AnyOf matchers with num parameters. +void AnyOfMatches(int num, const Matcher& m) { + SCOPED_TRACE(Describe(m)); + EXPECT_FALSE(m.Matches(0)); + for (int i = 1; i <= num; ++i) { + EXPECT_TRUE(m.Matches(i)); + } + EXPECT_FALSE(m.Matches(num + 1)); +} + // Tests that AnyOf(m1, ..., mn) matches any value that matches at // least one of the given matchers. TEST(AnyOfTest, MatchesWhenAnyMatches) { @@ -2033,6 +2070,20 @@ TEST(AnyOfTest, MatchesWhenAnyMatches) { EXPECT_TRUE(m.Matches(11)); EXPECT_TRUE(m.Matches(3)); EXPECT_FALSE(m.Matches(2)); + + // The following tests for varying number of sub-matchers. Due to the way + // the sub-matchers are handled it is enough to test every sub-matcher once + // with sub-matchers using the same matcher type. Varying matcher types are + // checked for above. + AnyOfMatches(2, AnyOf(1, 2)); + AnyOfMatches(3, AnyOf(1, 2, 3)); + AnyOfMatches(4, AnyOf(1, 2, 3, 4)); + AnyOfMatches(5, AnyOf(1, 2, 3, 4, 5)); + AnyOfMatches(6, AnyOf(1, 2, 3, 4, 5, 6)); + AnyOfMatches(7, AnyOf(1, 2, 3, 4, 5, 6, 7)); + AnyOfMatches(8, AnyOf(1, 2, 3, 4, 5, 6, 7, 8)); + AnyOfMatches(9, AnyOf(1, 2, 3, 4, 5, 6, 7, 8, 9)); + AnyOfMatches(10, AnyOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); } // Tests that AnyOf(m1, ..., mn) describes itself properly. -- cgit v1.2.3 From e3bd0981ca06e682bcd03659286d7a3267c4d999 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sat, 3 Jul 2010 00:16:42 +0000 Subject: Implements ReturnPointee() and ReturnRefOfCopy(). --- include/gmock/gmock-actions.h | 57 ++++++++++++++++++++++++++++++++++++++ include/gmock/gmock-more-actions.h | 3 ++ test/gmock-actions_test.cc | 25 +++++++++++++++++ test/gmock-more-actions_test.cc | 10 +++++++ 4 files changed, 95 insertions(+) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 9fe19644..ddaaef24 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -584,6 +584,55 @@ class ReturnRefAction { 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 DoDefault() action for a particular function type F. template class MonomorphicDoDefaultActionImpl : public ActionInterface { @@ -948,6 +997,14 @@ 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); +} + // Creates an action that does the default action for the give mock function. inline internal::DoDefaultAction DoDefault() { return internal::DoDefaultAction(); diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index 6d686cd1..c60557e6 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -195,6 +195,9 @@ ACTION_TEMPLATE(DeleteArg, delete ::std::tr1::get(args); } +// This action returns the value pointed to by 'pointer'. +ACTION_P(ReturnPointee, pointer) { return *pointer; } + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 8391e5fe..50cc6f98 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -68,6 +68,7 @@ using testing::PolymorphicAction; using testing::Return; using testing::ReturnNull; using testing::ReturnRef; +using testing::ReturnRefOfCopy; using testing::SetArgumentPointee; #if !GTEST_OS_WINDOWS_MOBILE @@ -584,6 +585,30 @@ TEST(ReturnRefTest, IsCovariant) { EXPECT_EQ(&derived, &a.Perform(make_tuple())); } +// Tests that ReturnRefOfCopy(v) works for reference types. +TEST(ReturnRefOfCopyTest, WorksForReference) { + int n = 42; + const Action ret = ReturnRefOfCopy(n); + + EXPECT_NE(&n, &ret.Perform(make_tuple())); + EXPECT_EQ(42, ret.Perform(make_tuple())); + + n = 43; + EXPECT_NE(&n, &ret.Perform(make_tuple())); + EXPECT_EQ(42, ret.Perform(make_tuple())); +} + +// Tests that ReturnRefOfCopy(v) is covariant. +TEST(ReturnRefOfCopyTest, IsCovariant) { + Base base; + Derived derived; + Action a = ReturnRefOfCopy(base); + EXPECT_NE(&base, &a.Perform(make_tuple())); + + a = ReturnRefOfCopy(derived); + EXPECT_NE(&derived, &a.Perform(make_tuple())); +} + // Tests that DoDefault() does the default action for the mock method. class MyClass {}; diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index b3b17d33..be7b1273 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -57,6 +57,7 @@ using testing::DeleteArg; using testing::Invoke; using testing::Return; using testing::ReturnArg; +using testing::ReturnPointee; using testing::SaveArg; using testing::SetArgReferee; using testing::SetArgumentPointee; @@ -664,5 +665,14 @@ TEST(SetArrayArgumentTest, SetsTheNthArrayWithIteratorArgument) { EXPECT_EQ(letters, s); } +TEST(ReturnPointeeTest, Works) { + int n = 42; + const Action a = ReturnPointee(&n); + EXPECT_EQ(42, a.Perform(make_tuple())); + + n = 43; + EXPECT_EQ(43, a.Perform(make_tuple())); +} + } // namespace gmock_generated_actions_test } // namespace testing -- cgit v1.2.3 From d60c5f41c2842effec130a9b0483b92dbbed6e55 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 21 Jul 2010 22:21:07 +0000 Subject: Removes unused scons scripts; picks up gtest r446. --- run_tests.py | 81 ------------- scons/SConscript | 215 ---------------------------------- scons/SConstruct | 96 --------------- test/gmock-generated-matchers_test.cc | 2 +- test/gmock-matchers_test.cc | 4 +- 5 files changed, 3 insertions(+), 395 deletions(-) delete mode 100755 run_tests.py delete mode 100644 scons/SConscript delete mode 100644 scons/SConstruct diff --git a/run_tests.py b/run_tests.py deleted file mode 100755 index 5e7b308f..00000000 --- a/run_tests.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -"""Runs the specified tests for Google Mock. - -This script requires Python 2.3 or higher. To learn the usage, run it -with -h. -""" - -__author__ = 'vladl@google.com (Vlad Losev)' - - -import os -import sys - -SCRIPT_DIR = os.path.dirname(__file__) or '.' - -# Path to the Google Test code this Google Mock will use. We assume the -# gtest/ directory is either a subdirectory (possibly via a symbolic link) -# of gmock/ or a sibling. -# -# isdir resolves symbolic links. -if os.path.isdir(os.path.join(SCRIPT_DIR, 'gtest/test')): - RUN_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, 'gtest/test') -else: - RUN_TESTS_UTIL_DIR = os.path.join(SCRIPT_DIR, '../gtest/test') - -sys.path.append(RUN_TESTS_UTIL_DIR) -import run_tests_util - -def GetGmockBuildDir(injected_os, script_dir, config): - return injected_os.path.normpath(injected_os.path.join(script_dir, - 'scons/build', - config, - 'gmock/scons')) - - -def _Main(): - """Runs all tests for Google Mock.""" - - options, args = run_tests_util.ParseArgs('gtest') - test_runner = run_tests_util.TestRunner( - script_dir=SCRIPT_DIR, - injected_build_dir_finder=GetGmockBuildDir) - tests = test_runner.GetTestsToRun(args, - options.configurations, - options.built_configurations) - if not tests: - sys.exit(1) # Incorrect parameters given, abort execution. - - sys.exit(test_runner.RunTests(tests[0], tests[1])) - -if __name__ == '__main__': - _Main() diff --git a/scons/SConscript b/scons/SConscript deleted file mode 100644 index dedad37d..00000000 --- a/scons/SConscript +++ /dev/null @@ -1,215 +0,0 @@ -# -*- Python -*- -# -# 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. - - -"""Builds the Google Mock (gmock) lib. - -You should be able to call this file from more or less any SConscript -file. - -You can optionally set a variable on the construction environment to -have the unit test executables copied to your output directory. The -variable should be env['EXE_OUTPUT']. - -Another optional variable is env['LIB_OUTPUT']. If set, the generated -libraries are copied to the folder indicated by the variable. - -If you place the Google Mock sources within your own project's source -directory, you should be able to call this SConscript file simply as -follows: - -# -- cut here -- -# Build gmock library; first tell it where to copy executables. -env['EXE_OUTPUT'] = '#/mybuilddir/mybuildmode' # example, optional -env['LIB_OUTPUT'] = '#/mybuilddir/mybuildmode/lib' -env.SConscript('whateverpath/gmock/scons/SConscript') -# -- cut here -- - -If on the other hand you place the Google Mock sources in a directory -outside of your project's source tree, you would use a snippet similar -to the following: - -# -- cut here -- - -# The following assumes that $BUILD_DIR refers to the root of the -# directory for your current build mode, e.g. "#/mybuilddir/mybuildmode" - -# Build gmock library; as it is outside of our source root, we need to -# tell SCons that the directory it will refer to as -# e.g. $BUILD_DIR/gmock is actually on disk in original form as -# ../../gmock (relative to your project root directory). Recall that -# SCons by default copies all source files into the build directory -# before building. -gmock_dir = env.Dir('$BUILD_DIR/gmock') - -# Modify this part to point to Google Mock relative to the current -# SConscript or SConstruct file's directory. The ../.. path would -# be different per project, to locate the base directory for Google Mock. -gmock_dir.addRepository(env.Dir('../../gmock')) - -# Tell the Google Mock SCons file where to copy executables. -env['EXE_OUTPUT'] = '$BUILD_DIR' # example, optional - -# Call the Google Mock SConscript to build gmock.lib and unit tests. The -# location of the library should end up as -# '$BUILD_DIR/gmock/scons/gmock.lib' -env.SConscript(env.File('scons/SConscript', gmock_dir)) - -# -- cut here -- -""" - - -__author__ = 'joi@google.com (Joi Sigurdsson)' - - -import os - -############################################################ -# Environments for building the targets, sorted by name. - -Import('env', 'gtest_exports') - -GTEST_DIR = env['GTEST_DIR'] - -GtestObject = gtest_exports['GtestObject'] -GtestBinary = gtest_exports['GtestBinary'] -GtestTest = gtest_exports['GtestTest'] - -gtest_common_exports = SConscript(GTEST_DIR + '/scons/SConscript.common') -EnvCreator = gtest_common_exports['EnvCreator'] - -env = env.Clone() -if env['PLATFORM'] == 'win32': - env.Append(CCFLAGS=[ - '-wd4127', # Disables warning "conditional expression is constant", - # triggered by VC 8.0's own STL header . - ]) - -# Note: The relative paths in SConscript files are relative to the location -# of the SConscript file itself. To make a path relative to the location of -# the main SConstruct file, prepend the path with the # sign. -# -# Include paths to gtest headers are relative to either the gmock -# directory or the 'include' subdirectory of it, and this SConscript -# file is one directory deeper than the gmock directory. -env.Prepend(CPPPATH = ['..', '../include', GTEST_DIR + '/include']) - -env_use_own_tuple = EnvCreator.Create(env, EnvCreator.UseOwnTuple) -env_with_exceptions = EnvCreator.Create(env, EnvCreator.WithExceptions) -env_without_rtti = EnvCreator.Create(env, EnvCreator.NoRtti) - -############################################################ -# Helpers for creating build targets. - -def GmockStaticLibraries(build_env): - """Builds static libraries for gmock and gmock_main in build_env. - - Args: - build_env: An environment in which to build libraries. - - Returns: - A pair (gmock_library, gmock_main_library) built in the build_env - environment. - """ - - gmock_object = GtestObject(build_env, '../src/gmock-all.cc') - gmock_main_object = GtestObject(build_env, '../src/gmock_main.cc') - - return (build_env.StaticLibrary(target='gmock' + build_env['OBJ_SUFFIX'], - source=[gmock_object]), - build_env.StaticLibrary(target='gmock_main' + build_env['OBJ_SUFFIX'], - source=[gmock_object, gmock_main_object])) - - -############################################################ -# Object and library targets. - -gtest = gtest_exports['gtest'] -gtest_ex = gtest_exports['gtest_ex'] -gtest_no_rtti = gtest_exports['gtest_no_rtti'] -gtest_use_own_tuple = gtest_exports['gtest_use_own_tuple'] - -# gmock.lib to be used by most apps (if you have your own main function). -# gmock_main.lib can be used if you just want a basic main function; it is -# also used by some tests for Google Test itself. -gmock, gmock_main = GmockStaticLibraries(env) -gmock_ex, gmock_main_ex = GmockStaticLibraries(env_with_exceptions) -gmock_no_rtti, gmock_main_no_rtti = GmockStaticLibraries(env_without_rtti) -gmock_use_own_tuple, gmock_main_use_own_tuple = GmockStaticLibraries( - env_use_own_tuple) - -# Install the libraries if needed. -if 'LIB_OUTPUT' in env.Dictionary(): - env.Install('$LIB_OUTPUT', source=[gmock, gmock_main, - gmock_ex, gmock_main_ex, - gmock_no_rtti, gmock_main_no_rtti, - gmock_use_own_tuple, - gmock_main_use_own_tuple]) - -############################################################# -# Test targets using the standard environment. -GtestTest(env, 'gmock-actions_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-cardinalities_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-generated-actions_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-generated-function-mockers_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-generated-internal-utils_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-generated-matchers_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-internal-utils_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-matchers_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-more-actions_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-nice-strict_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-port_test', [gtest, gmock_main]) -GtestTest(env, 'gmock-spec-builders_test', [gtest, gmock_main]) -GtestTest(env, 'gmock_leak_test_', [gtest, gmock_main]) -GtestTest(env, 'gmock_link_test', [gtest, gmock_main], - ['../test/gmock_link2_test.cc']) -GtestTest(env, 'gmock_output_test_', [gtest, gmock]) -#GtestTest(env, 'gmock_stress_test', [gtest, gmock]) -GtestTest(env, 'gmock_test', [gtest, gmock_main]) -# gmock_all_test is commented to save time building and running tests. -# Uncomment if necessary. -#GtestTest(env, 'gmock_all_test', [gtest, gmock_main]) - -############################################################ -# Tests targets using custom environments. -GtestBinary(env_with_exceptions, - 'gmock-more-actions-ex_test', - [gtest_ex, gmock_main_ex], - ['../test/gmock-more-actions_test.cc']) - -GtestBinary(env_without_rtti, - 'gmock_no_rtti_test', - [gtest_no_rtti, gmock_main_no_rtti], - ['../test/gmock-spec-builders_test.cc']) - -GtestBinary(env_use_own_tuple, - 'gmock_use_own_tuple_test', - [gtest_use_own_tuple, gmock_main_use_own_tuple], - ['../test/gmock-spec-builders_test.cc']) diff --git a/scons/SConstruct b/scons/SConstruct deleted file mode 100644 index 8f67d704..00000000 --- a/scons/SConstruct +++ /dev/null @@ -1,96 +0,0 @@ -# -*- Python -*- -# 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: joi@google.com (Joi Sigurdsson) -# Author: vladl@google.com (Vlad Losev) -# -# Build file for Google Mock and its tests. -# -# Usage: -# cd to the directory with this file, then -# ./scons.py [OPTIONS] -# -# where frequently used command-line options include: -# -h print usage help. -# BUILD=all build all build types. -# BUILD=win-opt8 build the given build type. - -EnsurePythonVersion(2, 3) - -# Path to the Google Test code this Google Mock will use. -GTEST_DIR = '../gtest' - -# TODO(vladl@google.com): Factor the looping logic out for reuse. -def BuildGMockSelectedEnvironments(sconstruct_helper): - # Build using whichever environments the 'BUILD' option selected - for build_name in sconstruct_helper.env_base['BUILD']: - print 'BUILDING %s' % build_name - env = sconstruct_helper.env_dict[build_name] - - # Make sure SConscript files can refer to base build dir - env['MAIN_DIR'] = env.Dir(env['BUILD_DIR']) - - #print 'CCFLAGS: %s' % env.subst('$CCFLAGS') - #print 'LINK: %s' % env.subst('$LINK') - #print 'AR: %s' % env.subst('$AR') - #print 'CC: %s' % env.subst('$CC') - #print 'CXX: %s' % env.subst('$CXX') - #print 'LIBPATH: %s' % env.subst('$LIBPATH') - #print 'ENV:PATH: %s' % env['ENV']['PATH'] - #print 'ENV:INCLUDE: %s' % env['ENV']['INCLUDE'] - #print 'ENV:LIB: %s' % env['ENV']['LIB'] - #print 'ENV:TEMP: %s' % env['ENV']['TEMP'] - - env['GTEST_DIR'] = '#/' + GTEST_DIR - env['GTEST_BUILD_TESTS'] = False - Export('env') - # Invokes SConscript with variant_dir being build/. - # Counter-intuitively, src_dir is relative to the build dir and has - # to be '../..' to point to the scons directory. - VariantDir(env['BUILD_DIR'], '../..', duplicate=0) - gtest_exports = env.SConscript(env['BUILD_DIR'] + '/gtest/scons/SConscript') - Export('gtest_exports') - SConscript('SConscript', - src_dir='../..', - variant_dir=env['BUILD_DIR'], - duplicate=0) - -sconstruct_helper = SConscript(GTEST_DIR + '/scons/SConstruct.common') - -sconstruct_helper.Initialize(build_root_path='..', - support_multiple_win_builds=False) - -win_base = sconstruct_helper.MakeWinBaseEnvironment() - -sconstruct_helper.MakeWinDebugEnvironment(win_base, 'win-dbg8') -sconstruct_helper.MakeWinOptimizedEnvironment(win_base, 'win-opt8') - -sconstruct_helper.ConfigureGccEnvironments() - -BuildGMockSelectedEnvironments(sconstruct_helper) diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 3a028040..600783c7 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -243,7 +243,7 @@ Matcher > LessThan() { TEST(ArgsTest, ExplainsMatchResultWithInnerExplanation) { const Matcher > m = Args<0, 2>(LessThan()); - EXPECT_EQ("whose fields (#0, #2) are ('a' (97), 42), " + EXPECT_EQ("whose fields (#0, #2) are ('a' (97, 0x61), 42), " "where the first value is 55 more than the second", Explain(m, make_tuple('a', 42, 42))); EXPECT_EQ("whose fields (#0, #2) are ('\\0', 43)", diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index f7a49c34..c2db86ca 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -3751,8 +3751,8 @@ TEST(MatcherTupleTest, ExplainsMatchFailure) { make_tuple(2, 'b'), &ss2); EXPECT_EQ(" Expected arg #0: is > 5\n" " Actual: 2, which is 3 less than 5\n" - " Expected arg #1: is equal to 'a' (97)\n" - " Actual: 'b' (98)\n", + " Expected arg #1: is equal to 'a' (97, 0x61)\n" + " Actual: 'b' (98, 0x62)\n", ss2.str()); // Failed match where both arguments need explanation. stringstream ss3; -- cgit v1.2.3 From c6333dca1c94ef434257c54ede69adace6e32e1c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 9 Aug 2010 18:20:45 +0000 Subject: Picks up gtest r453. --- test/gmock-spec-builders_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index ff30f02b..1d0c491b 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1855,7 +1855,7 @@ TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { "Uninteresting mock function call - returning directly\\.\n" " Function call: VoidMethod" "\\(false, 5, \"Hi\", NULL, @.+ " - "Printable, 4-byte object <0000 0000>\\)")); + "Printable, 4-byte object <00-00 00-00>\\)")); // A void function has no return value to print. } -- cgit v1.2.3 From ccedc1c93371e3b3826bc2d83b77ab1a26d07dc6 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 9 Aug 2010 22:46:12 +0000 Subject: Removes some gmock internal macros; sorts the file lists in Makefile.am; picks up gtest r454. --- Makefile.am | 106 +++++++++++---------- include/gmock/gmock-generated-actions.h | 2 +- include/gmock/gmock-generated-actions.h.pump | 2 +- include/gmock/gmock-generated-function-mockers.h | 2 +- .../gmock/gmock-generated-function-mockers.h.pump | 2 +- include/gmock/gmock-spec-builders.h | 2 +- include/gmock/internal/gmock-internal-utils.h | 11 --- 7 files changed, 60 insertions(+), 67 deletions(-) diff --git a/Makefile.am b/Makefile.am index e2a46730..2d967dcc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,16 +29,17 @@ lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la lib_libgmock_la_SOURCES = src/gmock-all.cc -pkginclude_HEADERS = include/gmock/gmock.h \ - 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-spec-builders.h +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-spec-builders.h \ + include/gmock/gmock.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ @@ -70,34 +71,35 @@ test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la # verifies that libgmock_main works. TESTS += test/gmock_link_test check_PROGRAMS += test/gmock_link_test -test_gmock_link_test_SOURCES = test/gmock_link_test.cc \ - test/gmock_link2_test.cc \ - test/gmock_link_test.h +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 # 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_main.cc \ - fused-src/gmock/gmock.h \ - fused-src/gtest/gtest.h \ - test/gmock_test.cc +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" # Google Mock source files that we don't compile directly. GMOCK_SOURCE_INGLUDES = \ - src/gmock.cc \ src/gmock-cardinalities.cc \ src/gmock-internal-utils.cc \ src/gmock-matchers.cc \ - src/gmock-spec-builders.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_all_test.cc \ test/gmock-actions_test.cc \ test/gmock-cardinalities_test.cc \ test/gmock-generated-actions_test.cc \ @@ -108,56 +110,58 @@ EXTRA_DIST += \ test/gmock-matchers_test.cc \ test/gmock-more-actions_test.cc \ test/gmock-nice-strict_test.cc \ - test/gmock-port_test.cc + test/gmock-port_test.cc \ + test/gmock_all_test.cc # Python tests, which we don't run using autotools. EXTRA_DIST += \ - test/gmock_test_utils.py \ - test/gmock_leak_test_.cc \ test/gmock_leak_test.py \ - test/gmock_output_test_.cc \ + test/gmock_leak_test_.cc \ test/gmock_output_test.py \ - test/gmock_output_test_golden.txt + 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 + 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 +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 # 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/COPYING \ - 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 + scripts/generator/COPYING \ + 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 # Microsoft Visual Studio 2005 projects. EXTRA_DIST += \ - msvc/gmock.sln \ - msvc/gmock.vcproj \ - msvc/gmock_config.vsprops \ - msvc/gmock_link_test.vcproj \ - msvc/gmock_main.vcproj \ - msvc/gmock-spec-builders_test.vcproj \ - msvc/gmock_test.vcproj + msvc/gmock-spec-builders_test.vcproj \ + msvc/gmock.sln \ + msvc/gmock.vcproj \ + msvc/gmock_config.vsprops \ + msvc/gmock_link_test.vcproj \ + msvc/gmock_main.vcproj \ + msvc/gmock_test.vcproj # gmock_test.cc does not really depend on files generated by the # fused-gmock-internal rule. However, gmock_test.o does, and it is diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 2b53c7b9..65652f8e 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -1378,7 +1378,7 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, // The name of the class template implementing the action template. #define GMOCK_ACTION_CLASS_(name, value_params)\ - GMOCK_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) + GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) #define ACTION_TEMPLATE(name, template_params, value_params)\ template =2 [[P$i]] // The name of the class template implementing the action template. #define GMOCK_ACTION_CLASS_(name, value_params)\ - GMOCK_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) + GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) $range k 0..n-1 diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 58be7e19..65090861 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -339,7 +339,7 @@ using internal::FunctionMocker; // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_MOCKER_(arity, constness, Method) \ - GMOCK_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD0_(tn, constness, ct, Method, F) \ diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 20a44541..e0a0cd10 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -119,7 +119,7 @@ using internal::FunctionMocker; // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_MOCKER_(arity, constness, Method) \ - GMOCK_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) $for i [[ diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 7038c2e4..27d2b747 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -537,7 +537,7 @@ class InSequence { bool sequence_created_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InSequence); // NOLINT -} GMOCK_ATTRIBUTE_UNUSED_; +} GTEST_ATTRIBUTE_UNUSED_; namespace internal { diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 69a23380..19ea89eb 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -46,17 +46,6 @@ #include #include -// Concatenates two pre-processor symbols; works for concatenating -// built-in macros like __FILE__ and __LINE__. -#define GMOCK_CONCAT_TOKEN_IMPL_(foo, bar) foo##bar -#define GMOCK_CONCAT_TOKEN_(foo, bar) GMOCK_CONCAT_TOKEN_IMPL_(foo, bar) - -#ifdef __GNUC__ -#define GMOCK_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#else -#define GMOCK_ATTRIBUTE_UNUSED_ -#endif // __GNUC__ - namespace testing { namespace internal { -- cgit v1.2.3 From 2516f60da9073f3b04c0bbfc37d3aefffe11767e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 31 Aug 2010 18:28:02 +0000 Subject: Publishes GTEST_HAS_STREAM_REDIRECTION (by Vlad Losev); casts char to unsigned char before calling isspace() etc to avoid undefined behavior (by Zhanyong Wan); fixes the VC projects (by Fredrik Roubert). --- msvc/gmock.vcproj | 8 -------- msvc/gmock_test.vcproj | 4 ---- src/gmock-internal-utils.cc | 10 +++++----- test/gmock-internal-utils_test.cc | 8 ++++---- test/gmock-nice-strict_test.cc | 8 ++++---- test/gmock-spec-builders_test.cc | 16 ++++++++-------- 6 files changed, 21 insertions(+), 33 deletions(-) diff --git a/msvc/gmock.vcproj b/msvc/gmock.vcproj index b9036dad..39d9dc9e 100644 --- a/msvc/gmock.vcproj +++ b/msvc/gmock.vcproj @@ -162,10 +162,6 @@ RelativePath="..\src\gmock-matchers.cc" > - - @@ -228,10 +224,6 @@ RelativePath="..\include\gmock\gmock-matchers.h" > - - diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj index 60e1b4bc..fd969d7c 100644 --- a/msvc/gmock_test.vcproj +++ b/msvc/gmock_test.vcproj @@ -222,10 +222,6 @@ RelativePath="..\test\gmock-port_test.cc" > - - diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index cc51836b..9debe187 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -57,14 +57,14 @@ string ConvertIdentifierNameToWords(const char* id_name) { for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) { // We don't care about the current locale as the input is // guaranteed to be a valid C++ identifier name. - const bool starts_new_word = isupper(*p) || - (!isalpha(prev_char) && islower(*p)) || - (!isdigit(prev_char) && isdigit(*p)); + const bool starts_new_word = IsUpper(*p) || + (!IsAlpha(prev_char) && IsLower(*p)) || + (!IsDigit(prev_char) && IsDigit(*p)); - if (isalnum(*p)) { + if (IsAlNum(*p)) { if (starts_new_word && result != "") result += ' '; - result += static_cast(tolower(*p)); + result += ToLower(*p); } } return result; diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 4309f7c8..720d6c72 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -375,7 +375,7 @@ TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) { EXPECT_TRUE(LogIsVisible(WARNING)); } -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Tests the Log() function. @@ -458,7 +458,7 @@ TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsInvalid) { TestLogWithSeverity("invalid", WARNING, true); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION TEST(TypeTraitsTest, true_type) { EXPECT_TRUE(true_type::value); @@ -495,7 +495,7 @@ TEST(TypeTraitsTest, remove_reference) { EXPECT_TRUE((type_equals::type>::value)); } -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Verifies that Log() behaves correctly for the given verbosity level // and log severity. @@ -572,7 +572,7 @@ TEST(OnCallTest, LogsAnythingArgument) { HasSubstr("ON_CALL(mock, TestMethodArg(_)")); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION // Tests StlContainerView. diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 0e52450d..f340cecb 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -57,10 +57,10 @@ using testing::HasSubstr; using testing::NiceMock; using testing::StrictMock; -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // Defines some mock classes needed by the tests. @@ -107,7 +107,7 @@ class MockBar { GTEST_DISALLOW_COPY_AND_ASSIGN_(MockBar); }; -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Tests that a nice mock generates no warning for uninteresting calls. TEST(NiceMockTest, NoWarningForUninterestingCall) { @@ -151,7 +151,7 @@ TEST(NiceMockTest, InfoForUninterestingCall) { GMOCK_FLAG(verbose) = saved_flag; } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION // Tests that a nice mock allows expected calls. TEST(NiceMockTest, AllowsExpectedCall) { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 1d0c491b..50af1fef 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -95,11 +95,11 @@ using testing::internal::kWarningVerbosity; using testing::internal::String; using testing::internal::string; -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION using testing::HasSubstr; using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif class Result {}; @@ -518,7 +518,7 @@ TEST(ExpectCallSyntaxTest, DefaultCardinalityIsOnce) { }, "to be called once"); } -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Tests that Google Mock doesn't print a warning when the number of // WillOnce() is adequate. @@ -643,7 +643,7 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooFewActions) { b.DoB(); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION // Tests the semantics of ON_CALL(). @@ -797,7 +797,7 @@ TEST(ExpectCallTest, NthMatchTakesNthAction) { EXPECT_EQ(3, b.DoB()); } -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Tests that the default action is taken when the WillOnce(...) list is // exhausted and there is no WillRepeatedly(). @@ -832,7 +832,7 @@ TEST(ExpectCallTest, TakesDefaultActionWhenWillListIsExhausted) { " - returning default value.")); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION // Tests that the WillRepeatedly() action is taken when the WillOnce(...) // list is exhausted. @@ -1802,7 +1802,7 @@ class VerboseFlagPreservingFixture : public testing::Test { GTEST_DISALLOW_COPY_AND_ASSIGN_(VerboseFlagPreservingFixture); }; -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Tests that an uninteresting mock function call generates a warning // containing the stack trace. @@ -1979,7 +1979,7 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { TestUninterestingCall(true); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION // A helper class that generates a failure when printed. We use it to // ensure that Google Mock doesn't print a value (even to an internal -- cgit v1.2.3 From ad7c462be7ea6041419426f98b5653bd98ad14dc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 9 Sep 2010 22:16:17 +0000 Subject: Simplifies the VC projects by using gmock-all.cc and gmock_all_test.cc. Also fixes a missing include directory for gmock_main in the Release mode. I had to add /bigobj to gmock_test.vcproj to make the compiler happy, as we now need to generate code for many functions in the same translation unit. --- msvc/gmock.vcproj | 70 +++----------------------------------------------- msvc/gmock_main.vcproj | 2 +- msvc/gmock_test.vcproj | 48 ++++------------------------------ 3 files changed, 9 insertions(+), 111 deletions(-) diff --git a/msvc/gmock.vcproj b/msvc/gmock.vcproj index 39d9dc9e..e50f88ce 100644 --- a/msvc/gmock.vcproj +++ b/msvc/gmock.vcproj @@ -41,7 +41,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msvc/gmock_main.vcproj b/msvc/gmock_main.vcproj index 8e0eccb8..f0e2fa3c 100644 --- a/msvc/gmock_main.vcproj +++ b/msvc/gmock_main.vcproj @@ -170,7 +170,7 @@ > diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj index fd969d7c..a0a2f0e5 100644 --- a/msvc/gmock_test.vcproj +++ b/msvc/gmock_test.vcproj @@ -40,8 +40,9 @@ /> - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From 53e08c44dd34857ba57581d7c5774d6c96a8d0e1 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 14 Sep 2010 05:38:21 +0000 Subject: Include gtest and gmock headers as user headers instead of system headers. --- include/gmock/gmock-actions.h | 4 ++-- include/gmock/gmock-cardinalities.h | 4 ++-- include/gmock/gmock-generated-actions.h | 4 ++-- include/gmock/gmock-generated-actions.h.pump | 4 ++-- include/gmock/gmock-generated-function-mockers.h | 4 ++-- .../gmock/gmock-generated-function-mockers.h.pump | 4 ++-- include/gmock/gmock-generated-matchers.h | 2 +- include/gmock/gmock-generated-matchers.h.pump | 2 +- include/gmock/gmock-generated-nice-strict.h | 4 ++-- include/gmock/gmock-generated-nice-strict.h.pump | 4 ++-- include/gmock/gmock-matchers.h | 6 +++--- include/gmock/gmock-more-actions.h | 2 +- include/gmock/gmock-spec-builders.h | 12 ++++++------ include/gmock/gmock.h | 18 +++++++++--------- .../internal/gmock-generated-internal-utils.h | 2 +- .../internal/gmock-generated-internal-utils.h.pump | 2 +- include/gmock/internal/gmock-internal-utils.h | 6 +++--- include/gmock/internal/gmock-port.h | 4 ++-- scripts/fuse_gmock_files.py | 22 +++++++++++----------- src/gmock-all.cc | 2 +- src/gmock-cardinalities.cc | 6 +++--- src/gmock-internal-utils.cc | 8 ++++---- src/gmock-matchers.cc | 4 ++-- src/gmock-spec-builders.cc | 6 +++--- src/gmock.cc | 4 ++-- src/gmock_main.cc | 4 ++-- test/gmock-actions_test.cc | 10 +++++----- test/gmock-cardinalities_test.cc | 6 +++--- test/gmock-generated-actions_test.cc | 6 +++--- test/gmock-generated-function-mockers_test.cc | 6 +++--- test/gmock-generated-internal-utils_test.cc | 6 +++--- test/gmock-generated-matchers_test.cc | 8 ++++---- test/gmock-internal-utils_test.cc | 10 +++++----- test/gmock-matchers_test.cc | 8 ++++---- test/gmock-more-actions_test.cc | 6 +++--- test/gmock-nice-strict_test.cc | 8 ++++---- test/gmock-port_test.cc | 4 ++-- test/gmock-spec-builders_test.cc | 10 +++++----- test/gmock_leak_test_.cc | 2 +- test/gmock_link_test.h | 6 +++--- test/gmock_output_test_.cc | 4 ++-- test/gmock_test.cc | 4 ++-- 42 files changed, 124 insertions(+), 124 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index ddaaef24..6eb3f445 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -43,8 +43,8 @@ #include #endif -#include -#include +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" namespace testing { diff --git a/include/gmock/gmock-cardinalities.h b/include/gmock/gmock-cardinalities.h index ae4cb641..954a86ea 100644 --- a/include/gmock/gmock-cardinalities.h +++ b/include/gmock/gmock-cardinalities.h @@ -40,8 +40,8 @@ #include #include // NOLINT -#include -#include +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" namespace testing { diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 65652f8e..6ab014dd 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -38,8 +38,8 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ -#include -#include +#include "gmock/gmock-actions.h" +#include "gmock/internal/gmock-port.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index b1deb798..4d7c5cee 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -42,8 +42,8 @@ $$}} This meta comment fixes auto-indentation in editors. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ -#include -#include +#include "gmock/gmock-actions.h" +#include "gmock/internal/gmock-port.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 65090861..7b334e42 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -38,8 +38,8 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ -#include -#include +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index e0a0cd10..50b369bb 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -41,8 +41,8 @@ $var n = 10 $$ The maximum arity we support. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ -#include -#include +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index cb610543..68af306b 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -41,7 +41,7 @@ #include #include #include -#include +#include "gmock/gmock-matchers.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 02e3c980..cebdd0e6 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -43,7 +43,7 @@ $$ }} This line fixes auto-indentation of the following code in Emacs. #include #include #include -#include +#include "gmock/gmock-matchers.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-generated-nice-strict.h b/include/gmock/gmock-generated-nice-strict.h index 435467fa..4fb69fdc 100644 --- a/include/gmock/gmock-generated-nice-strict.h +++ b/include/gmock/gmock-generated-nice-strict.h @@ -59,8 +59,8 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ -#include -#include +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-port.h" namespace testing { diff --git a/include/gmock/gmock-generated-nice-strict.h.pump b/include/gmock/gmock-generated-nice-strict.h.pump index 96371f57..784635bd 100644 --- a/include/gmock/gmock-generated-nice-strict.h.pump +++ b/include/gmock/gmock-generated-nice-strict.h.pump @@ -62,8 +62,8 @@ $var n = 10 $$ The maximum arity we support. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ -#include -#include +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-port.h" namespace testing { diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 9f268d64..1938be90 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -46,9 +46,9 @@ #include #include -#include -#include -#include +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" namespace testing { diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index c60557e6..e418505a 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -36,7 +36,7 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ -#include +#include "gmock/gmock-generated-actions.h" namespace testing { namespace internal { diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 27d2b747..1676056c 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -66,12 +66,12 @@ #include #include -#include -#include -#include -#include -#include -#include +#include "gmock/gmock-actions.h" +#include "gmock/gmock-cardinalities.h" +#include "gmock/gmock-matchers.h" +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" namespace testing { diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index e3d5fd8e..ba9fa286 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -55,15 +55,15 @@ // // where all clauses are optional and WillOnce() can be repeated. -#include -#include -#include -#include -#include -#include -#include -#include -#include +#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-more-actions.h" +#include "gmock/gmock-generated-nice-strict.h" +#include "gmock/gmock-matchers.h" +#include "gmock/internal/gmock-internal-utils.h" namespace testing { diff --git a/include/gmock/internal/gmock-generated-internal-utils.h b/include/gmock/internal/gmock-generated-internal-utils.h index 6386b05a..1b52dceb 100644 --- a/include/gmock/internal/gmock-generated-internal-utils.h +++ b/include/gmock/internal/gmock-generated-internal-utils.h @@ -39,7 +39,7 @@ #ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ #define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ -#include +#include "gmock/internal/gmock-port.h" namespace testing { diff --git a/include/gmock/internal/gmock-generated-internal-utils.h.pump b/include/gmock/internal/gmock-generated-internal-utils.h.pump index f3128b04..821e474e 100644 --- a/include/gmock/internal/gmock-generated-internal-utils.h.pump +++ b/include/gmock/internal/gmock-generated-internal-utils.h.pump @@ -42,7 +42,7 @@ $var n = 10 $$ The maximum arity we support. #ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ #define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_ -#include +#include "gmock/internal/gmock-port.h" namespace testing { diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 19ea89eb..7aaf6de5 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -42,9 +42,9 @@ #include // NOLINT #include -#include -#include -#include +#include "gmock/internal/gmock-generated-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" namespace testing { namespace internal { diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index b644eb4f..bb3f5838 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -42,8 +42,8 @@ // Most of the types needed for porting Google Mock are also required // for Google Test and are defined in gtest-port.h. -#include -#include +#include "gtest/internal/gtest-linked_ptr.h" +#include "gtest/internal/gtest-port.h" // To avoid conditional compilation everywhere, we make it // gmock-port.h's responsibility to #include the header implementing diff --git a/scripts/fuse_gmock_files.py b/scripts/fuse_gmock_files.py index 4e892e9a..fc0baf79 100755 --- a/scripts/fuse_gmock_files.py +++ b/scripts/fuse_gmock_files.py @@ -75,8 +75,8 @@ sys.path.append(os.path.join(DEFAULT_GMOCK_ROOT_DIR, 'gtest/scripts')) import fuse_gtest_files gtest = fuse_gtest_files -# Regex for matching '#include '. -INCLUDE_GMOCK_FILE_REGEX = re.compile(r'^\s*#\s*include\s*<(gmock/.+)>') +# Regex for matching '#include "gmock/..."'. +INCLUDE_GMOCK_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gmock/.+)"') # Where to find the source seed files. GMOCK_H_SEED = 'include/gmock/gmock.h' @@ -135,19 +135,19 @@ def FuseGMockH(gmock_root, output_dir): for line in file(os.path.join(gmock_root, gmock_header_path), 'r'): m = INCLUDE_GMOCK_FILE_REGEX.match(line) if m: - # It's '#include ' - let's process it recursively. + # It's '#include "gmock/..."' - let's process it recursively. ProcessFile('include/' + m.group(1)) else: m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) if m: - # It's '#include '. We translate it to - # , regardless of what foo is, since all + # It's '#include "gtest/foo.h"'. We translate it to + # "gtest/gtest.h", regardless of what foo is, since all # gtest headers are fused into gtest/gtest.h. # There is no need to #include gtest.h twice. if not gtest.GTEST_H_SEED in processed_files: processed_files.add(gtest.GTEST_H_SEED) - output_file.write('#include <%s>\n' % (gtest.GTEST_H_OUTPUT,)) + output_file.write('#include "%s"\n' % (gtest.GTEST_H_OUTPUT,)) else: # Otherwise we copy the line unchanged to the output file. output_file.write(line) @@ -174,18 +174,18 @@ def FuseGMockAllCcToFile(gmock_root, output_file): for line in file(os.path.join(gmock_root, gmock_source_file), 'r'): m = INCLUDE_GMOCK_FILE_REGEX.match(line) if m: - # It's '#include '. We treat it as '#include - # ', as all other gmock headers are being fused + # It's '#include "gmock/foo.h"'. We treat it as '#include + # "gmock/gmock.h"', as all other gmock headers are being fused # into gmock.h and cannot be #included directly. - # There is no need to #include more than once. + # There is no need to #include "gmock/gmock.h" more than once. if not GMOCK_H_SEED in processed_files: processed_files.add(GMOCK_H_SEED) - output_file.write('#include <%s>\n' % (GMOCK_H_OUTPUT,)) + output_file.write('#include "%s"\n' % (GMOCK_H_OUTPUT,)) else: m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) if m: - # It's '#include '. + # It's '#include "gtest/..."'. # There is no need to #include gtest.h as it has been # #included by gtest-all.cc. pass diff --git a/src/gmock-all.cc b/src/gmock-all.cc index 76118d88..7aebce7a 100644 --- a/src/gmock-all.cc +++ b/src/gmock-all.cc @@ -37,7 +37,7 @@ // This line ensures that gmock.h can be compiled on its own, even // when it's fused. -#include +#include "gmock/gmock.h" // The following lines pull in the real gmock *.cc files. #include "src/gmock-cardinalities.cc" diff --git a/src/gmock-cardinalities.cc b/src/gmock-cardinalities.cc index 07eed469..1a7902b4 100644 --- a/src/gmock-cardinalities.cc +++ b/src/gmock-cardinalities.cc @@ -33,14 +33,14 @@ // // This file implements cardinalities. -#include +#include "gmock/gmock-cardinalities.h" #include #include // NOLINT #include #include -#include -#include +#include "gmock/internal/gmock-internal-utils.h" +#include "gtest/gtest.h" namespace testing { diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 9debe187..dd38132a 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -35,14 +35,14 @@ // Mock. They are subject to change without notice, so please DO NOT // USE THEM IN USER CODE. -#include +#include "gmock/internal/gmock-internal-utils.h" #include #include // NOLINT #include -#include -#include -#include +#include "gmock/gmock.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" namespace testing { namespace internal { diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc index 89007d9f..a5e6824d 100644 --- a/src/gmock-matchers.cc +++ b/src/gmock-matchers.cc @@ -34,8 +34,8 @@ // This file implements Matcher, Matcher, and // utilities for defining matchers. -#include -#include +#include "gmock/gmock-matchers.h" +#include "gmock/gmock-generated-matchers.h" #include #include diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index dab1a2c9..0d40d9cd 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -34,15 +34,15 @@ // This file implements the spec builder syntax (ON_CALL and // EXPECT_CALL). -#include +#include "gmock/gmock-spec-builders.h" #include #include // NOLINT #include #include #include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" #if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC #include // NOLINT diff --git a/src/gmock.cc b/src/gmock.cc index f487265d..700bcb2e 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -29,8 +29,8 @@ // // Author: wan@google.com (Zhanyong Wan) -#include -#include +#include "gmock/gmock.h" +#include "gmock/internal/gmock-port.h" namespace testing { diff --git a/src/gmock_main.cc b/src/gmock_main.cc index 0a3071bf..3725ae72 100644 --- a/src/gmock_main.cc +++ b/src/gmock_main.cc @@ -30,8 +30,8 @@ // Author: wan@google.com (Zhanyong Wan) #include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" // MS C++ compiler/linker has a bug on Windows (not on Windows CE), which // causes a link error when _tmain is defined in a static library and UNICODE diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 50cc6f98..fd52ce21 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -33,14 +33,14 @@ // // This file tests the built-in actions. -#include +#include "gmock/gmock-actions.h" #include #include #include -#include -#include -#include -#include +#include "gmock/gmock.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" namespace { diff --git a/test/gmock-cardinalities_test.cc b/test/gmock-cardinalities_test.cc index f6a94916..64815e57 100644 --- a/test/gmock-cardinalities_test.cc +++ b/test/gmock-cardinalities_test.cc @@ -33,9 +33,9 @@ // // This file tests the built-in cardinalities. -#include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" namespace { diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 3c076d7c..f4d42a38 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -33,13 +33,13 @@ // // This file tests the built-in actions generated by a script. -#include +#include "gmock/gmock-generated-actions.h" #include #include #include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" namespace testing { namespace gmock_generated_actions_test { diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index 5d839c41..d000386d 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -33,12 +33,12 @@ // // This file tests the function mocker classes. -#include +#include "gmock/gmock-generated-function-mockers.h" #include #include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" #if GTEST_OS_WINDOWS // MSDN says the header file to be included for STDMETHOD is BaseTyps.h but diff --git a/test/gmock-generated-internal-utils_test.cc b/test/gmock-generated-internal-utils_test.cc index 13b4c5cf..1156c7db 100644 --- a/test/gmock-generated-internal-utils_test.cc +++ b/test/gmock-generated-internal-utils_test.cc @@ -33,9 +33,9 @@ // // This file tests the internal utilities. -#include -#include -#include +#include "gmock/internal/gmock-generated-internal-utils.h" +#include "gmock/internal/gmock-internal-utils.h" +#include "gtest/gtest.h" namespace { diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 600783c7..2a7f498a 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -31,7 +31,7 @@ // // This file tests the built-in matchers generated by a script. -#include +#include "gmock/gmock-generated-matchers.h" #include #include @@ -41,9 +41,9 @@ #include #include -#include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" namespace { diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 720d6c72..5b0e8043 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -33,16 +33,16 @@ // // This file tests the internal utilities. -#include +#include "gmock/internal/gmock-internal-utils.h" #include #include #include #include #include -#include -#include -#include -#include +#include "gmock/gmock.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" #if GTEST_OS_CYGWIN #include // For ssize_t. NOLINT diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index c2db86ca..dfa34a42 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -33,7 +33,7 @@ // // This file tests some commonly used argument matchers. -#include +#include "gmock/gmock-matchers.h" #include #include @@ -45,9 +45,9 @@ #include #include #include -#include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" namespace testing { diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index be7b1273..c09cccf4 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -33,13 +33,13 @@ // // This file tests the built-in actions in gmock-more-actions.h. -#include +#include "gmock/gmock-more-actions.h" #include #include #include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" namespace testing { namespace gmock_more_actions_test { diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index f340cecb..e3344180 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -29,12 +29,12 @@ // // Author: wan@google.com (Zhanyong Wan) -#include +#include "gmock/gmock-generated-nice-strict.h" #include -#include -#include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" // This must not be defined inside the ::testing namespace, or it will // clash with ::testing::Mock. diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index a84eb9ea..d6a8d444 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -33,8 +33,8 @@ // // This file tests the internal cross-platform support utilities. -#include -#include +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" // NOTE: if this file is left without tests for some reason, put a dummy // test here to make references to symbols in the gtest library and avoid diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 50af1fef..6c844e22 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -33,16 +33,16 @@ // // This file tests the spec builder syntax. -#include +#include "gmock/gmock-spec-builders.h" #include // NOLINT #include #include -#include -#include -#include -#include +#include "gmock/gmock.h" +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" namespace testing { namespace internal { diff --git a/test/gmock_leak_test_.cc b/test/gmock_leak_test_.cc index 24dfc1ff..1d27d22f 100644 --- a/test/gmock_leak_test_.cc +++ b/test/gmock_leak_test_.cc @@ -34,7 +34,7 @@ // This program is for verifying that a leaked mock object can be // caught by Google Mock's leak detector. -#include +#include "gmock/gmock.h" namespace { diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index aa9aab3a..00b2110d 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -114,14 +114,14 @@ #ifndef GMOCK_TEST_GMOCK_LINK_TEST_H_ #define GMOCK_TEST_GMOCK_LINK_TEST_H_ -#include +#include "gmock/gmock.h" #if !GTEST_OS_WINDOWS_MOBILE #include #endif -#include -#include +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" #include #include diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index 24c9b383..c8e6b831 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -32,12 +32,12 @@ // Tests Google Mock's output in various scenarios. This ensures that // Google Mock's messages are readable and useful. -#include +#include "gmock/gmock.h" #include #include -#include +#include "gtest/gtest.h" using testing::_; using testing::AnyNumber; diff --git a/test/gmock_test.cc b/test/gmock_test.cc index 0c832607..ba137dd3 100644 --- a/test/gmock_test.cc +++ b/test/gmock_test.cc @@ -33,10 +33,10 @@ // // This file tests code in gmock.cc. -#include +#include "gmock/gmock.h" #include -#include +#include "gtest/gtest.h" using testing::GMOCK_FLAG(verbose); using testing::InitGoogleMock; -- cgit v1.2.3 From 4c91551c3b342ec58910f3622297217615b0afb3 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Sat, 25 Sep 2010 00:52:20 +0000 Subject: Updates the gMock Doctor script to understand Clang error messages. --- scripts/gmock_doctor.py | 429 ++++++++++++++++++++++++++++-------------------- 1 file changed, 253 insertions(+), 176 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index fad4e340..1918cf6c 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -29,7 +29,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Converts gcc errors in code using Google Mock to plain English.""" +"""Converts compiler's errors in code using Google Mock to plain English.""" __author__ = 'wan@google.com (Zhanyong Wan)' @@ -124,8 +124,11 @@ _COMMON_GMOCK_SYMBOLS = [ 'Mock', ] -# Regex for matching source file path and line number in gcc's errors. -_FILE_LINE_RE = r'(?P.*):(?P\d+):\s+' +# Regex for matching source file path and line number in the compiler's errors. +_GCC_FILE_LINE_RE = r'(?P.*):(?P\d+):\s+' +_CLANG_FILE_LINE_RE = r'(?P.*):(?P\d+):(?P\d+):\s+' +_CLANG_NON_GMOCK_FILE_LINE_RE = ( + r'(?P.*[/\\^](?!gmock-)[^/\\]+):(?P\d+):(?P\d+):\s+') def _FindAllMatches(regex, s): @@ -135,109 +138,174 @@ def _FindAllMatches(regex, s): return r.finditer(s) -def _GenericDiagnoser(short_name, long_name, regex, diagnosis, msg): +def _GenericDiagnoser(short_name, long_name, diagnoses, msg): """Diagnoses the given disease by pattern matching. + Can provide different diagnoses for different patterns. + Args: short_name: Short name of the disease. long_name: Long name of the disease. - regex: Regex for matching the symptoms. - diagnosis: Pattern for formatting the diagnosis. - msg: Gcc's error messages. + diagnoses: A list of pairs (regex, pattern for formatting the diagnosis + for matching regex). + msg: Compiler's error messages. Yields: Tuples of the form (short name of disease, long name of disease, diagnosis). """ - - diagnosis = '%(file)s:%(line)s:' + diagnosis - for m in _FindAllMatches(regex, msg): - yield (short_name, long_name, diagnosis % m.groupdict()) + for regex, diagnosis in diagnoses: + if re.search(regex, msg): + diagnosis = '%(file)s:%(line)s:' + diagnosis + for m in _FindAllMatches(regex, msg): + yield (short_name, long_name, diagnosis % m.groupdict()) def _NeedToReturnReferenceDiagnoser(msg): - """Diagnoses the NRR disease, given the error messages by gcc.""" - - regex = (r'In member function \'testing::internal::ReturnAction.*\n' - + _FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-actions\.h.*error: creating array with negative size') + """Diagnoses the NRR disease, given the error messages by the compiler.""" + + gcc_regex = (r'In member function \'testing::internal::ReturnAction.*\n' + + _GCC_FILE_LINE_RE + r'instantiated from here\n' + r'.*gmock-actions\.h.*error: creating array with negative size') + clang_regex = (r'error: array size is negative\r?\n' + r'(.*\n)*?' + + _CLANG_NON_GMOCK_FILE_LINE_RE + + r'note: in instantiation of function template specialization ' + r'\'testing::internal::ReturnAction<(?P).*>' + r'::operator Action<.*>\' requested here') diagnosis = """ -You are using an Return() action in a function that returns a reference. -Please use ReturnRef() instead.""" +You are using a Return() action in a function that returns a reference to +%(type)s. Please use ReturnRef() instead.""" return _GenericDiagnoser('NRR', 'Need to Return Reference', - regex, diagnosis, msg) + [(clang_regex, diagnosis), + (gcc_regex, diagnosis % {'type': 'a type'})], + msg) def _NeedToReturnSomethingDiagnoser(msg): - """Diagnoses the NRS disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + - r'(instantiated from here\n.' - r'*gmock.*actions\.h.*error: void value not ignored)' - r'|(error: control reaches end of non-void function)') + """Diagnoses the NRS disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.' + r'*gmock.*actions\.h.*error: void value not ignored)' + r'|(error: control reaches end of non-void function)') + clang_regex1 = (_CLANG_FILE_LINE_RE + + r'error: cannot initialize return object ' + r'of type \'Result\' \(aka \'(?P).*\'\) ' + r'with an rvalue of type \'void\'') + clang_regex2 = (_CLANG_FILE_LINE_RE + + r'error: cannot initialize return object ' + r'of type \'(?P).*\' ' + r'with an rvalue of type \'void\'') diagnosis = """ You are using an action that returns void, but it needs to return -*something*. Please tell it *what* to return. Perhaps you can use +%(return_type)s. Please tell it *what* to return. Perhaps you can use the pattern DoAll(some_action, Return(some_value))?""" - return _GenericDiagnoser('NRS', 'Need to Return Something', - regex, diagnosis, msg) + return _GenericDiagnoser( + 'NRS', + 'Need to Return Something', + [(gcc_regex, diagnosis % {'return_type': '*something*'}), + (clang_regex1, diagnosis), + (clang_regex2, diagnosis)], + msg) def _NeedToReturnNothingDiagnoser(msg): - """Diagnoses the NRN disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + r'instantiated from here\n' - r'.*gmock-actions\.h.*error: instantiation of ' - r'\'testing::internal::ReturnAction::Impl::value_\' ' - r'as type \'void\'') + """Diagnoses the NRN disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n' + r'.*gmock-actions\.h.*error: instantiation of ' + r'\'testing::internal::ReturnAction::Impl::value_\' ' + r'as type \'void\'') + clang_regex1 = (r'error: field has incomplete type ' + r'\'Result\' \(aka \'void\'\)(\r)?\n' + r'(.*\n)*?' + + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' + r'of function template specialization ' + r'\'testing::internal::ReturnAction<(?P.*)>' + r'::operator Action\' requested here') + clang_regex2 = (r'error: field has incomplete type ' + r'\'Result\' \(aka \'void\'\)(\r)?\n' + r'(.*\n)*?' + + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' + r'of function template specialization ' + r'\'testing::internal::DoBothAction<.*>' + r'::operator Action<(?P.*) \(.*\)>\' ' + r'requested here') diagnosis = """ -You are using an action that returns *something*, but it needs to return +You are using an action that returns %(return_type)s, but it needs to return void. Please use a void-returning action instead. All actions but the last in DoAll(...) must return void. Perhaps you need to re-arrange the order of actions in a DoAll(), if you are using one?""" - return _GenericDiagnoser('NRN', 'Need to Return Nothing', - regex, diagnosis, msg) + return _GenericDiagnoser( + 'NRN', + 'Need to Return Nothing', + [(gcc_regex, diagnosis % {'return_type': '*something*'}), + (clang_regex1, diagnosis), + (clang_regex2, diagnosis)], + msg) def _IncompleteByReferenceArgumentDiagnoser(msg): - """Diagnoses the IBRA disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + r'instantiated from here\n' - r'.*gtest-printers\.h.*error: invalid application of ' - r'\'sizeof\' to incomplete type \'(?P.*)\'') + """Diagnoses the IBRA disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n' + r'.*gtest-printers\.h.*error: invalid application of ' + r'\'sizeof\' to incomplete type \'(?P.*)\'') + + clang_regex = (r'.*gtest-printers\.h.*error: invalid application of ' + r'\'sizeof\' to an incomplete type ' + r'\'(?P.*)( const)?\'\r?\n' + r'(.*\n)*?' + + _CLANG_NON_GMOCK_FILE_LINE_RE + + r'note: in instantiation of member function ' + r'\'testing::internal::FunctionMocker<.*>::Invoke\' ' + r'requested here') diagnosis = """ In order to mock this function, Google Mock needs to see the definition of type "%(type)s" - declaration alone is not enough. Either #include the header that defines it, or change the argument to be passed by pointer.""" + return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type', - regex, diagnosis, msg) + [(gcc_regex, diagnosis), + (clang_regex, diagnosis)], + msg) def _OverloadedFunctionMatcherDiagnoser(msg): - """Diagnoses the OFM disease, given the error messages by gcc.""" + """Diagnoses the OFM disease, given the error messages by the compiler.""" - regex = (_FILE_LINE_RE + r'error: no matching function for ' - r'call to \'Truly\(\)') + gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for ' + r'call to \'Truly\(\)') + clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for ' + r'call to \'Truly') diagnosis = """ The argument you gave to Truly() is an overloaded function. Please tell -gcc which overloaded version you want to use. +your compiler which overloaded version you want to use. For example, if you want to use the version whose signature is bool Foo(int n); you should write Truly(static_cast(Foo))""" return _GenericDiagnoser('OFM', 'Overloaded Function Matcher', - regex, diagnosis, msg) + [(gcc_regex, diagnosis), + (clang_regex, diagnosis)], + msg) def _OverloadedFunctionActionDiagnoser(msg): - """Diagnoses the OFA disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + r'error: no matching function for call to \'Invoke\(' - r'') + """Diagnoses the OFA disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to ' + r'\'Invoke\(') + clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching ' + r'function for call to \'Invoke\'\r?\n' + r'(.*\n)*?' + r'.*\bgmock-\w+-actions\.h:\d+:\d+:\s+' + r'note: candidate template ignored:\s+' + r'couldn\'t infer template argument \'FunctionImpl\'') diagnosis = """ -You are passing an overloaded function to Invoke(). Please tell gcc +Function you are passing to Invoke is overloaded. Please tell your compiler which overloaded version you want to use. For example, if you want to use the version whose signature is @@ -245,18 +313,26 @@ For example, if you want to use the version whose signature is you should write something like Invoke(static_cast(MyFunction))""" return _GenericDiagnoser('OFA', 'Overloaded Function Action', - regex, diagnosis, msg) - - -def _OverloadedMethodActionDiagnoser1(msg): - """Diagnoses the OMA disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + r'error: ' - r'.*no matching function for call to \'Invoke\(.*, ' - r'unresolved overloaded function type>') + [(gcc_regex, diagnosis), + (clang_regex, diagnosis)], + msg) + + +def _OverloadedMethodActionDiagnoser(msg): + """Diagnoses the OMA disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for ' + r'call to \'Invoke\(.+, \)') + clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function ' + r'for call to \'Invoke\'\r?\n' + r'(.*\n)*?' + r'.*\bgmock-\w+-actions\.h:\d+:\d+: ' + r'note: candidate function template not viable: ' + r'requires 1 argument, but 2 were provided') diagnosis = """ The second argument you gave to Invoke() is an overloaded method. Please -tell gcc which overloaded version you want to use. +tell your compiler which overloaded version you want to use. For example, if you want to use the version whose signature is class Foo { @@ -266,15 +342,20 @@ For example, if you want to use the version whose signature is you should write something like Invoke(foo, static_cast(&Foo::Bar))""" return _GenericDiagnoser('OMA', 'Overloaded Method Action', - regex, diagnosis, msg) + [(gcc_regex, diagnosis), + (clang_regex, diagnosis)], + msg) def _MockObjectPointerDiagnoser(msg): - """Diagnoses the MOP disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + r'error: request for member ' - r'\'gmock_(?P.+)\' in \'(?P.+)\', ' - r'which is of non-class type \'(.*::)*(?P.+)\*\'') + """Diagnoses the MOP disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member ' + r'\'gmock_(?P.+)\' in \'(?P.+)\', ' + r'which is of non-class type \'(.*::)*(?P.+)\*\'') + clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type ' + r'\'(?P.*?) *\' is a pointer; ' + r'maybe you meant to use \'->\'\?') diagnosis = """ The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*, not a *pointer* to it. Please write '*(%(mock_object)s)' instead of @@ -294,63 +375,89 @@ and the following mock instance: you should use the EXPECT_CALL like this: EXPECT_CALL(*mock_ptr, %(method)s(...));""" - return _GenericDiagnoser('MOP', 'Mock Object Pointer', - regex, diagnosis, msg) - -def _OverloadedMethodActionDiagnoser2(msg): - """Diagnoses the OMA disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + r'error: no matching function for ' - r'call to \'Invoke\(.+, \)') - diagnosis = """ -The second argument you gave to Invoke() is an overloaded method. Please -tell gcc which overloaded version you want to use. - -For example, if you want to use the version whose signature is - class Foo { - ... - bool Bar(int n, double x); - }; -you should write something like - Invoke(foo, static_cast(&Foo::Bar))""" - return _GenericDiagnoser('OMA', 'Overloaded Method Action', - regex, diagnosis, msg) + return _GenericDiagnoser( + 'MOP', + 'Mock Object Pointer', + [(gcc_regex, diagnosis), + (clang_regex, diagnosis % {'mock_object': 'mock_object', + 'method': 'method', + 'class_name': '%(class_name)s'})], + msg) def _NeedToUseSymbolDiagnoser(msg): - """Diagnoses the NUS disease, given the error messages by gcc.""" + """Diagnoses the NUS disease, given the error messages by the compiler.""" - regex = (_FILE_LINE_RE + r'error: \'(?P.+)\' ' - r'(was not declared in this scope|has not been declared)') + gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P.+)\' ' + r'(was not declared in this scope|has not been declared)') + clang_regex = (_CLANG_FILE_LINE_RE + r'error: use of undeclared identifier ' + r'\'(?P.+)\'') diagnosis = """ '%(symbol)s' is defined by Google Mock in the testing namespace. Did you forget to write using testing::%(symbol)s; ?""" - for m in _FindAllMatches(regex, msg): + for m in (list(_FindAllMatches(gcc_regex, msg)) + + list(_FindAllMatches(clang_regex, msg))): symbol = m.groupdict()['symbol'] if symbol in _COMMON_GMOCK_SYMBOLS: yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) def _NeedToUseReturnNullDiagnoser(msg): - """Diagnoses the NRNULL disease, given the error messages by gcc.""" - - regex = ('instantiated from \'testing::internal::ReturnAction' - '::operator testing::Action\(\) const.*\n' + - _FILE_LINE_RE + r'instantiated from here\n' - r'.*error: no matching function for call to \'implicit_cast\(' - r'long int&\)') + """Diagnoses the NRNULL disease, given the error messages by the compiler.""" + + gcc_regex = ('instantiated from \'testing::internal::ReturnAction' + '::operator testing::Action\(\) const.*\n' + + _GCC_FILE_LINE_RE + r'instantiated from here\n' + r'.*error: no matching function for call to \'implicit_cast\(' + r'long int&\)') + clang_regex = (r'\bgmock-actions.h:.* error: no matching function for ' + r'call to \'implicit_cast\'\r?\n' + r'(.*\n)*?' + + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' + r'of function template specialization ' + r'\'testing::internal::ReturnAction::operator ' + r'Action<(?P.*)\(\)>\' requested here') diagnosis = """ You are probably calling Return(NULL) and the compiler isn't sure how to turn -NULL into the right type. Use ReturnNull() instead. +NULL into %(type)s. Use ReturnNull() instead. Note: the line number may be off; please fix all instances of Return(NULL).""" - return _GenericDiagnoser('NRNULL', 'Need to use ReturnNull', - regex, diagnosis, msg) + return _GenericDiagnoser( + 'NRNULL', 'Need to use ReturnNull', + [(clang_regex, diagnosis), + (gcc_regex, diagnosis % {'type': 'the right type'})], + msg) + +def _TypeInTemplatedBaseDiagnoser(msg): + """Diagnoses the TTB disease, given the error messages by the compiler.""" -_TTB_DIAGNOSIS = """ + # This version works when the type is used as the mock function's return + # type. + gcc_4_3_1_regex_type_in_retval = ( + r'In member function \'int .*\n' + _GCC_FILE_LINE_RE + + r'error: a function call cannot appear in a constant-expression') + gcc_4_4_0_regex_type_in_retval = ( + r'error: a function call cannot appear in a constant-expression' + + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n') + # This version works when the type is used as the mock function's sole + # parameter type. + gcc_regex_type_of_sole_param = ( + _GCC_FILE_LINE_RE + + r'error: \'(?P.+)\' was not declared in this scope\n' + r'.*error: template argument 1 is invalid\n') + # This version works when the type is used as a parameter of a mock + # function that has multiple parameters. + gcc_regex_type_of_a_param = ( + r'error: expected `;\' before \'::\' token\n' + + _GCC_FILE_LINE_RE + + r'error: \'(?P.+)\' was not declared in this scope\n' + r'.*error: template argument 1 is invalid\n' + r'.*error: \'.+\' was not declared in this scope') + + diagnosis = """ In a mock class template, types or typedefs defined in the base class template are *not* automatically visible. This is how C++ works. Before you can use a type or typedef named %(type)s defined in base class Base, you @@ -358,78 +465,47 @@ need to make it visible. One way to do it is: typedef typename Base::%(type)s %(type)s;""" - -def _TypeInTemplatedBaseDiagnoser1(msg): - """Diagnoses the TTB disease, given the error messages by gcc. - - This version works when the type is used as the mock function's return - type. - """ - - gcc_4_3_1_regex = ( - r'In member function \'int .*\n' + _FILE_LINE_RE + - r'error: a function call cannot appear in a constant-expression') - gcc_4_4_0_regex = ( - r'error: a function call cannot appear in a constant-expression' - + _FILE_LINE_RE + r'error: template argument 1 is invalid\n') - diagnosis = _TTB_DIAGNOSIS % {'type': 'Foo'} - return (list(_GenericDiagnoser('TTB', 'Type in Template Base', - gcc_4_3_1_regex, diagnosis, msg)) + - list(_GenericDiagnoser('TTB', 'Type in Template Base', - gcc_4_4_0_regex, diagnosis, msg))) - - -def _TypeInTemplatedBaseDiagnoser2(msg): - """Diagnoses the TTB disease, given the error messages by gcc. - - This version works when the type is used as the mock function's sole - parameter type. - """ - - regex = (_FILE_LINE_RE + - r'error: \'(?P.+)\' was not declared in this scope\n' - r'.*error: template argument 1 is invalid\n') - return _GenericDiagnoser('TTB', 'Type in Template Base', - regex, _TTB_DIAGNOSIS, msg) - - -def _TypeInTemplatedBaseDiagnoser3(msg): - """Diagnoses the TTB disease, given the error messages by gcc. - - This version works when the type is used as a parameter of a mock - function that has multiple parameters. - """ - - regex = (r'error: expected `;\' before \'::\' token\n' - + _FILE_LINE_RE + - r'error: \'(?P.+)\' was not declared in this scope\n' - r'.*error: template argument 1 is invalid\n' - r'.*error: \'.+\' was not declared in this scope') - return _GenericDiagnoser('TTB', 'Type in Template Base', - regex, _TTB_DIAGNOSIS, msg) + return _GenericDiagnoser( + 'TTB', 'Type in Template Base', + [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}), + (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}), + (gcc_regex_type_of_sole_param, diagnosis), + (gcc_regex_type_of_a_param, diagnosis)], + msg) def _WrongMockMethodMacroDiagnoser(msg): - """Diagnoses the WMM disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + - r'.*this_method_does_not_take_(?P\d+)_argument.*\n' - r'.*\n' - r'.*candidates are.*FunctionMocker<[^>]+A(?P\d+)\)>') + """Diagnoses the WMM disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + + r'.*this_method_does_not_take_(?P\d+)_argument.*\n' + r'.*\n' + r'.*candidates are.*FunctionMocker<[^>]+A(?P\d+)\)>') + clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + + r'error: array size is negative\r?\n' + r'(.*\n)*?' + r'(?P=file):(?P=line):(?P=column): error: too few arguments ' + r'to function call, expected (?P\d+), ' + r'have (?P\d+)') diagnosis = """ You are using MOCK_METHOD%(wrong_args)s to define a mock method that has %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro', - regex, diagnosis, msg) + [(gcc_regex, diagnosis), + (clang_regex, diagnosis)], + msg) def _WrongParenPositionDiagnoser(msg): - """Diagnoses the WPP disease, given the error messages by gcc.""" - - regex = (_FILE_LINE_RE + - r'error:.*testing::internal::MockSpec<.* has no member named \'' - r'(?P\w+)\'') + """Diagnoses the WPP disease, given the error messages by the compiler.""" + + gcc_regex = (_GCC_FILE_LINE_RE + + r'error:.*testing::internal::MockSpec<.* has no member named \'' + r'(?P\w+)\'') + clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + + r'error: no member named \'(?P\w+)\' in ' + r'\'testing::internal::MockSpec<.*>\'') diagnosis = """ The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* ".%(method)s". For example, you should write: @@ -437,7 +513,9 @@ The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* instead of: EXPECT_CALL(my_mock, Foo(_).%(method)s(...));""" return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position', - regex, diagnosis, msg) + [(gcc_regex, diagnosis), + (clang_regex, diagnosis)], + msg) _DIAGNOSERS = [ @@ -450,18 +528,17 @@ _DIAGNOSERS = [ _NeedToUseSymbolDiagnoser, _OverloadedFunctionActionDiagnoser, _OverloadedFunctionMatcherDiagnoser, - _OverloadedMethodActionDiagnoser1, - _OverloadedMethodActionDiagnoser2, - _TypeInTemplatedBaseDiagnoser1, - _TypeInTemplatedBaseDiagnoser2, - _TypeInTemplatedBaseDiagnoser3, + _OverloadedMethodActionDiagnoser, + _TypeInTemplatedBaseDiagnoser, _WrongMockMethodMacroDiagnoser, _WrongParenPositionDiagnoser, ] def Diagnose(msg): - """Generates all possible diagnoses given the gcc error message.""" + """Generates all possible diagnoses given the compiler error message.""" + + msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting. diagnoses = [] for diagnoser in _DIAGNOSERS: @@ -493,7 +570,7 @@ def main(): print """ Uh-oh, I'm not smart enough to figure out what the problem is. :-( However... -If you send your source code and gcc's error messages to +If you send your source code and the compiler's error messages to googlemock@googlegroups.com, you can be helped and I can get smarter -- win-win for us!""" else: @@ -511,8 +588,8 @@ win-win for us!""" print d print """ How did I do? If you think I'm wrong or unhelpful, please send your -source code and gcc's error messages to googlemock@googlegroups.com. Then -you can be helped and I can get smarter -- I promise I won't be upset!""" +source code and compiler's error messages to googlemock@googlegroups.com. +Then you can be helped and I can get smarter -- I promise I won't be upset!""" if __name__ == '__main__': -- cgit v1.2.3 From 736baa8ac028f01a5c79ebecb6fc7043b47d3c4e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 27 Sep 2010 17:44:16 +0000 Subject: Prints the type of the actual value as part of a match message when appropriate. --- include/gmock/gmock-matchers.h | 15 ++++++ test/gmock-matchers_test.cc | 101 +++++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 28 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 1938be90..627f3ff0 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -461,6 +461,16 @@ inline void PrintIfNotEmpty(const internal::string& 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. @@ -479,6 +489,11 @@ bool MatchPrintAndExplain(Value& value, const Matcher& matcher, 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; diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index dfa34a42..deff9b23 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -123,6 +123,7 @@ using testing::internal::DummyMatchResultListener; using testing::internal::ExplainMatchFailureTupleTo; using testing::internal::FloatingEqMatcher; using testing::internal::FormatMatcherDescription; +using testing::internal::IsReadableTypeName; using testing::internal::JoinAsTuple; using testing::internal::RE; using testing::internal::StreamMatchResultListener; @@ -164,6 +165,14 @@ Matcher GreaterThan(int n) { return MakeMatcher(new GreaterThanMatcher(n)); } +string OfType(const string& type_name) { +#if GTEST_HAS_RTTI + return " (of type " + type_name + ")"; +#else + return ""; +#endif +} + // Returns the description of the given matcher. template string Describe(const Matcher& m) { @@ -2383,7 +2392,7 @@ TEST(MatcherAssertionTest, WorksWhenMatcherIsSatisfied) { TEST(MatcherAssertionTest, WorksWhenMatcherIsNotSatisfied) { // 'n' must be static as it is used in an EXPECT_FATAL_FAILURE(), // which cannot reference auto variables. - static int n; + static unsigned short n; // NOLINT n = 5; // VC++ prior to version 8.0 SP1 has a bug where it will not see any @@ -2394,13 +2403,13 @@ TEST(MatcherAssertionTest, WorksWhenMatcherIsNotSatisfied) { EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Gt(10)), "Value of: n\n" "Expected: is > 10\n" - " Actual: 5"); + " Actual: 5" + OfType("unsigned short")); n = 0; EXPECT_NONFATAL_FAILURE( EXPECT_THAT(n, ::testing::AllOf(::testing::Le(7), ::testing::Ge(5))), "Value of: n\n" "Expected: (is <= 7) and (is >= 5)\n" - " Actual: 0"); + " Actual: 0" + OfType("unsigned short")); } // Tests that ASSERT_THAT() and EXPECT_THAT() work when the argument @@ -2416,7 +2425,7 @@ TEST(MatcherAssertionTest, WorksForByRefArguments) { "Expected: does not reference the variable @"); // Tests the "Actual" part. EXPECT_FATAL_FAILURE(ASSERT_THAT(n, ::testing::Not(::testing::Ref(n))), - "Actual: 0, which is located @"); + "Actual: 0" + OfType("int") + ", which is located @"); } #if !GTEST_OS_SYMBIAN @@ -2439,12 +2448,16 @@ TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { Matcher ends_with_ok = EndsWith("ok"); ASSERT_THAT("book", ends_with_ok); - + const string bad = "bad"; + EXPECT_NONFATAL_FAILURE(EXPECT_THAT(bad, ends_with_ok), + "Value of: bad\n" + "Expected: ends with \"ok\"\n" + " Actual: \"bad\""); Matcher is_greater_than_5 = Gt(5); EXPECT_NONFATAL_FAILURE(EXPECT_THAT(5, is_greater_than_5), "Value of: 5\n" "Expected: is > 5\n" - " Actual: 5"); + " Actual: 5" + OfType("int")); } #endif // !GTEST_OS_SYMBIAN @@ -2768,16 +2781,16 @@ TEST(PointeeTest, CanExplainMatchResult) { EXPECT_EQ("", Explain(m, static_cast(NULL))); - const Matcher m2 = Pointee(GreaterThan(1)); - int n = 3; - EXPECT_EQ("which points to 3, which is 2 more than 1", + const Matcher m2 = Pointee(GreaterThan(1)); // NOLINT + long n = 3; // NOLINT + EXPECT_EQ("which points to 3" + OfType("long") + ", which is 2 more than 1", Explain(m2, &n)); } TEST(PointeeTest, AlwaysExplainsPointee) { const Matcher m = Pointee(0); int n = 42; - EXPECT_EQ("which points to 42", Explain(m, &n)); + EXPECT_EQ("which points to 42" + OfType("int"), Explain(m, &n)); } // An uncopyable class. @@ -2914,10 +2927,12 @@ TEST(FieldTest, CanExplainMatchResult) { AStruct a; a.x = 1; - EXPECT_EQ("whose given field is 1", Explain(m, a)); + EXPECT_EQ("whose given field is 1" + OfType("int"), Explain(m, a)); m = Field(&AStruct::x, GreaterThan(0)); - EXPECT_EQ("whose given field is 1, which is 1 more than 0", Explain(m, a)); + EXPECT_EQ( + "whose given field is 1" + OfType("int") + ", which is 1 more than 0", + Explain(m, a)); } // Tests that Field() works when the argument is a pointer to const. @@ -2984,11 +2999,12 @@ TEST(FieldForPointerTest, CanExplainMatchResult) { AStruct a; a.x = 1; EXPECT_EQ("", Explain(m, static_cast(NULL))); - EXPECT_EQ("which points to an object whose given field is 1", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given field is 1" + OfType("int"), + Explain(m, &a)); m = Field(&AStruct::x, GreaterThan(0)); - EXPECT_EQ("which points to an object whose given field is 1, " - "which is 1 more than 0", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given field is 1" + OfType("int") + + ", which is 1 more than 0", Explain(m, &a)); } // A user-defined class for testing Property(). @@ -3118,10 +3134,12 @@ TEST(PropertyTest, CanExplainMatchResult) { AClass a; a.set_n(1); - EXPECT_EQ("whose given property is 1", Explain(m, a)); + EXPECT_EQ("whose given property is 1" + OfType("int"), Explain(m, a)); m = Property(&AClass::n, GreaterThan(0)); - EXPECT_EQ("whose given property is 1, which is 1 more than 0", Explain(m, a)); + EXPECT_EQ( + "whose given property is 1" + OfType("int") + ", which is 1 more than 0", + Explain(m, a)); } // Tests that Property() works when the argument is a pointer to const. @@ -3198,12 +3216,14 @@ TEST(PropertyForPointerTest, CanExplainMatchResult) { AClass a; a.set_n(1); EXPECT_EQ("", Explain(m, static_cast(NULL))); - EXPECT_EQ("which points to an object whose given property is 1", - Explain(m, &a)); + EXPECT_EQ( + "which points to an object whose given property is 1" + OfType("int"), + Explain(m, &a)); m = Property(&AClass::n, GreaterThan(0)); - EXPECT_EQ("which points to an object whose given property is 1, " - "which is 1 more than 0", Explain(m, &a)); + EXPECT_EQ("which points to an object whose given property is 1" + + OfType("int") + ", which is 1 more than 0", + Explain(m, &a)); } // Tests ResultOf. @@ -3234,12 +3254,12 @@ int IntFunction(int input) { return input == 42 ? 80 : 90; } TEST(ResultOfTest, CanExplainMatchResult) { Matcher matcher = ResultOf(&IntFunction, Ge(85)); - EXPECT_EQ("which is mapped by the given callable to 90", + EXPECT_EQ("which is mapped by the given callable to 90" + OfType("int"), Explain(matcher, 36)); matcher = ResultOf(&IntFunction, GreaterThan(85)); - EXPECT_EQ("which is mapped by the given callable to 90, " - "which is 5 more than 85", Explain(matcher, 36)); + EXPECT_EQ("which is mapped by the given callable to 90" + OfType("int") + + ", which is 5 more than 85", Explain(matcher, 36)); } // Tests that ResultOf(f, ...) compiles and works as expected when f(x) @@ -3253,9 +3273,9 @@ TEST(ResultOfTest, WorksForNonReferenceResults) { // Tests that ResultOf(f, ...) compiles and works as expected when f(x) // returns a reference to non-const. -double& DoubleFunction(double& input) { return input; } +double& DoubleFunction(double& input) { return input; } // NOLINT -Uncopyable& RefUncopyableFunction(Uncopyable& obj) { +Uncopyable& RefUncopyableFunction(Uncopyable& obj) { // NOLINT return obj; } @@ -3304,7 +3324,7 @@ TEST(ResultOfTest, WorksForCompatibleMatcherTypes) { // a NULL function pointer. TEST(ResultOfDeathTest, DiesOnNullFunctionPointers) { EXPECT_DEATH_IF_SUPPORTED( - ResultOf(static_cast(NULL), Eq(string("foo"))), + ResultOf(static_cast(NULL), Eq(string("foo"))), "NULL function pointer is passed into ResultOf\\(\\)\\."); } @@ -3682,6 +3702,31 @@ TEST(ContainerEqExtraTest, CopiesNativeArrayParameter) { EXPECT_THAT(a1, m); } +// Tests IsReadableTypeName(). + +TEST(IsReadableTypeNameTest, ReturnsTrueForShortNames) { + EXPECT_TRUE(IsReadableTypeName("int")); + EXPECT_TRUE(IsReadableTypeName("const unsigned char*")); + EXPECT_TRUE(IsReadableTypeName("MyMap")); + EXPECT_TRUE(IsReadableTypeName("void (*)(int, bool)")); +} + +TEST(IsReadableTypeNameTest, ReturnsTrueForLongNonTemplateNonFunctionNames) { + EXPECT_TRUE(IsReadableTypeName("my_long_namespace::MyClassName")); + EXPECT_TRUE(IsReadableTypeName("int [5][6][7][8][9][10][11]")); + EXPECT_TRUE(IsReadableTypeName("my_namespace::MyOuterClass::MyInnerClass")); +} + +TEST(IsReadableTypeNameTest, ReturnsFalseForLongTemplateNames) { + EXPECT_FALSE( + IsReadableTypeName("basic_string >")); + EXPECT_FALSE(IsReadableTypeName("std::vector >")); +} + +TEST(IsReadableTypeNameTest, ReturnsFalseForLongFunctionTypeNames) { + EXPECT_FALSE(IsReadableTypeName("void (&)(int, bool, char, float)")); +} + // Tests JoinAsTuple(). TEST(JoinAsTupleTest, JoinsEmptyTuple) { @@ -3772,7 +3817,7 @@ TEST(EachTest, ExplainsMatchResultCorrectly) { Matcher > m = Each(2); EXPECT_EQ("", Explain(m, a)); - Matcher n = Each(1); + Matcher n = Each(1); // NOLINT const int b[1] = { 1 }; EXPECT_EQ("", Explain(n, b)); -- cgit v1.2.3 From d43acacf5070eabfcecb2cd9a4072bf9036eadfc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 27 Sep 2010 22:10:44 +0000 Subject: Fixes issue 105. --- scripts/gmock-config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gmock-config.in b/scripts/gmock-config.in index 9ce17a25..2baefe94 100755 --- a/scripts/gmock-config.in +++ b/scripts/gmock-config.in @@ -216,7 +216,7 @@ if test "${this_bindir}" = "${this_bindir%${bindir}}"; then # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we # should work to remove it, and/or remove libtool altogether, replacing it # with direct references to the library and a link path. - gmock_libs="${build_dir}/lib/libgtest.la" + gmock_libs="${build_dir}/lib/libgmock.la" gmock_ldflags="" # We provide hooks to include from either the source or build dir, where the -- cgit v1.2.3 From 662d8a23502173db60e2d9d600c508e06d8ba173 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 29 Sep 2010 00:38:12 +0000 Subject: Factors out email address in Google Mock Doctor messages. --- scripts/gmock_doctor.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 1918cf6c..4a41abfc 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -38,6 +38,8 @@ import sys _VERSION = '1.0.3' +_EMAIL = 'googlemock@googlegroups.com' + _COMMON_GMOCK_SYMBOLS = [ # Matchers '_', @@ -563,16 +565,17 @@ def main(): diagnoses = Diagnose(msg) count = len(diagnoses) if not count: - print '\nGcc complained:' - print '8<------------------------------------------------------------' - print msg - print '------------------------------------------------------------>8' - print """ + print (""" +Your compiler complained: +8<------------------------------------------------------------ +%s +------------------------------------------------------------>8 + Uh-oh, I'm not smart enough to figure out what the problem is. :-( However... If you send your source code and the compiler's error messages to -googlemock@googlegroups.com, you can be helped and I can get smarter -- -win-win for us!""" +%s, you can be helped and I can get smarter -- +win-win for us!""" % (msg, _EMAIL)) else: print '------------------------------------------------------------' print 'Your code appears to have the following', @@ -586,10 +589,11 @@ win-win for us!""" if count > 1: print '\n#%s:' % (i,) print d - print """ + print (""" How did I do? If you think I'm wrong or unhelpful, please send your -source code and compiler's error messages to googlemock@googlegroups.com. -Then you can be helped and I can get smarter -- I promise I won't be upset!""" +source code and the compiler's error messages to %s. +Then you can be helped and I can get smarter -- I promise I won't be upset!""" % + _EMAIL) if __name__ == '__main__': -- cgit v1.2.3 From 5921483640fed07d8dcfff9cc34fe353fec55f26 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 Oct 2010 05:58:51 +0000 Subject: Adds SetArgPointee to replace SetArgumentPointee. --- include/gmock/gmock-actions.h | 9 +++ scripts/gmock_doctor.py | 1 + test/gmock-actions_test.cc | 120 +++++++++++++++++++++++++++++++++++ test/gmock-generated-actions_test.cc | 92 +++++++++++++-------------- test/gmock-more-actions_test.cc | 1 - test/gmock_link_test.h | 12 ++-- 6 files changed, 182 insertions(+), 53 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 6eb3f445..1d5509ce 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -1013,6 +1013,15 @@ inline internal::DoDefaultAction DoDefault() { // 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)); +} +// The following version is DEPRECATED. +template PolymorphicAction< internal::SetArgumentPointeeAction< N, T, internal::IsAProtocolMessage::value> > diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 4a41abfc..18c117fb 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -102,6 +102,7 @@ _COMMON_GMOCK_SYMBOLS = [ 'ReturnRef', 'SaveArg', 'SetArgReferee', + 'SetArgPointee', 'SetArgumentPointee', 'SetArrayArgument', 'SetErrnoAndReturn', diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index fd52ce21..7200fa1a 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -69,6 +69,7 @@ using testing::Return; using testing::ReturnNull; using testing::ReturnRef; using testing::ReturnRefOfCopy; +using testing::SetArgPointee; using testing::SetArgumentPointee; #if !GTEST_OS_WINDOWS_MOBILE @@ -694,6 +695,125 @@ TEST(DoDefaultTest, CannotBeUsedInOnCall) { }, "DoDefault() cannot be used in ON_CALL()"); } +// Tests that SetArgPointee(v) sets the variable pointed to by +// the N-th (0-based) argument to v. +TEST(SetArgPointeeTest, SetsTheNthPointee) { + typedef void MyFunction(bool, int*, char*); + Action a = SetArgPointee<1>(2); + + int n = 0; + char ch = '\0'; + a.Perform(make_tuple(true, &n, &ch)); + EXPECT_EQ(2, n); + EXPECT_EQ('\0', ch); + + a = SetArgPointee<2>('a'); + n = 0; + ch = '\0'; + a.Perform(make_tuple(true, &n, &ch)); + EXPECT_EQ(0, n); + EXPECT_EQ('a', ch); +} + +#if GTEST_HAS_PROTOBUF_ + +// Tests that SetArgPointee(proto_buffer) sets the v1 protobuf +// variable pointed to by the N-th (0-based) argument to proto_buffer. +TEST(SetArgPointeeTest, SetsTheNthPointeeOfProtoBufferType) { + TestMessage* const msg = new TestMessage; + msg->set_member("yes"); + TestMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgPointee<1>(*msg); + // SetArgPointee(proto_buffer) makes a copy of proto_buffer + // s.t. the action works even when the original proto_buffer has + // died. We ensure this behavior by deleting msg before using the + // action. + delete msg; + + TestMessage dest; + EXPECT_FALSE(orig_msg.Equals(dest)); + a.Perform(make_tuple(true, &dest)); + EXPECT_TRUE(orig_msg.Equals(dest)); +} + +// Tests that SetArgPointee(proto_buffer) sets the +// ::ProtocolMessage variable pointed to by the N-th (0-based) +// argument to proto_buffer. +TEST(SetArgPointeeTest, SetsTheNthPointeeOfProtoBufferBaseType) { + TestMessage* const msg = new TestMessage; + msg->set_member("yes"); + TestMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgPointee<1>(*msg); + // SetArgPointee(proto_buffer) makes a copy of proto_buffer + // s.t. the action works even when the original proto_buffer has + // died. We ensure this behavior by deleting msg before using the + // action. + delete msg; + + TestMessage dest; + ::ProtocolMessage* const dest_base = &dest; + EXPECT_FALSE(orig_msg.Equals(dest)); + a.Perform(make_tuple(true, dest_base)); + EXPECT_TRUE(orig_msg.Equals(dest)); +} + +// Tests that SetArgPointee(proto2_buffer) sets the v2 +// protobuf variable pointed to by the N-th (0-based) argument to +// proto2_buffer. +TEST(SetArgPointeeTest, SetsTheNthPointeeOfProto2BufferType) { + using testing::internal::FooMessage; + FooMessage* const msg = new FooMessage; + msg->set_int_field(2); + msg->set_string_field("hi"); + FooMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgPointee<1>(*msg); + // SetArgPointee(proto2_buffer) makes a copy of + // proto2_buffer s.t. the action works even when the original + // proto2_buffer has died. We ensure this behavior by deleting msg + // before using the action. + delete msg; + + FooMessage dest; + dest.set_int_field(0); + a.Perform(make_tuple(true, &dest)); + EXPECT_EQ(2, dest.int_field()); + EXPECT_EQ("hi", dest.string_field()); +} + +// Tests that SetArgPointee(proto2_buffer) sets the +// proto2::Message variable pointed to by the N-th (0-based) argument +// to proto2_buffer. +TEST(SetArgPointeeTest, SetsTheNthPointeeOfProto2BufferBaseType) { + using testing::internal::FooMessage; + FooMessage* const msg = new FooMessage; + msg->set_int_field(2); + msg->set_string_field("hi"); + FooMessage orig_msg; + orig_msg.CopyFrom(*msg); + + Action a = SetArgPointee<1>(*msg); + // SetArgPointee(proto2_buffer) makes a copy of + // proto2_buffer s.t. the action works even when the original + // proto2_buffer has died. We ensure this behavior by deleting msg + // before using the action. + delete msg; + + FooMessage dest; + dest.set_int_field(0); + ::proto2::Message* const dest_base = &dest; + a.Perform(make_tuple(true, dest_base)); + EXPECT_EQ(2, dest.int_field()); + EXPECT_EQ("hi", dest.string_field()); +} + +#endif // GTEST_HAS_PROTOBUF_ + // Tests that SetArgumentPointee(v) sets the variable pointed to by // the N-th (0-based) argument to v. TEST(SetArgumentPointeeTest, SetsTheNthPointee) { diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index f4d42a38..982be1b9 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -58,7 +58,7 @@ using testing::DoAll; using testing::Invoke; using testing::Return; using testing::ReturnNew; -using testing::SetArgumentPointee; +using testing::SetArgPointee; using testing::StaticAssertTypeEq; using testing::Unused; using testing::WithArgs; @@ -419,7 +419,7 @@ TEST(WithArgsTest, VoidAction) { // Tests DoAll(a1, a2). TEST(DoAllTest, TwoActions) { int n = 0; - Action a = DoAll(SetArgumentPointee<0>(1), // NOLINT + Action a = DoAll(SetArgPointee<0>(1), // NOLINT Return(2)); EXPECT_EQ(2, a.Perform(make_tuple(&n))); EXPECT_EQ(1, n); @@ -428,8 +428,8 @@ TEST(DoAllTest, TwoActions) { // Tests DoAll(a1, a2, a3). TEST(DoAllTest, ThreeActions) { int m = 0, n = 0; - Action a = DoAll(SetArgumentPointee<0>(1), // NOLINT - SetArgumentPointee<1>(2), + Action a = DoAll(SetArgPointee<0>(1), // NOLINT + SetArgPointee<1>(2), Return(3)); EXPECT_EQ(3, a.Perform(make_tuple(&m, &n))); EXPECT_EQ(1, m); @@ -441,9 +441,9 @@ TEST(DoAllTest, FourActions) { int m = 0, n = 0; char ch = '\0'; Action a = // NOLINT - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), Return(3)); EXPECT_EQ(3, a.Perform(make_tuple(&m, &n, &ch))); EXPECT_EQ(1, m); @@ -456,10 +456,10 @@ TEST(DoAllTest, FiveActions) { int m = 0, n = 0; char a = '\0', b = '\0'; Action action = // NOLINT - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), - SetArgumentPointee<3>('b'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), + SetArgPointee<3>('b'), Return(3)); EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b))); EXPECT_EQ(1, m); @@ -473,11 +473,11 @@ TEST(DoAllTest, SixActions) { int m = 0, n = 0; char a = '\0', b = '\0', c = '\0'; Action action = // NOLINT - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), - SetArgumentPointee<3>('b'), - SetArgumentPointee<4>('c'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), + SetArgPointee<3>('b'), + SetArgPointee<4>('c'), Return(3)); EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c))); EXPECT_EQ(1, m); @@ -492,12 +492,12 @@ TEST(DoAllTest, SevenActions) { int m = 0, n = 0; char a = '\0', b = '\0', c = '\0', d = '\0'; Action action = // NOLINT - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), - SetArgumentPointee<3>('b'), - SetArgumentPointee<4>('c'), - SetArgumentPointee<5>('d'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), + SetArgPointee<3>('b'), + SetArgPointee<4>('c'), + SetArgPointee<5>('d'), Return(3)); EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d))); EXPECT_EQ(1, m); @@ -514,13 +514,13 @@ TEST(DoAllTest, EightActions) { char a = '\0', b = '\0', c = '\0', d = '\0', e = '\0'; Action action = - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), - SetArgumentPointee<3>('b'), - SetArgumentPointee<4>('c'), - SetArgumentPointee<5>('d'), - SetArgumentPointee<6>('e'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), + SetArgPointee<3>('b'), + SetArgPointee<4>('c'), + SetArgPointee<5>('d'), + SetArgPointee<6>('e'), Return(3)); EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d, &e))); EXPECT_EQ(1, m); @@ -538,14 +538,14 @@ TEST(DoAllTest, NineActions) { char a = '\0', b = '\0', c = '\0', d = '\0', e = '\0', f = '\0'; Action action = - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), - SetArgumentPointee<3>('b'), - SetArgumentPointee<4>('c'), - SetArgumentPointee<5>('d'), - SetArgumentPointee<6>('e'), - SetArgumentPointee<7>('f'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), + SetArgPointee<3>('b'), + SetArgPointee<4>('c'), + SetArgPointee<5>('d'), + SetArgPointee<6>('e'), + SetArgPointee<7>('f'), Return(3)); EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d, &e, &f))); EXPECT_EQ(1, m); @@ -565,15 +565,15 @@ TEST(DoAllTest, TenActions) { char e = '\0', f = '\0', g = '\0'; Action action = - DoAll(SetArgumentPointee<0>(1), - SetArgumentPointee<1>(2), - SetArgumentPointee<2>('a'), - SetArgumentPointee<3>('b'), - SetArgumentPointee<4>('c'), - SetArgumentPointee<5>('d'), - SetArgumentPointee<6>('e'), - SetArgumentPointee<7>('f'), - SetArgumentPointee<8>('g'), + DoAll(SetArgPointee<0>(1), + SetArgPointee<1>(2), + SetArgPointee<2>('a'), + SetArgPointee<3>('b'), + SetArgPointee<4>('c'), + SetArgPointee<5>('d'), + SetArgPointee<6>('e'), + SetArgPointee<7>('f'), + SetArgPointee<8>('g'), Return(3)); EXPECT_EQ(3, action.Perform(make_tuple(&m, &n, &a, &b, &c, &d, &e, &f, &g))); EXPECT_EQ(1, m); diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index c09cccf4..64c4e081 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -60,7 +60,6 @@ using testing::ReturnArg; using testing::ReturnPointee; using testing::SaveArg; using testing::SetArgReferee; -using testing::SetArgumentPointee; using testing::StaticAssertTypeEq; using testing::Unused; using testing::WithArg; diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index 00b2110d..499cc186 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -44,7 +44,7 @@ // ReturnNull // ReturnRef // Assign -// SetArgumentPointee +// SetArgPointee // SetArrayArgument // SetErrnoAndReturn // Invoke(function) @@ -164,7 +164,7 @@ using testing::ResultOf; using testing::Return; using testing::ReturnNull; using testing::ReturnRef; -using testing::SetArgumentPointee; +using testing::SetArgPointee; using testing::SetArrayArgument; using testing::StartsWith; using testing::StrCaseEq; @@ -281,12 +281,12 @@ TEST(LinkTest, TestAssign) { mock.VoidFromString(NULL); } -// Tests the linkage of the SetArgumentPointee action. -TEST(LinkTest, TestSetArgumentPointee) { +// Tests the linkage of the SetArgPointee action. +TEST(LinkTest, TestSetArgPointee) { Mock mock; char ch = 'x'; - EXPECT_CALL(mock, VoidFromString(_)).WillOnce(SetArgumentPointee<0>('y')); + EXPECT_CALL(mock, VoidFromString(_)).WillOnce(SetArgPointee<0>('y')); mock.VoidFromString(&ch); } @@ -381,7 +381,7 @@ TEST(LinkTest, TestDoAll) { char ch = 'x'; EXPECT_CALL(mock, VoidFromString(_)) - .WillOnce(DoAll(SetArgumentPointee<0>('y'), Return())); + .WillOnce(DoAll(SetArgPointee<0>('y'), Return())); mock.VoidFromString(&ch); } -- cgit v1.2.3 From 4b16e8ed2785136d863fb52961539c27c9716497 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 Oct 2010 06:11:56 +0000 Subject: Enables gmock_gen to handle return types that are templates (based on Pride Haveit's patch); also fixes deprecation warnings when using gmock_gen with python 2.6 (by Aaron Jacobs). --- scripts/generator/cpp/gmock_class.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index 3ad0bcdd..645c295b 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -31,12 +31,18 @@ __author__ = 'nnorwitz@google.com (Neal Norwitz)' import os import re -import sets import sys from cpp import ast from cpp import utils +# Preserve compatibility with Python 2.3. +try: + _dummy = set +except NameError: + import sets + set = sets.Set + _VERSION = (1, 0, 1) # The version of this script. # How many spaces to indent. Can set me with the INDENT environment variable. _INDENT = 2 @@ -45,6 +51,7 @@ _INDENT = 2 def _GenerateMethods(output_lines, source, class_node): function_type = ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR + indent = ' ' * _INDENT for node in class_node.body: # We only care about virtual functions. @@ -62,11 +69,20 @@ def _GenerateMethods(output_lines, source, class_node): if node.return_type.modifiers: modifiers = ' '.join(node.return_type.modifiers) + ' ' return_type = modifiers + node.return_type.name + template_args = [arg.name for arg in node.return_type.templated_types] + if template_args: + return_type += '<' + ', '.join(template_args) + '>' + if len(template_args) > 1: + for line in [ + '// The following line won\'t really compile, as the return', + '// type has multiple template arguments. To fix it, use a', + '// typedef for the return type.']: + output_lines.append(indent + line) if node.return_type.pointer: return_type += '*' if node.return_type.reference: return_type += '&' - prefix = 'MOCK_%sMETHOD%d' % (const, len(node.parameters)) + mock_method_macro = 'MOCK_%sMETHOD%d' % (const, len(node.parameters)) args = '' if node.parameters: # Get the full text of the parameters from the start @@ -81,15 +97,13 @@ def _GenerateMethods(output_lines, source, class_node): # intervening whitespace, e.g.: int\nBar args = re.sub(' +', ' ', args_strings.replace('\n', ' ')) - # Create the prototype. - indent = ' ' * _INDENT - line = ('%s%s(%s,\n%s%s(%s));' % - (indent, prefix, node.name, indent*3, return_type, args)) - output_lines.append(line) + # Create the mock method definition. + output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name), + '%s%s(%s));' % (indent*3, return_type, args)]) def _GenerateMocks(filename, source, ast_list, desired_class_names): - processed_class_names = sets.Set() + processed_class_names = set() lines = [] for node in ast_list: if (isinstance(node, ast.Class) and node.body and @@ -156,7 +170,7 @@ def main(argv=sys.argv): filename = argv[1] desired_class_names = None # None means all classes in the source file. if len(argv) >= 3: - desired_class_names = sets.Set(argv[2:]) + desired_class_names = set(argv[2:]) source = utils.ReadFile(filename) if source is None: return 1 -- cgit v1.2.3 From d8e15d9c4a05553daa13dbfeaa1ed4bca899d079 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 Oct 2010 19:21:38 +0000 Subject: Adds more tests for the gmock generator. --- scripts/generator/cpp/gmock_class_test.py | 71 ++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/scripts/generator/cpp/gmock_class_test.py b/scripts/generator/cpp/gmock_class_test.py index ae00800f..607d5cf7 100755 --- a/scripts/generator/cpp/gmock_class_test.py +++ b/scripts/generator/cpp/gmock_class_test.py @@ -34,22 +34,47 @@ from cpp import gmock_class class TestCase(unittest.TestCase): """Helper class that adds assert methods.""" + def StripLeadingWhitespace(self, lines): + """Strip leading whitespace in each line in 'lines'.""" + return '\n'.join([s.lstrip() for s in lines.split('\n')]) + def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines): """Specialized assert that ignores the indent level.""" - stripped_lines = '\n'.join([s.lstrip() for s in lines.split('\n')]) - self.assertEqual(expected_lines, stripped_lines) + self.assertEqual(expected_lines, self.StripLeadingWhitespace(lines)) class GenerateMethodsTest(TestCase): def GenerateMethodSource(self, cpp_source): - """Helper method to convert C++ source to gMock output source lines.""" + """Convert C++ source to Google Mock output source lines.""" method_source_lines = [] # is a pseudo-filename, it is not read or written. builder = ast.BuilderFromSource(cpp_source, '') ast_list = list(builder.Generate()) gmock_class._GenerateMethods(method_source_lines, cpp_source, ast_list[0]) - return ''.join(method_source_lines) + return '\n'.join(method_source_lines) + + def testSimpleMethod(self): + source = """ +class Foo { + public: + virtual int Bar(); +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) + + def testSimpleConstMethod(self): + source = """ +class Foo { + public: + virtual void Bar(bool flag) const; +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));', + self.GenerateMethodSource(source)) def testStrangeNewlineInParameter(self): source = """ @@ -90,11 +115,47 @@ class Foo { 'MOCK_METHOD2(Bar,\nconst string&(int /* keeper */, int b));', self.GenerateMethodSource(source)) + def testArgsOfTemplateTypes(self): + source = """ +class Foo { + public: + virtual int Bar(const vector& v, map* output); +};""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\n' + 'int(const vector& v, map* output));', + self.GenerateMethodSource(source)) + + def testReturnTypeWithOneTemplateArg(self): + source = """ +class Foo { + public: + virtual vector* Bar(int n); +};""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD1(Bar,\nvector*(int n));', + self.GenerateMethodSource(source)) + + def testReturnTypeWithManyTemplateArgs(self): + source = """ +class Foo { + public: + virtual map Bar(); +};""" + # Comparing the comment text is brittle - we'll think of something + # better in case this gets annoying, but for now let's keep it simple. + self.assertEqualIgnoreLeadingWhitespace( + '// The following line won\'t really compile, as the return\n' + '// type has multiple template arguments. To fix it, use a\n' + '// typedef for the return type.\n' + 'MOCK_METHOD0(Bar,\nmap());', + self.GenerateMethodSource(source)) + class GenerateMocksTest(TestCase): def GenerateMocks(self, cpp_source): - """Helper method to convert C++ source to complete gMock output source.""" + """Convert C++ source to complete Google Mock output source.""" # is a pseudo-filename, it is not read or written. filename = '' builder = ast.BuilderFromSource(cpp_source, filename) -- cgit v1.2.3 From 7dfbea4976d41421b82c7988017cf1c695104236 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 5 Oct 2010 19:24:04 +0000 Subject: Fixes an include order problem in CMakeLists.txt; pulls in gtest r489. --- CMakeLists.txt | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 186a710d..061c2fc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,5 @@ ######################################################################## -# Experimental CMake build script for Google Mock. -# -# Consider this a prototype. It will change drastically. For now, -# this is only for people on the cutting edge. +# 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'. @@ -12,7 +9,7 @@ # make it prominent in the GUI. option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) -# Forses BUILD_SHARED_LIBS to OFF as Google Mock currently does not support +# Forces BUILD_SHARED_LIBS to OFF as Google Mock currently does not support # working in a DLL. # TODO(vladl@google.com): Implement building gMock as a DLL. set(BUILD_SHARED_LIBS OFF) @@ -26,6 +23,7 @@ else() set(gtest_dir ../gtest) 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) @@ -51,19 +49,17 @@ if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() -# Defines functions and variables used by Google Mock. -include("${gtest_dir}/cmake/internal_utils.cmake") - -# Google Test also calls this function from add_subdirectory, -# although its changes will not affect things at the current scope. -fix_default_settings() # Defined in internal_utils.cmake. - # 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). +# 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}" -- cgit v1.2.3 From 2321b2a6757328bbf30b69af434c28dac3060b83 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 Oct 2010 06:51:27 +0000 Subject: Adds action SaveArgPointee. --- include/gmock/gmock-more-actions.h | 10 ++++++++++ test/gmock-more-actions_test.cc | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index e418505a..a547a648 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -36,6 +36,8 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ +#include + #include "gmock/gmock-generated-actions.h" namespace testing { @@ -153,6 +155,14 @@ ACTION_TEMPLATE(SaveArg, *pointer = ::std::tr1::get(args); } +// Action SaveArgPointee(pointer) saves the value pointed to +// by the k-th (0-based) argument of the mock function to *pointer. +ACTION_TEMPLATE(SaveArgPointee, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(pointer)) { + *pointer = *::std::tr1::get(args); +} + // Action SetArgReferee(value) assigns 'value' to the variable // referenced by the k-th (0-based) argument of the mock function. ACTION_TEMPLATE(SetArgReferee, diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index 64c4e081..43ff55d8 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -40,6 +40,7 @@ #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "gtest/internal/gtest-linked_ptr.h" namespace testing { namespace gmock_more_actions_test { @@ -59,11 +60,13 @@ using testing::Return; using testing::ReturnArg; using testing::ReturnPointee; using testing::SaveArg; +using testing::SaveArgPointee; using testing::SetArgReferee; using testing::StaticAssertTypeEq; using testing::Unused; using testing::WithArg; using testing::WithoutArgs; +using testing::internal::linked_ptr; // For suppressing compiler warnings on conversion possibly losing precision. inline short Short(short n) { return n; } // NOLINT @@ -506,6 +509,30 @@ TEST(SaveArgActionTest, WorksForCompatibleType) { EXPECT_EQ('a', result); } +TEST(SaveArgPointeeActionTest, WorksForSameType) { + int result = 0; + const int value = 5; + const Action a1 = SaveArgPointee<0>(&result); + a1.Perform(make_tuple(&value)); + EXPECT_EQ(5, result); +} + +TEST(SaveArgPointeeActionTest, WorksForCompatibleType) { + int result = 0; + char value = 'a'; + const Action a1 = SaveArgPointee<1>(&result); + a1.Perform(make_tuple(true, &value)); + EXPECT_EQ('a', result); +} + +TEST(SaveArgPointeeActionTest, WorksForLinkedPtr) { + int result = 0; + linked_ptr value(new int(5)); + const Action)> a1 = SaveArgPointee<0>(&result); + a1.Perform(make_tuple(value)); + EXPECT_EQ(5, result); +} + TEST(SetArgRefereeActionTest, WorksForSameType) { int value = 0; const Action a1 = SetArgReferee<0>(1); -- cgit v1.2.3 From 88032d8e0f6d4bc63b97aeeab84fdc44aeab1c89 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 17 Nov 2010 23:29:21 +0000 Subject: Adds comment clarifying the use of default-constructed matchers. --- include/gmock/gmock-matchers.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 627f3ff0..86c3db73 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -250,8 +250,9 @@ class MatcherBase { template class Matcher : public internal::MatcherBase { public: - // Constructs a null matcher. Needed for storing Matcher objects in - // STL containers. + // 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. Matcher() {} // Constructs a matcher from its implementation. -- cgit v1.2.3 From a684b5a5269e3f9c53ef842bf9b9658370418a0c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 2 Dec 2010 23:30:50 +0000 Subject: Enables SetArgPointee<>() to accept a string literal; removes a self-assignment warning; teaches gmock doctor to diagnose TTB with Clang; picks up gtest r525. --- include/gmock/gmock-actions.h | 8 ++++++++ scripts/gmock_doctor.py | 18 +++++++++++++++++- test/gmock-actions_test.cc | 37 +++++++++++++++++++++++++++++++++++++ test/gmock_test.cc | 2 +- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 1d5509ce..215af4f9 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -1020,6 +1020,14 @@ SetArgPointee(const T& x) { return MakePolymorphicAction(internal::SetArgumentPointeeAction< N, T, internal::IsAProtocolMessage::value>(x)); } +// This overload allows SetArgPointee() to accept a string literal. +template +PolymorphicAction< + internal::SetArgumentPointeeAction > +SetArgPointee(const char* p) { + return MakePolymorphicAction(internal::SetArgumentPointeeAction< + N, const char*, false>(p)); +} // The following version is DEPRECATED. template PolymorphicAction< diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 18c117fb..15e2433c 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -459,6 +459,20 @@ def _TypeInTemplatedBaseDiagnoser(msg): r'error: \'(?P.+)\' was not declared in this scope\n' r'.*error: template argument 1 is invalid\n' r'.*error: \'.+\' was not declared in this scope') + clang_regex_type_of_retval_or_sole_param = ( + _CLANG_FILE_LINE_RE + + r'error: use of undeclared identifier \'(?P.*)\'\n' + r'(.*\n)*?' + r'(?P=file):(?P=line):(?P=column): error: ' + r'non-friend class member \'Result\' cannot have a qualified name' + ) + clang_regex_type_of_a_param = ( + _CLANG_FILE_LINE_RE + + r'error: C\+\+ requires a type specifier for all declarations\n' + r'(.*\n)*?' + r'(?P=file):(?P=line):(?P=column): error: ' + r'C\+\+ requires a type specifier for all declarations' + ) diagnosis = """ In a mock class template, types or typedefs defined in the base class @@ -473,7 +487,9 @@ need to make it visible. One way to do it is: [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}), (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}), (gcc_regex_type_of_sole_param, diagnosis), - (gcc_regex_type_of_a_param, diagnosis)], + (gcc_regex_type_of_a_param, diagnosis), + (clang_regex_type_of_retval_or_sole_param, diagnosis), + (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})], msg) diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 7200fa1a..e12402b9 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -715,6 +715,43 @@ TEST(SetArgPointeeTest, SetsTheNthPointee) { EXPECT_EQ('a', ch); } +// Tests that SetArgPointee() accepts a string literal. +TEST(SetArgPointeeTest, AcceptsStringLiteral) { + typedef void MyFunction(bool, std::string*, const char**); + Action a = SetArgPointee<1>("hi"); + std::string str; + const char* ptr = NULL; + a.Perform(make_tuple(true, &str, &ptr)); + EXPECT_EQ("hi", str); + EXPECT_TRUE(ptr == NULL); + + a = SetArgPointee<2>("world"); + str = ""; + a.Perform(make_tuple(true, &str, &ptr)); + EXPECT_EQ("", str); + EXPECT_STREQ("world", ptr); +} + +// Tests that SetArgPointee() accepts a char pointer. +TEST(SetArgPointeeTest, AcceptsCharPointer) { + typedef void MyFunction(bool, std::string*, const char**); + const char* const hi = "hi"; + Action a = SetArgPointee<1>(hi); + std::string str; + const char* ptr = NULL; + a.Perform(make_tuple(true, &str, &ptr)); + EXPECT_EQ("hi", str); + EXPECT_TRUE(ptr == NULL); + + char world_array[] = "world"; + char* const world = world_array; + a = SetArgPointee<2>(world); + str = ""; + a.Perform(make_tuple(true, &str, &ptr)); + EXPECT_EQ("", str); + EXPECT_EQ(world, ptr); +} + #if GTEST_HAS_PROTOBUF_ // Tests that SetArgPointee(proto_buffer) sets the v1 protobuf diff --git a/test/gmock_test.cc b/test/gmock_test.cc index ba137dd3..0b891137 100644 --- a/test/gmock_test.cc +++ b/test/gmock_test.cc @@ -251,5 +251,5 @@ TEST(WideInitGoogleMockTest, CallsInitGoogleTest) { TEST(FlagTest, IsAccessibleInCode) { bool dummy = testing::GMOCK_FLAG(catch_leaked_mocks) && testing::GMOCK_FLAG(verbose) == ""; - dummy = dummy; // Avoids the "unused local variable" warning. + (void)dummy; // Avoids the "unused local variable" warning. } -- cgit v1.2.3 From 5b61ce3ee5b15e6356487dd97236bf663a96a391 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 1 Feb 2011 00:00:03 +0000 Subject: Picks up gtest r536; renames implicit_cast and down_cast to reduce the chance of clash (by Roman Perepelitsa); enables gmock_gen.py to handle storage specifiers (by Steve Fox). --- include/gmock/gmock-actions.h | 4 +- include/gmock/gmock-generated-nice-strict.h | 48 ++++++++++++------------ include/gmock/gmock-generated-nice-strict.h.pump | 16 ++++---- include/gmock/gmock-spec-builders.h | 2 +- scripts/generator/cpp/ast.py | 8 +++- scripts/generator/cpp/gmock_class_test.py | 16 ++++++++ scripts/gmock_doctor.py | 8 ++-- 7 files changed, 62 insertions(+), 40 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 215af4f9..f88ac80d 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -494,11 +494,11 @@ class ReturnAction { // 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. implicit_cast forces the compiler to convert R to + // 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(R value) - : value_(::testing::internal::implicit_cast(value)) {} + : value_(::testing::internal::ImplicitCast_(value)) {} virtual Result Perform(const ArgumentTuple&) { return value_; } diff --git a/include/gmock/gmock-generated-nice-strict.h b/include/gmock/gmock-generated-nice-strict.h index 4fb69fdc..6099e81e 100644 --- a/include/gmock/gmock-generated-nice-strict.h +++ b/include/gmock/gmock-generated-nice-strict.h @@ -71,7 +71,7 @@ class NiceMock : public MockClass { // we have to avoid a possible clash with members of MockClass. NiceMock() { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } // C++ doesn't (yet) allow inheritance of constructors, so we have @@ -79,32 +79,32 @@ class NiceMock : public MockClass { template explicit NiceMock(const A1& a1) : MockClass(a1) { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + 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::implicit_cast(this)); + 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::implicit_cast(this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } virtual ~NiceMock() { ::testing::Mock::UnregisterCallReaction( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } private: @@ -167,38 +167,38 @@ class StrictMock : public MockClass { // we have to avoid a possible clash with members of MockClass. StrictMock() { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } template explicit StrictMock(const A1& a1) : MockClass(a1) { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + 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::implicit_cast(this)); + 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::implicit_cast(this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } template (this)); + internal::ImplicitCast_(this)); } virtual ~StrictMock() { ::testing::Mock::UnregisterCallReaction( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } private: diff --git a/include/gmock/gmock-generated-nice-strict.h.pump b/include/gmock/gmock-generated-nice-strict.h.pump index 784635bd..b7964db3 100644 --- a/include/gmock/gmock-generated-nice-strict.h.pump +++ b/include/gmock/gmock-generated-nice-strict.h.pump @@ -74,7 +74,7 @@ class NiceMock : public MockClass { // we have to avoid a possible clash with members of MockClass. NiceMock() { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } // C++ doesn't (yet) allow inheritance of constructors, so we have @@ -82,7 +82,7 @@ class NiceMock : public MockClass { template explicit NiceMock(const A1& a1) : MockClass(a1) { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } $range i 2..n @@ -91,14 +91,14 @@ $range j 1..i template <$for j, [[typename A$j]]> NiceMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { ::testing::Mock::AllowUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } ]] virtual ~NiceMock() { ::testing::Mock::UnregisterCallReaction( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } private: @@ -112,13 +112,13 @@ class StrictMock : public MockClass { // we have to avoid a possible clash with members of MockClass. StrictMock() { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } template explicit StrictMock(const A1& a1) : MockClass(a1) { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } $for i [[ @@ -126,14 +126,14 @@ $range j 1..i template <$for j, [[typename A$j]]> StrictMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { ::testing::Mock::FailUninterestingCalls( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } ]] virtual ~StrictMock() { ::testing::Mock::UnregisterCallReaction( - internal::implicit_cast(this)); + internal::ImplicitCast_(this)); } private: diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 1676056c..df2aef16 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1388,7 +1388,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { mock_obj_ = mock_obj; } Mock::Register(mock_obj, this); - return *::testing::internal::down_cast*>(this); + return *::testing::internal::DownCast_*>(this); } // The following two functions are from UntypedFunctionMockerBase. diff --git a/scripts/generator/cpp/ast.py b/scripts/generator/cpp/ast.py index 47dc9a07..6f61f877 100755 --- a/scripts/generator/cpp/ast.py +++ b/scripts/generator/cpp/ast.py @@ -1483,7 +1483,13 @@ class AstBuilder(object): assert class_token.token_type == tokenize.SYNTAX, class_token token = class_token else: - self._AddBackToken(class_token) + # Skip any macro (e.g. storage class specifiers) after the + # 'class' keyword. + next_token = self._GetNextToken() + if next_token.token_type == tokenize.NAME: + self._AddBackToken(next_token) + else: + self._AddBackTokens([class_token, next_token]) name_tokens, token = self.GetName() class_name = ''.join([t.name for t in name_tokens]) bases = None diff --git a/scripts/generator/cpp/gmock_class_test.py b/scripts/generator/cpp/gmock_class_test.py index 607d5cf7..494720cd 100755 --- a/scripts/generator/cpp/gmock_class_test.py +++ b/scripts/generator/cpp/gmock_class_test.py @@ -193,6 +193,22 @@ void()); self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) + def testClassWithStorageSpecifierMacro(self): + source = """ +class STORAGE_SPECIFIER Test { + public: + virtual void Foo(); +}; +""" + expected = """\ +class MockTest : public Test { +public: +MOCK_METHOD0(Foo, +void()); +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) if __name__ == '__main__': unittest.main() diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 15e2433c..f7932b5e 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -169,7 +169,7 @@ def _NeedToReturnReferenceDiagnoser(msg): gcc_regex = (r'In member function \'testing::internal::ReturnAction.*\n' + _GCC_FILE_LINE_RE + r'instantiated from here\n' r'.*gmock-actions\.h.*error: creating array with negative size') - clang_regex = (r'error: array size is negative\r?\n' + clang_regex = (r'error:.*array.*negative.*\r?\n' r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation of function template specialization ' @@ -414,10 +414,10 @@ def _NeedToUseReturnNullDiagnoser(msg): gcc_regex = ('instantiated from \'testing::internal::ReturnAction' '::operator testing::Action\(\) const.*\n' + _GCC_FILE_LINE_RE + r'instantiated from here\n' - r'.*error: no matching function for call to \'implicit_cast\(' + r'.*error: no matching function for call to \'ImplicitCast_\(' r'long int&\)') clang_regex = (r'\bgmock-actions.h:.* error: no matching function for ' - r'call to \'implicit_cast\'\r?\n' + r'call to \'ImplicitCast_\'\r?\n' r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' r'of function template specialization ' @@ -501,7 +501,7 @@ def _WrongMockMethodMacroDiagnoser(msg): r'.*\n' r'.*candidates are.*FunctionMocker<[^>]+A(?P\d+)\)>') clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + - r'error: array size is negative\r?\n' + r'error:.*array.*negative.*r?\n' r'(.*\n)*?' r'(?P=file):(?P=line):(?P=column): error: too few arguments ' r'to function call, expected (?P\d+), ' -- cgit v1.2.3 From e5121b5a828c13588d7aa4fc328b348e92ee4abb Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 11 Feb 2011 23:50:38 +0000 Subject: Improves cross-platform compatibility of gmock output. This fixes issue 135. --- include/gmock/gmock-spec-builders.h | 4 ++-- test/gmock-spec-builders_test.cc | 48 +++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index df2aef16..4f0b0725 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -575,7 +575,7 @@ class ExpectationBase { // Describes the source file location of this expectation. void DescribeLocationTo(::std::ostream* os) const { - *os << file() << ":" << line() << ": "; + *os << FormatFileLocation(file(), line()) << " "; } // Describes how many times a function call matching this @@ -1527,7 +1527,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { "returning default value.\n"); } else { *os << "taking default action specified at:\n" - << spec->file() << ":" << spec->line() << ":\n"; + << FormatFileLocation(spec->file(), spec->line()) << "\n"; } } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 6c844e22..737bcfff 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -43,6 +43,7 @@ #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" #include "gtest/gtest-spi.h" +#include "gtest/internal/gtest-port.h" namespace testing { namespace internal { @@ -88,6 +89,7 @@ using testing::Ne; using testing::Return; using testing::Sequence; using testing::internal::ExpectationTester; +using testing::internal::FormatFileLocation; using testing::internal::g_gmock_mutex; using testing::internal::kErrorVerbosity; using testing::internal::kInfoVerbosity; @@ -797,6 +799,19 @@ TEST(ExpectCallTest, NthMatchTakesNthAction) { EXPECT_EQ(3, b.DoB()); } +// Tests that the WillRepeatedly() action is taken when the WillOnce(...) +// list is exhausted. +TEST(ExpectCallTest, TakesRepeatedActionWhenWillListIsExhausted) { + MockB b; + EXPECT_CALL(b, DoB()) + .WillOnce(Return(1)) + .WillRepeatedly(Return(2)); + + EXPECT_EQ(1, b.DoB()); + EXPECT_EQ(2, b.DoB()); + EXPECT_EQ(2, b.DoB()); +} + #if GTEST_HAS_STREAM_REDIRECTION // Tests that the default action is taken when the WillOnce(...) list is @@ -832,21 +847,34 @@ TEST(ExpectCallTest, TakesDefaultActionWhenWillListIsExhausted) { " - returning default value.")); } -#endif // GTEST_HAS_STREAM_REDIRECTION - -// Tests that the WillRepeatedly() action is taken when the WillOnce(...) -// list is exhausted. -TEST(ExpectCallTest, TakesRepeatedActionWhenWillListIsExhausted) { +TEST(FunctionMockerTest, ReportsExpectCallLocationForExhausedActions) { MockB b; - EXPECT_CALL(b, DoB()) - .WillOnce(Return(1)) - .WillRepeatedly(Return(2)); + std::string expect_call_location = FormatFileLocation(__FILE__, __LINE__ + 1); + EXPECT_CALL(b, DoB()).Times(AnyNumber()).WillOnce(Return(1)); EXPECT_EQ(1, b.DoB()); - EXPECT_EQ(2, b.DoB()); - EXPECT_EQ(2, b.DoB()); + + CaptureStdout(); + EXPECT_EQ(0, b.DoB()); + const String output = GetCapturedStdout(); + // The warning message should contain the call location. + EXPECT_PRED_FORMAT2(IsSubstring, expect_call_location, output); } +TEST(FunctionMockerTest, ReportsDefaultActionLocationOfUninterestingCalls) { + std::string on_call_location; + CaptureStdout(); + { + MockB b; + on_call_location = FormatFileLocation(__FILE__, __LINE__ + 1); + ON_CALL(b, DoB(_)).WillByDefault(Return(0)); + b.DoB(0); + } + EXPECT_PRED_FORMAT2(IsSubstring, on_call_location, GetCapturedStdout()); +} + +#endif // GTEST_HAS_STREAM_REDIRECTION + // Tests that an uninteresting call performs the default action. TEST(UninterestingCallTest, DoesDefaultAction) { // When there is an ON_CALL() statement, the action specified by it -- cgit v1.2.3 From b3e904227f81fc6d2ea577dadbc3e510a989bbd2 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Sat, 12 Feb 2011 01:56:45 +0000 Subject: Adds project files for MSVC 2010 (by Fredrik Roubert). --- Makefile.am | 20 ++-- README | 14 ++- msvc/2005/gmock.sln | 32 ++++++ msvc/2005/gmock.vcproj | 191 ++++++++++++++++++++++++++++++++ msvc/2005/gmock_config.vsprops | 15 +++ msvc/2005/gmock_main.vcproj | 187 ++++++++++++++++++++++++++++++++ msvc/2005/gmock_test.vcproj | 201 ++++++++++++++++++++++++++++++++++ msvc/2010/gmock.sln | 32 ++++++ msvc/2010/gmock.vcxproj | 82 ++++++++++++++ msvc/2010/gmock_config.props | 19 ++++ msvc/2010/gmock_main.vcxproj | 88 +++++++++++++++ msvc/2010/gmock_test.vcxproj | 101 +++++++++++++++++ msvc/gmock-spec-builders_test.vcproj | 205 ----------------------------------- msvc/gmock.sln | 44 -------- msvc/gmock.vcproj | 191 -------------------------------- msvc/gmock_config.vsprops | 15 --- msvc/gmock_link_test.vcproj | 203 ---------------------------------- msvc/gmock_main.vcproj | 187 -------------------------------- msvc/gmock_test.vcproj | 201 ---------------------------------- 19 files changed, 969 insertions(+), 1059 deletions(-) create mode 100644 msvc/2005/gmock.sln create mode 100644 msvc/2005/gmock.vcproj create mode 100644 msvc/2005/gmock_config.vsprops create mode 100644 msvc/2005/gmock_main.vcproj create mode 100644 msvc/2005/gmock_test.vcproj create mode 100644 msvc/2010/gmock.sln create mode 100644 msvc/2010/gmock.vcxproj create mode 100644 msvc/2010/gmock_config.props create mode 100644 msvc/2010/gmock_main.vcxproj create mode 100644 msvc/2010/gmock_test.vcxproj delete mode 100755 msvc/gmock-spec-builders_test.vcproj delete mode 100644 msvc/gmock.sln delete mode 100644 msvc/gmock.vcproj delete mode 100644 msvc/gmock_config.vsprops delete mode 100644 msvc/gmock_link_test.vcproj delete mode 100644 msvc/gmock_main.vcproj delete mode 100644 msvc/gmock_test.vcproj diff --git a/Makefile.am b/Makefile.am index 2d967dcc..e02c07e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -155,13 +155,19 @@ EXTRA_DIST += \ # Microsoft Visual Studio 2005 projects. EXTRA_DIST += \ - msvc/gmock-spec-builders_test.vcproj \ - msvc/gmock.sln \ - msvc/gmock.vcproj \ - msvc/gmock_config.vsprops \ - msvc/gmock_link_test.vcproj \ - msvc/gmock_main.vcproj \ - msvc/gmock_test.vcproj + 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 # gmock_test.cc does not really depend on files generated by the # fused-gmock-internal rule. However, gmock_test.o does, and it is diff --git a/README b/README index 8e4150aa..aa3283d7 100644 --- a/README +++ b/README @@ -208,16 +208,18 @@ it. ### Windows ### -The msvc/ directory contains VC++ 2005 projects for building Google -Mock and selected tests. +The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010 +directory contains VC++ 2010 projects for building Google Mock and +selected tests. -Open msvc/gmock.sln and build the library and tests. 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: +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 and select it. + * Navigate to gmock_config.vsprops or gmock_config.props and select it. * In Project Properties | Configuration Properties | General | Additional Include Directories, type /include. diff --git a/msvc/2005/gmock.sln b/msvc/2005/gmock.sln new file mode 100644 index 00000000..b752f876 --- /dev/null +++ b/msvc/2005/gmock.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock", "gmock.vcproj", "{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vcproj", "{F10D22F8-AC7B-4213-8720-608E7D878CD2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.Build.0 = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.ActiveCfg = Release|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.Build.0 = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.Build.0 = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.ActiveCfg = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.Build.0 = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/msvc/2005/gmock.vcproj b/msvc/2005/gmock.vcproj new file mode 100644 index 00000000..4bbfe989 --- /dev/null +++ b/msvc/2005/gmock.vcproj @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/2005/gmock_config.vsprops b/msvc/2005/gmock_config.vsprops new file mode 100644 index 00000000..8b65cfb6 --- /dev/null +++ b/msvc/2005/gmock_config.vsprops @@ -0,0 +1,15 @@ + + + + + diff --git a/msvc/2005/gmock_main.vcproj b/msvc/2005/gmock_main.vcproj new file mode 100644 index 00000000..01505a93 --- /dev/null +++ b/msvc/2005/gmock_main.vcproj @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/2005/gmock_test.vcproj b/msvc/2005/gmock_test.vcproj new file mode 100644 index 00000000..d1e01e71 --- /dev/null +++ b/msvc/2005/gmock_test.vcproj @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/2010/gmock.sln b/msvc/2010/gmock.sln new file mode 100644 index 00000000..d9496569 --- /dev/null +++ b/msvc/2010/gmock.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock", "gmock.vcxproj", "{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vcxproj", "{F10D22F8-AC7B-4213-8720-608E7D878CD2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcxproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.Build.0 = Debug|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.ActiveCfg = Release|Win32 + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.Build.0 = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.Build.0 = Debug|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.ActiveCfg = Release|Win32 + {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.Build.0 = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 + {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/msvc/2010/gmock.vcxproj b/msvc/2010/gmock.vcxproj new file mode 100644 index 00000000..21a85ef6 --- /dev/null +++ b/msvc/2010/gmock.vcxproj @@ -0,0 +1,82 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {34681F0D-CE45-415D-B5F2-5C662DFE3BD5} + gmock + Win32Proj + + + + StaticLibrary + Unicode + true + + + StaticLibrary + Unicode + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)$(Configuration)\ + $(OutDir)$(ProjectName)\ + + + + Disabled + ..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + + + ..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + + + + $(GTestDir);%(AdditionalIncludeDirectories) + $(GTestDir);%(AdditionalIncludeDirectories) + + + + + + diff --git a/msvc/2010/gmock_config.props b/msvc/2010/gmock_config.props new file mode 100644 index 00000000..bd497f1d --- /dev/null +++ b/msvc/2010/gmock_config.props @@ -0,0 +1,19 @@ + + + + ../../gtest + + + <_ProjectFileVersion>10.0.30319.1 + + + + $(GTestDir)/include;%(AdditionalIncludeDirectories) + + + + + $(GTestDir) + + + diff --git a/msvc/2010/gmock_main.vcxproj b/msvc/2010/gmock_main.vcxproj new file mode 100644 index 00000000..27fecd5f --- /dev/null +++ b/msvc/2010/gmock_main.vcxproj @@ -0,0 +1,88 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E4EF614B-30DF-4954-8C53-580A0BF6B589} + gmock_main + Win32Proj + + + + StaticLibrary + Unicode + true + + + StaticLibrary + Unicode + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)$(Configuration)\ + $(OutDir)$(ProjectName)\ + + + + Disabled + ../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + + + ../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + + + {34681f0d-ce45-415d-b5f2-5c662dfe3bd5} + true + true + + + + + ../../include;%(AdditionalIncludeDirectories) + ../../include;%(AdditionalIncludeDirectories) + + + + + + diff --git a/msvc/2010/gmock_test.vcxproj b/msvc/2010/gmock_test.vcxproj new file mode 100644 index 00000000..265439ec --- /dev/null +++ b/msvc/2010/gmock_test.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F10D22F8-AC7B-4213-8720-608E7D878CD2} + gmock_test + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(OutDir)$(ProjectName)\ + true + $(SolutionDir)$(Configuration)\ + $(OutDir)$(ProjectName)\ + false + + + + /bigobj %(AdditionalOptions) + Disabled + ..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + true + Console + MachineX86 + + + + + /bigobj %(AdditionalOptions) + ..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + true + Console + true + true + MachineX86 + + + + + {e4ef614b-30df-4954-8c53-580a0bf6b589} + true + true + + + + + + + + + diff --git a/msvc/gmock-spec-builders_test.vcproj b/msvc/gmock-spec-builders_test.vcproj deleted file mode 100755 index 84407420..00000000 --- a/msvc/gmock-spec-builders_test.vcproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msvc/gmock.sln b/msvc/gmock.sln deleted file mode 100644 index f56dda64..00000000 --- a/msvc/gmock.sln +++ /dev/null @@ -1,44 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock", "gmock.vcproj", "{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_test", "gmock_test.vcproj", "{F10D22F8-AC7B-4213-8720-608E7D878CD2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_link_test", "gmock_link_test.vcproj", "{ED597847-A714-4327-B569-70029D2311F0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock-spec-builders_test", "gmock-spec-builders_test.vcproj", "{46972604-5BE0-4493-BAE3-878DB825FDCB}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.ActiveCfg = Debug|Win32 - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Debug|Win32.Build.0 = Debug|Win32 - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.ActiveCfg = Release|Win32 - {34681F0D-CE45-415D-B5F2-5C662DFE3BD5}.Release|Win32.Build.0 = Release|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.ActiveCfg = Debug|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Debug|Win32.Build.0 = Debug|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.ActiveCfg = Release|Win32 - {F10D22F8-AC7B-4213-8720-608E7D878CD2}.Release|Win32.Build.0 = Release|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.ActiveCfg = Debug|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Debug|Win32.Build.0 = Debug|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.ActiveCfg = Release|Win32 - {ED597847-A714-4327-B569-70029D2311F0}.Release|Win32.Build.0 = Release|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.ActiveCfg = Debug|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32 - {E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32 - {46972604-5BE0-4493-BAE3-878DB825FDCB}.Debug|Win32.ActiveCfg = Debug|Win32 - {46972604-5BE0-4493-BAE3-878DB825FDCB}.Debug|Win32.Build.0 = Debug|Win32 - {46972604-5BE0-4493-BAE3-878DB825FDCB}.Release|Win32.ActiveCfg = Release|Win32 - {46972604-5BE0-4493-BAE3-878DB825FDCB}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/msvc/gmock.vcproj b/msvc/gmock.vcproj deleted file mode 100644 index e50f88ce..00000000 --- a/msvc/gmock.vcproj +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msvc/gmock_config.vsprops b/msvc/gmock_config.vsprops deleted file mode 100644 index a68c32e1..00000000 --- a/msvc/gmock_config.vsprops +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/msvc/gmock_link_test.vcproj b/msvc/gmock_link_test.vcproj deleted file mode 100644 index 3c1ee142..00000000 --- a/msvc/gmock_link_test.vcproj +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msvc/gmock_main.vcproj b/msvc/gmock_main.vcproj deleted file mode 100644 index f0e2fa3c..00000000 --- a/msvc/gmock_main.vcproj +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msvc/gmock_test.vcproj b/msvc/gmock_test.vcproj deleted file mode 100644 index a0a2f0e5..00000000 --- a/msvc/gmock_test.vcproj +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From ed6c9277bb12f2808bb812ae8f91492dac9517b4 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 23 Feb 2011 19:39:27 +0000 Subject: Makes Google Mock compile much faster and use much less memory; reviewed by Nico Weber. This fixes issue 68. --- include/gmock/gmock-actions.h | 63 +- include/gmock/gmock-generated-function-mockers.h | 63 +- .../gmock/gmock-generated-function-mockers.h.pump | 3 +- include/gmock/gmock-spec-builders.h | 852 +++++++++------------ scripts/gmock_doctor.py | 4 +- src/gmock-spec-builders.cc | 338 +++++++- test/gmock-actions_test.cc | 3 +- test/gmock-spec-builders_test.cc | 57 +- 8 files changed, 813 insertions(+), 570 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index f88ac80d..af3483f7 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -59,9 +59,6 @@ namespace testing { namespace internal { -template -class MonomorphicDoDefaultActionImpl; - template class ActionAdaptor; @@ -255,8 +252,7 @@ class ActionInterface { typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; - ActionInterface() : is_do_default_(false) {} - + ActionInterface() {} virtual ~ActionInterface() {} // Performs the action. This method is not const, as in general an @@ -265,21 +261,7 @@ class ActionInterface { // remember the current element. virtual Result Perform(const ArgumentTuple& args) = 0; - // Returns true iff this is the DoDefault() action. - bool IsDoDefault() const { return is_do_default_; } - private: - template - friend class internal::MonomorphicDoDefaultActionImpl; - - // This private constructor is reserved for implementing - // DoDefault(), the default action for a given mock function. - explicit ActionInterface(bool is_do_default) - : is_do_default_(is_do_default) {} - - // True iff this action is DoDefault(). - const bool is_do_default_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); }; @@ -302,7 +284,8 @@ class Action { // STL containers. Action() : impl_(NULL) {} - // Constructs an Action from its implementation. + // 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. @@ -316,7 +299,7 @@ class Action { explicit Action(const Action& action); // Returns true iff this is the DoDefault() action. - bool IsDoDefault() const { return impl_->IsDoDefault(); } + 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 @@ -325,6 +308,13 @@ class Action { // 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); } @@ -633,42 +623,13 @@ class ReturnRefOfCopyAction { GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction); }; -// Implements the DoDefault() action for a particular function type F. -template -class MonomorphicDoDefaultActionImpl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - MonomorphicDoDefaultActionImpl() : ActionInterface(true) {} - - // For technical reasons, DoDefault() cannot be used inside a - // composite action (e.g. DoAll(...)). It can only be used at the - // top level in an EXPECT_CALL(). If this function is called, the - // user must be using DoDefault() inside a composite action, and we - // have to generate a run-time error. - virtual Result Perform(const ArgumentTuple&) { - Assert(false, __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 internal::Invalid(); - // The above statement will never be reached, but is required in - // order for this function to compile. - } -}; - // 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(new MonomorphicDoDefaultActionImpl); - } + operator Action() const { return Action(NULL); } }; // Implements the Assign action to set a given pointer referent to a diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 7b334e42..509d46cb 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -1,4 +1,6 @@ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! +// 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. @@ -352,7 +354,8 @@ using internal::FunctionMocker; } \ ::testing::MockSpec& \ gmock_##Method() constness { \ - return GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this).With(); \ + GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(0, constness, Method).With(); \ } \ mutable ::testing::FunctionMocker GMOCK_MOCKER_(0, constness, Method) @@ -367,8 +370,8 @@ using internal::FunctionMocker; } \ ::testing::MockSpec& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1) constness { \ - return GMOCK_MOCKER_(1, constness, \ - Method).RegisterOwner(this).With(gmock_a1); \ + GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \ } \ mutable ::testing::FunctionMocker GMOCK_MOCKER_(1, constness, Method) @@ -385,8 +388,8 @@ using internal::FunctionMocker; ::testing::MockSpec& \ gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ GMOCK_MATCHER_(tn, F, 2) gmock_a2) constness { \ - return GMOCK_MOCKER_(2, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \ + GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \ } \ mutable ::testing::FunctionMocker GMOCK_MOCKER_(2, constness, Method) @@ -406,8 +409,9 @@ using internal::FunctionMocker; gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ GMOCK_MATCHER_(tn, F, 3) gmock_a3) constness { \ - return GMOCK_MOCKER_(3, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3); \ + GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \ + gmock_a3); \ } \ mutable ::testing::FunctionMocker GMOCK_MOCKER_(3, constness, Method) @@ -429,9 +433,9 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ GMOCK_MATCHER_(tn, F, 4) gmock_a4) constness { \ - return GMOCK_MOCKER_(4, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4); \ + 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 GMOCK_MOCKER_(4, constness, Method) @@ -455,9 +459,9 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ GMOCK_MATCHER_(tn, F, 5) gmock_a5) constness { \ - return GMOCK_MOCKER_(5, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5); \ + 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 GMOCK_MOCKER_(5, constness, Method) @@ -483,9 +487,9 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ GMOCK_MATCHER_(tn, F, 6) gmock_a6) constness { \ - return GMOCK_MOCKER_(6, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6); \ + 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 GMOCK_MOCKER_(6, constness, Method) @@ -513,9 +517,9 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ GMOCK_MATCHER_(tn, F, 7) gmock_a7) constness { \ - return GMOCK_MOCKER_(7, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ + 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 GMOCK_MOCKER_(7, constness, Method) @@ -545,9 +549,9 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ GMOCK_MATCHER_(tn, F, 8) gmock_a8) constness { \ - return GMOCK_MOCKER_(8, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ + 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 GMOCK_MOCKER_(8, constness, Method) @@ -580,9 +584,10 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ GMOCK_MATCHER_(tn, F, 9) gmock_a9) constness { \ - return GMOCK_MOCKER_(9, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9); \ + 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 GMOCK_MOCKER_(9, constness, Method) @@ -617,9 +622,9 @@ using internal::FunctionMocker; GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ GMOCK_MATCHER_(tn, F, 9) gmock_a9, \ GMOCK_MATCHER_(tn, F, 10) gmock_a10) constness { \ - return GMOCK_MOCKER_(10, constness, \ - Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \ - gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ + 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 GMOCK_MOCKER_(10, constness, Method) diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 50b369bb..4f82d622 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -140,7 +140,8 @@ $var matcher_as = [[$for j, \ } \ ::testing::MockSpec& \ gmock_##Method($matcher_as) constness { \ - return GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this).With($as); \ + GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \ + return GMOCK_MOCKER_($i, constness, Method).With($as); \ } \ mutable ::testing::FunctionMocker GMOCK_MOCKER_($i, constness, Method) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 4f0b0725..9e185085 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -113,53 +113,190 @@ template class FunctionMockerBase; // calls to ensure the integrity of the mock objects' states. GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); +// Untyped base class for ActionResultHolder. +class UntypedActionResultHolderBase; + // Abstract base class of FunctionMockerBase. This is the // type-agnostic part of the function mocker interface. Its pure // virtual methods are implemented by FunctionMockerBase. class UntypedFunctionMockerBase { public: - virtual ~UntypedFunctionMockerBase() {} + UntypedFunctionMockerBase(); + virtual ~UntypedFunctionMockerBase(); // Verifies that all expectations on this mock function have been // satisfied. Reports one or more Google Test non-fatal failures // and returns false if not. // L >= g_gmock_mutex - virtual bool VerifyAndClearExpectationsLocked() = 0; + bool VerifyAndClearExpectationsLocked(); // Clears the ON_CALL()s set on this mock function. // L >= g_gmock_mutex virtual void ClearDefaultActionsLocked() = 0; + + // In all of the following Untyped* functions, it's the caller's + // responsibility to guarantee the correctness of the arguments' + // types. + + // Performs the default action with the given arguments and returns + // the action's result. The call description string will be used in + // the error message to describe the call in the case the default + // action fails. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction( + const void* untyped_args, + const string& call_description) const = 0; + + // Performs the given action with the given arguments and returns + // the action's result. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformAction( + const void* untyped_action, + const void* untyped_args) const = 0; + + // Writes a message that the call is uninteresting (i.e. neither + // explicitly expected nor explicitly unexpected) to the given + // ostream. + // L < g_gmock_mutex + virtual void UntypedDescribeUninterestingCall(const void* untyped_args, + ::std::ostream* os) const = 0; + + // Returns the expectation that matches the given function arguments + // (or NULL is there's no match); when a match is found, + // untyped_action is set to point to the action that should be + // performed (or NULL if the action is "do default"), and + // is_excessive is modified to indicate whether the call exceeds the + // expected number. + // L < g_gmock_mutex + virtual const ExpectationBase* UntypedFindMatchingExpectation( + const void* untyped_args, + const void** untyped_action, bool* is_excessive, + ::std::ostream* what, ::std::ostream* why) = 0; + + // Prints the given function arguments to the ostream. + virtual void UntypedPrintArgs(const void* untyped_args, + ::std::ostream* os) const = 0; + + // Sets the mock object this mock method belongs to, and registers + // this information in the global mock registry. Will be called + // whenever an EXPECT_CALL() or ON_CALL() is executed on this mock + // method. + // TODO(wan@google.com): rename to SetAndRegisterOwner(). + // L < g_gmock_mutex + void RegisterOwner(const void* mock_obj); + + // Sets the mock object this mock method belongs to, and sets the + // name of the mock function. Will be called upon each invocation + // of this mock function. + // L < g_gmock_mutex + void SetOwnerAndName(const void* mock_obj, const char* name); + + // Returns the mock object this mock method belongs to. Must be + // called after RegisterOwner() or SetOwnerAndName() has been + // called. + // L < g_gmock_mutex + const void* MockObject() const; + + // Returns the name of this mock method. Must be called after + // SetOwnerAndName() has been called. + // L < g_gmock_mutex + const char* Name() const; + + // Returns the result of invoking this mock function with the given + // arguments. This function can be safely called from multiple + // threads concurrently. The caller is responsible for deleting the + // result. + // L < g_gmock_mutex + const UntypedActionResultHolderBase* UntypedInvokeWith( + const void* untyped_args); + + protected: + typedef std::vector UntypedOnCallSpecs; + + typedef std::vector > + UntypedExpectations; + + // Returns an Expectation object that references and co-owns exp, + // which must be an expectation on this mock function. + Expectation GetHandleOf(ExpectationBase* exp); + + // Address of the mock object this mock method belongs to. Only + // valid after this mock method has been called or + // ON_CALL/EXPECT_CALL has been invoked on it. + const void* mock_obj_; // Protected by g_gmock_mutex. + + // Name of the function being mocked. Only valid after this mock + // method has been called. + const char* name_; // Protected by g_gmock_mutex. + + // All default action specs for this function mocker. + UntypedOnCallSpecs untyped_on_call_specs_; + + // All expectations for this function mocker. + UntypedExpectations untyped_expectations_; }; // class UntypedFunctionMockerBase -// This template class implements a default action spec (i.e. an -// ON_CALL() statement). +// Untyped base class for OnCallSpec. +class UntypedOnCallSpecBase { + public: + // The arguments are the location of the ON_CALL() statement. + UntypedOnCallSpecBase(const char* a_file, int a_line) + : file_(a_file), line_(a_line), last_clause_(kNone) {} + + // Where in the source file was the default action spec defined? + const char* file() const { return file_; } + int line() const { return line_; } + + protected: + // Gives each clause in the ON_CALL() statement a name. + enum Clause { + // Do not change the order of the enum members! The run-time + // syntax checking relies on it. + kNone, + kWith, + kWillByDefault, + }; + + // Asserts that the ON_CALL() statement has a certain property. + void AssertSpecProperty(bool property, const string& failure_message) const { + Assert(property, file_, line_, failure_message); + } + + // Expects that the ON_CALL() statement has a certain property. + void ExpectSpecProperty(bool property, const string& failure_message) const { + Expect(property, file_, line_, failure_message); + } + + const char* file_; + int line_; + + // The last clause in the ON_CALL() statement as seen so far. + // Initially kNone and changes as the statement is parsed. + Clause last_clause_; +}; // class UntypedOnCallSpecBase + +// This template class implements an ON_CALL spec. template -class DefaultActionSpec { +class OnCallSpec : public UntypedOnCallSpecBase { public: typedef typename Function::ArgumentTuple ArgumentTuple; typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; - // Constructs a DefaultActionSpec object from the information inside + // Constructs an OnCallSpec object from the information inside // the parenthesis of an ON_CALL() statement. - DefaultActionSpec(const char* a_file, int a_line, - const ArgumentMatcherTuple& matchers) - : file_(a_file), - line_(a_line), + OnCallSpec(const char* a_file, int a_line, + const ArgumentMatcherTuple& matchers) + : UntypedOnCallSpecBase(a_file, a_line), matchers_(matchers), // By default, extra_matcher_ should match anything. However, // we cannot initialize it with _ as that triggers a compiler // bug in Symbian's C++ compiler (cannot decide between two // overloaded constructors of Matcher). - extra_matcher_(A()), - last_clause_(kNone) { + extra_matcher_(A()) { } - // Where in the source file was the default action spec defined? - const char* file() const { return file_; } - int line() const { return line_; } - // Implements the .With() clause. - DefaultActionSpec& With(const Matcher& m) { + OnCallSpec& With(const Matcher& m) { // Makes sure this is called at most once. ExpectSpecProperty(last_clause_ < kWith, ".With() cannot appear " @@ -171,7 +308,7 @@ class DefaultActionSpec { } // Implements the .WillByDefault() clause. - DefaultActionSpec& WillByDefault(const Action& action) { + OnCallSpec& WillByDefault(const Action& action) { ExpectSpecProperty(last_clause_ < kWillByDefault, ".WillByDefault() must appear " "exactly once in an ON_CALL()."); @@ -197,25 +334,6 @@ class DefaultActionSpec { } private: - // Gives each clause in the ON_CALL() statement a name. - enum Clause { - // Do not change the order of the enum members! The run-time - // syntax checking relies on it. - kNone, - kWith, - kWillByDefault, - }; - - // Asserts that the ON_CALL() statement has a certain property. - void AssertSpecProperty(bool property, const string& failure_message) const { - Assert(property, file_, line_, failure_message); - } - - // Expects that the ON_CALL() statement has a certain property. - void ExpectSpecProperty(bool property, const string& failure_message) const { - Expect(property, file_, line_, failure_message); - } - // The information in statement // // ON_CALL(mock_object, Method(matchers)) @@ -229,16 +347,10 @@ class DefaultActionSpec { // matchers => matchers_ // multi-argument-matcher => extra_matcher_ // action => action_ - const char* file_; - int line_; ArgumentMatcherTuple matchers_; Matcher extra_matcher_; Action action_; - - // The last clause in the ON_CALL() statement as seen so far. - // Initially kNone and changes as the statement is parsed. - Clause last_clause_; -}; // class DefaultActionSpec +}; // class OnCallSpec // Possible reactions on uninteresting calls. TODO(wan@google.com): // rename the enum values to the kFoo style. @@ -269,6 +381,8 @@ class Mock { // verification was successful. static bool VerifyAndClear(void* mock_obj); private: + friend class internal::UntypedFunctionMockerBase; + // Needed for a function mocker to register itself (so that we know // how to clear a mock object). template @@ -389,6 +503,7 @@ class Expectation { friend class ExpectationSet; friend class Sequence; friend class ::testing::internal::ExpectationBase; + friend class ::testing::internal::UntypedFunctionMockerBase; template friend class ::testing::internal::FunctionMockerBase; @@ -581,10 +696,15 @@ class ExpectationBase { // Describes how many times a function call matching this // expectation has occurred. // L >= g_gmock_mutex - virtual void DescribeCallCountTo(::std::ostream* os) const = 0; + void DescribeCallCountTo(::std::ostream* os) const; + + // If this mock method has an extra matcher (i.e. .With(matcher)), + // describes it to the ostream. + virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) = 0; protected: friend class ::testing::Expectation; + friend class UntypedFunctionMockerBase; enum Clause { // Don't change the order of the enum members! @@ -598,6 +718,8 @@ class ExpectationBase { kRetiresOnSaturation, }; + typedef std::vector UntypedActions; + // Returns an Expectation object that references and co-owns this // expectation. virtual Expectation GetHandle() = 0; @@ -690,13 +812,22 @@ class ExpectationBase { call_count_++; } - private: + // Checks the action count (i.e. the number of WillOnce() and + // WillRepeatedly() clauses) against the cardinality if this hasn't + // been done before. Prints a warning if there are too many or too + // few actions. + // L < mutex_ + void CheckActionCountIfNotDone() const; + friend class ::testing::Sequence; friend class ::testing::internal::ExpectationTester; template friend class TypedExpectation; + // Implements the .Times() clause. + void UntypedTimes(const Cardinality& a_cardinality); + // This group of fields are part of the spec and won't change after // an EXPECT_CALL() statement finishes. const char* file_; // The file that contains the expectation. @@ -717,6 +848,13 @@ class ExpectationBase { // and can change as the mock function is called. int call_count_; // How many times this expectation has been invoked. bool retired_; // True iff this expectation has retired. + UntypedActions untyped_actions_; + bool extra_matcher_specified_; + bool repeated_action_specified_; // True if a WillRepeatedly() was specified. + bool retires_on_saturation_; + Clause last_clause_; + mutable bool action_count_checked_; // Under mutex_. + mutable Mutex mutex_; // Protects action_count_checked_. GTEST_DISALLOW_ASSIGN_(ExpectationBase); }; // class ExpectationBase @@ -735,22 +873,21 @@ class TypedExpectation : public ExpectationBase { : ExpectationBase(a_file, a_line, a_source_text), owner_(owner), matchers_(m), - extra_matcher_specified_(false), // By default, extra_matcher_ should match anything. However, // we cannot initialize it with _ as that triggers a compiler // bug in Symbian's C++ compiler (cannot decide between two // overloaded constructors of Matcher). extra_matcher_(A()), - repeated_action_specified_(false), - repeated_action_(DoDefault()), - retires_on_saturation_(false), - last_clause_(kNone), - action_count_checked_(false) {} + repeated_action_(DoDefault()) {} virtual ~TypedExpectation() { // Check the validity of the action count if it hasn't been done // yet (for example, if the expectation was never used). CheckActionCountIfNotDone(); + for (UntypedActions::const_iterator it = untyped_actions_.begin(); + it != untyped_actions_.end(); ++it) { + delete static_cast*>(*it); + } } // Implements the .With() clause. @@ -773,19 +910,7 @@ class TypedExpectation : public ExpectationBase { // Implements the .Times() clause. TypedExpectation& Times(const Cardinality& a_cardinality) { - if (last_clause_ ==kTimes) { - ExpectSpecProperty(false, - ".Times() cannot appear " - "more than once in an EXPECT_CALL()."); - } else { - ExpectSpecProperty(last_clause_ < kTimes, - ".Times() cannot appear after " - ".InSequence(), .WillOnce(), .WillRepeatedly(), " - "or .RetiresOnSaturation()."); - } - last_clause_ = kTimes; - - ExpectationBase::SpecifyCardinality(a_cardinality); + ExpectationBase::UntypedTimes(a_cardinality); return *this; } @@ -859,9 +984,9 @@ class TypedExpectation : public ExpectationBase { ".WillRepeatedly() or .RetiresOnSaturation()."); last_clause_ = kWillOnce; - actions_.push_back(action); + untyped_actions_.push_back(new Action(action)); if (!cardinality_specified()) { - set_cardinality(Exactly(static_cast(actions_.size()))); + set_cardinality(Exactly(static_cast(untyped_actions_.size()))); } return *this; } @@ -882,7 +1007,7 @@ class TypedExpectation : public ExpectationBase { repeated_action_ = action; if (!cardinality_specified()) { - set_cardinality(AtLeast(static_cast(actions_.size()))); + set_cardinality(AtLeast(static_cast(untyped_actions_.size()))); } // Now that no more action clauses can be specified, we check @@ -916,38 +1041,12 @@ class TypedExpectation : public ExpectationBase { return extra_matcher_; } - // Returns the sequence of actions specified by the .WillOnce() clause. - const std::vector >& actions() const { return actions_; } - // Returns the action specified by the .WillRepeatedly() clause. const Action& repeated_action() const { return repeated_action_; } - // Returns true iff the .RetiresOnSaturation() clause was specified. - bool retires_on_saturation() const { return retires_on_saturation_; } - - // Describes how many times a function call matching this - // expectation has occurred (implements - // ExpectationBase::DescribeCallCountTo()). - // L >= g_gmock_mutex - virtual void DescribeCallCountTo(::std::ostream* os) const { - g_gmock_mutex.AssertHeld(); - - // Describes how many times the function is expected to be called. - *os << " Expected: to be "; - cardinality().DescribeTo(os); - *os << "\n Actual: "; - Cardinality::DescribeActualCallCountTo(call_count(), os); - - // Describes the state of the expectation (e.g. is it satisfied? - // is it active?). - *os << " - " << (IsOverSaturated() ? "over-saturated" : - IsSaturated() ? "saturated" : - IsSatisfied() ? "satisfied" : "unsatisfied") - << " and " - << (is_retired() ? "retired" : "active"); - } - - void MaybeDescribeExtraMatcherTo(::std::ostream* os) { + // If this mock method has an extra matcher (i.e. .With(matcher)), + // describes it to the ostream. + virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) { if (extra_matcher_specified_) { *os << " Expected args: "; extra_matcher_.DescribeTo(os); @@ -1044,7 +1143,7 @@ class TypedExpectation : public ExpectationBase { "call_count() is <= 0 when GetCurrentAction() is " "called - this should never happen."); - const int action_count = static_cast(actions().size()); + const int action_count = static_cast(untyped_actions_.size()); if (action_count > 0 && !repeated_action_specified_ && count > action_count) { // If there is at least one WillOnce() and no WillRepeatedly(), @@ -1059,7 +1158,9 @@ class TypedExpectation : public ExpectationBase { Log(WARNING, ss.str(), 1); } - return count <= action_count ? actions()[count - 1] : repeated_action(); + return count <= action_count ? + *static_cast*>(untyped_actions_[count - 1]) : + repeated_action(); } // Given the arguments of a mock function call, if the call will @@ -1067,12 +1168,13 @@ class TypedExpectation : public ExpectationBase { // otherwise, returns the next action in this expectation. Also // describes *what* happened to 'what', and explains *why* Google // Mock does it to 'why'. This method is not const as it calls - // IncrementCallCount(). + // IncrementCallCount(). A return value of NULL means the default + // action. // L >= g_gmock_mutex - Action GetActionForArguments(const FunctionMockerBase* mocker, - const ArgumentTuple& args, - ::std::ostream* what, - ::std::ostream* why) { + const Action* GetActionForArguments(const FunctionMockerBase* mocker, + const ArgumentTuple& args, + ::std::ostream* what, + ::std::ostream* why) { g_gmock_mutex.AssertHeld(); if (IsSaturated()) { // We have an excessive call. @@ -1081,92 +1183,30 @@ class TypedExpectation : public ExpectationBase { mocker->DescribeDefaultActionTo(args, what); DescribeCallCountTo(why); - // TODO(wan): allow the user to control whether unexpected calls - // should fail immediately or continue using a flag - // --gmock_unexpected_calls_are_fatal. - return DoDefault(); + // TODO(wan@google.com): allow the user to control whether + // unexpected calls should fail immediately or continue using a + // flag --gmock_unexpected_calls_are_fatal. + return NULL; } IncrementCallCount(); RetireAllPreRequisites(); - if (retires_on_saturation() && IsSaturated()) { + if (retires_on_saturation_ && IsSaturated()) { Retire(); } // Must be done after IncrementCount()! *what << "Mock function call matches " << source_text() <<"...\n"; - return GetCurrentAction(mocker, args); - } - - // Checks the action count (i.e. the number of WillOnce() and - // WillRepeatedly() clauses) against the cardinality if this hasn't - // been done before. Prints a warning if there are too many or too - // few actions. - // L < mutex_ - void CheckActionCountIfNotDone() const { - bool should_check = false; - { - MutexLock l(&mutex_); - if (!action_count_checked_) { - action_count_checked_ = true; - should_check = true; - } - } - - if (should_check) { - if (!cardinality_specified_) { - // The cardinality was inferred - no need to check the action - // count against it. - return; - } - - // The cardinality was explicitly specified. - const int action_count = static_cast(actions_.size()); - const int upper_bound = cardinality().ConservativeUpperBound(); - const int lower_bound = cardinality().ConservativeLowerBound(); - bool too_many; // True if there are too many actions, or false - // if there are too few. - if (action_count > upper_bound || - (action_count == upper_bound && repeated_action_specified_)) { - too_many = true; - } else if (0 < action_count && action_count < lower_bound && - !repeated_action_specified_) { - too_many = false; - } else { - return; - } - - ::std::stringstream ss; - DescribeLocationTo(&ss); - ss << "Too " << (too_many ? "many" : "few") - << " actions specified in " << source_text() << "...\n" - << "Expected to be "; - cardinality().DescribeTo(&ss); - ss << ", but has " << (too_many ? "" : "only ") - << action_count << " WillOnce()" - << (action_count == 1 ? "" : "s"); - if (repeated_action_specified_) { - ss << " and a WillRepeatedly()"; - } - ss << "."; - Log(WARNING, ss.str(), -1); // -1 means "don't print stack trace". - } + return &(GetCurrentAction(mocker, args)); } // All the fields below won't change once the EXPECT_CALL() // statement finishes. FunctionMockerBase* const owner_; ArgumentMatcherTuple matchers_; - bool extra_matcher_specified_; Matcher extra_matcher_; - std::vector > actions_; - bool repeated_action_specified_; // True if a WillRepeatedly() was specified. Action repeated_action_; - bool retires_on_saturation_; - Clause last_clause_; - mutable bool action_count_checked_; // Under mutex_. - mutable Mutex mutex_; // Protects action_count_checked_. GTEST_DISALLOW_COPY_AND_ASSIGN_(TypedExpectation); }; // class TypedExpectation @@ -1181,6 +1221,11 @@ class TypedExpectation : public ExpectationBase { // template. To workaround this compiler bug, we define MockSpec in // ::testing::internal and import it into ::testing. +// Logs a message including file and line number information. +void LogWithLocation(testing::internal::LogSeverity severity, + const char* file, int line, + const string& message); + template class MockSpec { public: @@ -1195,11 +1240,11 @@ class MockSpec { // Adds a new default action spec to the function mocker and returns // the newly created spec. - internal::DefaultActionSpec& InternalDefaultActionSetAt( + internal::OnCallSpec& InternalDefaultActionSetAt( const char* file, int line, const char* obj, const char* call) { LogWithLocation(internal::INFO, file, line, string("ON_CALL(") + obj + ", " + call + ") invoked"); - return function_mocker_->AddNewDefaultActionSpec(file, line, matchers_); + return function_mocker_->AddNewOnCallSpec(file, line, matchers_); } // Adds a new expectation spec to the function mocker and returns @@ -1220,15 +1265,6 @@ class MockSpec { matchers_ = matchers; } - // Logs a message including file and line number information. - void LogWithLocation(testing::internal::LogSeverity severity, - const char* file, int line, - const string& message) { - ::std::ostringstream s; - s << file << ":" << line << ": " << message << ::std::endl; - Log(severity, s.str(), 0); - } - // The function mocker that owns this spec. internal::FunctionMockerBase* const function_mocker_; // The argument matchers specified in the spec. @@ -1253,42 +1289,58 @@ class MockSpec { // copyable type or void (T doesn't need to be default-constructable). // It hides the syntactic difference between void and other types, and // is used to unify the code for invoking both void-returning and -// non-void-returning mock functions. This generic definition is used -// when T is not void. +// non-void-returning mock functions. + +// Untyped base class for ActionResultHolder. +class UntypedActionResultHolderBase { + public: + virtual ~UntypedActionResultHolderBase() {} + + // Prints the held value as an action's result to os. + virtual void PrintAsActionResult(::std::ostream* os) const = 0; +}; + +// This generic definition is used when T is not void. template -class ActionResultHolder { +class ActionResultHolder : public UntypedActionResultHolderBase { public: explicit ActionResultHolder(T a_value) : value_(a_value) {} // The compiler-generated copy constructor and assignment operator // are exactly what we need, so we don't need to define them. - T value() const { return value_; } + // Returns the held value and deletes this object. + T GetValueAndDelete() const { + T retval(value_); + delete this; + return retval; + } // Prints the held value as an action's result to os. - void PrintAsActionResult(::std::ostream* os) const { + virtual void PrintAsActionResult(::std::ostream* os) const { *os << "\n Returns: "; // T may be a reference type, so we don't use UniversalPrint(). UniversalPrinter::Print(value_, os); } // Performs the given mock function's default action and returns the - // result in a ActionResultHolder. - template - static ActionResultHolder PerformDefaultAction( - const FunctionMockerBase* func_mocker, - const Arguments& args, + // result in a new-ed ActionResultHolder. + template + static ActionResultHolder* PerformDefaultAction( + const FunctionMockerBase* func_mocker, + const typename Function::ArgumentTuple& args, const string& call_description) { - return ActionResultHolder( + return new ActionResultHolder( func_mocker->PerformDefaultAction(args, call_description)); } - // Performs the given action and returns the result in a + // Performs the given action and returns the result in a new-ed // ActionResultHolder. - template - static ActionResultHolder PerformAction(const Action& action, - const Arguments& args) { - return ActionResultHolder(action.Perform(args)); + template + static ActionResultHolder* + PerformAction(const Action& action, + const typename Function::ArgumentTuple& args) { + return new ActionResultHolder(action.Perform(args)); } private: @@ -1300,26 +1352,29 @@ class ActionResultHolder { // Specialization for T = void. template <> -class ActionResultHolder { +class ActionResultHolder : public UntypedActionResultHolderBase { public: - ActionResultHolder() {} - void value() const {} - void PrintAsActionResult(::std::ostream* /* os */) const {} - - template - static ActionResultHolder PerformDefaultAction( - const FunctionMockerBase* func_mocker, - const Arguments& args, + void GetValueAndDelete() const { delete this; } + + virtual void PrintAsActionResult(::std::ostream* /* os */) const {} + + // Performs the given mock function's default action and returns NULL; + template + static ActionResultHolder* PerformDefaultAction( + const FunctionMockerBase* func_mocker, + const typename Function::ArgumentTuple& args, const string& call_description) { func_mocker->PerformDefaultAction(args, call_description); - return ActionResultHolder(); + return NULL; } - template - static ActionResultHolder PerformAction(const Action& action, - const Arguments& args) { + // Performs the given action and returns NULL. + template + static ActionResultHolder* PerformAction( + const Action& action, + const typename Function::ArgumentTuple& args) { action.Perform(args); - return ActionResultHolder(); + return NULL; } }; @@ -1333,7 +1388,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { typedef typename Function::ArgumentTuple ArgumentTuple; typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; - FunctionMockerBase() : mock_obj_(NULL), name_(""), current_spec_(this) {} + FunctionMockerBase() : current_spec_(this) {} // The destructor verifies that all expectations on this mock // function have been satisfied. If not, it will report Google Test @@ -1343,19 +1398,20 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { MutexLock l(&g_gmock_mutex); VerifyAndClearExpectationsLocked(); Mock::UnregisterLocked(this); + ClearDefaultActionsLocked(); } // Returns the ON_CALL spec that matches this mock function with the // given arguments; returns NULL if no matching ON_CALL is found. // L = * - const DefaultActionSpec* FindDefaultActionSpec( + const OnCallSpec* FindOnCallSpec( const ArgumentTuple& args) const { - for (typename std::vector >::const_reverse_iterator it - = default_actions_.rbegin(); - it != default_actions_.rend(); ++it) { - const DefaultActionSpec& spec = *it; - if (spec.Matches(args)) - return &spec; + for (UntypedOnCallSpecs::const_reverse_iterator it + = untyped_on_call_specs_.rbegin(); + it != untyped_on_call_specs_.rend(); ++it) { + const OnCallSpec* spec = static_cast*>(*it); + if (spec->Matches(args)) + return spec; } return NULL; @@ -1368,7 +1424,8 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // L = * Result PerformDefaultAction(const ArgumentTuple& args, const string& call_description) const { - const DefaultActionSpec* const spec = FindDefaultActionSpec(args); + const OnCallSpec* const spec = + this->FindOnCallSpec(args); if (spec != NULL) { return spec->GetAction().Perform(args); } @@ -1378,91 +1435,70 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { return DefaultValue::Get(); } - // Registers this function mocker and the mock object owning it; - // returns a reference to the function mocker object. This is only - // called by the ON_CALL() and EXPECT_CALL() macros. - // L < g_gmock_mutex - FunctionMocker& RegisterOwner(const void* mock_obj) { - { - MutexLock l(&g_gmock_mutex); - mock_obj_ = mock_obj; - } - Mock::Register(mock_obj, this); - return *::testing::internal::DownCast_*>(this); + // Performs the default action with the given arguments and returns + // the action's result. The call description string will be used in + // the error message to describe the call in the case the default + // action fails. The caller is responsible for deleting the result. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction( + const void* untyped_args, // must point to an ArgumentTuple + const string& call_description) const { + const ArgumentTuple& args = + *static_cast(untyped_args); + return ResultHolder::PerformDefaultAction(this, args, call_description); } - // The following two functions are from UntypedFunctionMockerBase. - - // Verifies that all expectations on this mock function have been - // satisfied. Reports one or more Google Test non-fatal failures - // and returns false if not. - // L >= g_gmock_mutex - virtual bool VerifyAndClearExpectationsLocked(); - - // Clears the ON_CALL()s set on this mock function. + // Performs the given action with the given arguments and returns + // the action's result. The caller is responsible for deleting the + // result. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformAction( + const void* untyped_action, const void* untyped_args) const { + // Make a copy of the action before performing it, in case the + // action deletes the mock object (and thus deletes itself). + const Action action = *static_cast*>(untyped_action); + const ArgumentTuple& args = + *static_cast(untyped_args); + return ResultHolder::PerformAction(action, args); + } + + // Implements UntypedFunctionMockerBase::ClearDefaultActionsLocked(): + // clears the ON_CALL()s set on this mock function. // L >= g_gmock_mutex virtual void ClearDefaultActionsLocked() { g_gmock_mutex.AssertHeld(); - default_actions_.clear(); - } - - // Sets the name of the function being mocked. Will be called upon - // each invocation of this mock function. - // L < g_gmock_mutex - void SetOwnerAndName(const void* mock_obj, const char* name) { - // We protect name_ under g_gmock_mutex in case this mock function - // is called from two threads concurrently. - MutexLock l(&g_gmock_mutex); - mock_obj_ = mock_obj; - name_ = name; - } - - // Returns the address of the mock object this method belongs to. - // Must be called after SetOwnerAndName() has been called. - // L < g_gmock_mutex - const void* MockObject() const { - const void* mock_obj; - { - // We protect mock_obj_ under g_gmock_mutex in case this mock - // function is called from two threads concurrently. - MutexLock l(&g_gmock_mutex); - mock_obj = mock_obj_; + for (UntypedOnCallSpecs::const_iterator it = + untyped_on_call_specs_.begin(); + it != untyped_on_call_specs_.end(); ++it) { + delete static_cast*>(*it); } - return mock_obj; - } - - // Returns the name of the function being mocked. Must be called - // after SetOwnerAndName() has been called. - // L < g_gmock_mutex - const char* Name() const { - const char* name; - { - // We protect name_ under g_gmock_mutex in case this mock - // function is called from two threads concurrently. - MutexLock l(&g_gmock_mutex); - name = name_; - } - return name; + untyped_on_call_specs_.clear(); } protected: template friend class MockSpec; + typedef ActionResultHolder ResultHolder; + // Returns the result of invoking this mock function with the given // arguments. This function can be safely called from multiple // threads concurrently. // L < g_gmock_mutex - Result InvokeWith(const ArgumentTuple& args); + Result InvokeWith(const ArgumentTuple& args) { + return static_cast( + this->UntypedInvokeWith(&args))->GetValueAndDelete(); + } // Adds and returns a default action spec for this mock function. // L < g_gmock_mutex - DefaultActionSpec& AddNewDefaultActionSpec( + OnCallSpec& AddNewOnCallSpec( const char* file, int line, const ArgumentMatcherTuple& m) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); - default_actions_.push_back(DefaultActionSpec(file, line, m)); - return default_actions_.back(); + OnCallSpec* const on_call_spec = new OnCallSpec(file, line, m); + untyped_on_call_specs_.push_back(on_call_spec); + return *on_call_spec; } // Adds and returns an expectation spec for this mock function. @@ -1473,14 +1509,15 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { const string& source_text, const ArgumentMatcherTuple& m) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); - const linked_ptr > expectation( - new TypedExpectation(this, file, line, source_text, m)); - expectations_.push_back(expectation); + TypedExpectation* const expectation = + new TypedExpectation(this, file, line, source_text, m); + const linked_ptr untyped_expectation(expectation); + untyped_expectations_.push_back(untyped_expectation); // Adds this expectation into the implicit sequence if there is one. Sequence* const implicit_sequence = g_gmock_implicit_sequence.get(); if (implicit_sequence != NULL) { - implicit_sequence->AddExpectation(Expectation(expectation)); + implicit_sequence->AddExpectation(Expectation(untyped_expectation)); } return *expectation; @@ -1493,33 +1530,14 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { private: template friend class TypedExpectation; - typedef std::vector > > - TypedExpectations; - - // Returns an Expectation object that references and co-owns exp, - // which must be an expectation on this mock function. - Expectation GetHandleOf(TypedExpectation* exp) { - for (typename TypedExpectations::const_iterator it = expectations_.begin(); - it != expectations_.end(); ++it) { - if (it->get() == exp) { - return Expectation(*it); - } - } - - Assert(false, __FILE__, __LINE__, "Cannot find expectation."); - return Expectation(); - // The above statement is just to make the code compile, and will - // never be executed. - } - - // Some utilities needed for implementing InvokeWith(). + // Some utilities needed for implementing UntypedInvokeWith(). // Describes what default action will be performed for the given // arguments. // L = * void DescribeDefaultActionTo(const ArgumentTuple& args, ::std::ostream* os) const { - const DefaultActionSpec* const spec = FindDefaultActionSpec(args); + const OnCallSpec* const spec = FindOnCallSpec(args); if (spec == NULL) { *os << (internal::type_equals::value ? @@ -1535,14 +1553,23 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // explicitly expected nor explicitly unexpected) to the given // ostream. // L < g_gmock_mutex - void DescribeUninterestingCall(const ArgumentTuple& args, - ::std::ostream* os) const { + virtual void UntypedDescribeUninterestingCall(const void* untyped_args, + ::std::ostream* os) const { + const ArgumentTuple& args = + *static_cast(untyped_args); *os << "Uninteresting mock function call - "; DescribeDefaultActionTo(args, os); *os << " Function call: " << Name(); UniversalPrint(args, os); } + // Returns the expectation that matches the given function arguments + // (or NULL is there's no match); when a match is found, + // untyped_action is set to point to the action that should be + // performed (or NULL if the action is "do default"), and + // is_excessive is modified to indicate whether the call exceeds the + // expected number. + // // Critical section: We must find the matching expectation and the // corresponding action that needs to be taken in an ATOMIC // transaction. Otherwise another thread may call this mock @@ -1553,23 +1580,36 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // action does (it can invoke an arbitrary user function or even a // mock function) and excessive locking could cause a dead lock. // L < g_gmock_mutex - bool FindMatchingExpectationAndAction( - const ArgumentTuple& args, TypedExpectation** exp, Action* action, - bool* is_excessive, ::std::ostream* what, ::std::ostream* why) { + virtual const ExpectationBase* UntypedFindMatchingExpectation( + const void* untyped_args, + const void** untyped_action, bool* is_excessive, + ::std::ostream* what, ::std::ostream* why) { + const ArgumentTuple& args = + *static_cast(untyped_args); MutexLock l(&g_gmock_mutex); - *exp = this->FindMatchingExpectationLocked(args); - if (*exp == NULL) { // A match wasn't found. - *action = DoDefault(); + TypedExpectation* exp = this->FindMatchingExpectationLocked(args); + if (exp == NULL) { // A match wasn't found. this->FormatUnexpectedCallMessageLocked(args, what, why); - return false; + return NULL; } // This line must be done before calling GetActionForArguments(), // which will increment the call count for *exp and thus affect // its saturation status. - *is_excessive = (*exp)->IsSaturated(); - *action = (*exp)->GetActionForArguments(this, args, what, why); - return true; + *is_excessive = exp->IsSaturated(); + const Action* action = exp->GetActionForArguments(this, args, what, why); + if (action != NULL && action->IsDoDefault()) + action = NULL; // Normalize "do default" to NULL. + *untyped_action = action; + return exp; + } + + // Prints the given function arguments to the ostream. + virtual void UntypedPrintArgs(const void* untyped_args, + ::std::ostream* os) const { + const ArgumentTuple& args = + *static_cast(untyped_args); + UniversalPrint(args, os); } // Returns the expectation that matches the arguments, or NULL if no @@ -1578,10 +1618,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { TypedExpectation* FindMatchingExpectationLocked( const ArgumentTuple& args) const { g_gmock_mutex.AssertHeld(); - for (typename TypedExpectations::const_reverse_iterator it = - expectations_.rbegin(); - it != expectations_.rend(); ++it) { - TypedExpectation* const exp = it->get(); + for (typename UntypedExpectations::const_reverse_iterator it = + untyped_expectations_.rbegin(); + it != untyped_expectations_.rend(); ++it) { + TypedExpectation* const exp = + static_cast*>(it->get()); if (exp->ShouldHandleArguments(args)) { return exp; } @@ -1606,41 +1647,29 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { void PrintTriedExpectationsLocked(const ArgumentTuple& args, ::std::ostream* why) const { g_gmock_mutex.AssertHeld(); - const int count = static_cast(expectations_.size()); + const int count = static_cast(untyped_expectations_.size()); *why << "Google Mock tried the following " << count << " " << (count == 1 ? "expectation, but it didn't match" : "expectations, but none matched") << ":\n"; for (int i = 0; i < count; i++) { + TypedExpectation* const expectation = + static_cast*>(untyped_expectations_[i].get()); *why << "\n"; - expectations_[i]->DescribeLocationTo(why); + expectation->DescribeLocationTo(why); if (count > 1) { *why << "tried expectation #" << i << ": "; } - *why << expectations_[i]->source_text() << "...\n"; - expectations_[i]->ExplainMatchResultTo(args, why); - expectations_[i]->DescribeCallCountTo(why); + *why << expectation->source_text() << "...\n"; + expectation->ExplainMatchResultTo(args, why); + expectation->DescribeCallCountTo(why); } } - // Address of the mock object this mock method belongs to. Only - // valid after this mock method has been called or - // ON_CALL/EXPECT_CALL has been invoked on it. - const void* mock_obj_; // Protected by g_gmock_mutex. - - // Name of the function being mocked. Only valid after this mock - // method has been called. - const char* name_; // Protected by g_gmock_mutex. - // The current spec (either default action spec or expectation spec) // being described on this function mocker. MockSpec current_spec_; - // All default action specs for this function mocker. - std::vector > default_actions_; - // All expectations for this function mocker. - TypedExpectations expectations_; - // There is no generally useful and implementable semantics of // copying a mock object, so copying a mock is usually a user error. // Thus we disallow copying function mockers. If the user really @@ -1666,144 +1695,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // satisfied. Reports one or more Google Test non-fatal failures and // returns false if not. // L >= g_gmock_mutex -template -bool FunctionMockerBase::VerifyAndClearExpectationsLocked() { - g_gmock_mutex.AssertHeld(); - bool expectations_met = true; - for (typename TypedExpectations::const_iterator it = expectations_.begin(); - it != expectations_.end(); ++it) { - TypedExpectation* const exp = it->get(); - - if (exp->IsOverSaturated()) { - // There was an upper-bound violation. Since the error was - // already reported when it occurred, there is no need to do - // anything here. - expectations_met = false; - } else if (!exp->IsSatisfied()) { - expectations_met = false; - ::std::stringstream ss; - ss << "Actual function call count doesn't match " - << exp->source_text() << "...\n"; - // No need to show the source file location of the expectation - // in the description, as the Expect() call that follows already - // takes care of it. - exp->MaybeDescribeExtraMatcherTo(&ss); - exp->DescribeCallCountTo(&ss); - Expect(false, exp->file(), exp->line(), ss.str()); - } - } - expectations_.clear(); - return expectations_met; -} // Reports an uninteresting call (whose description is in msg) in the // manner specified by 'reaction'. void ReportUninterestingCall(CallReaction reaction, const string& msg); -// Calculates the result of invoking this mock function with the given -// arguments, prints it, and returns it. -// L < g_gmock_mutex -template -typename Function::Result FunctionMockerBase::InvokeWith( - const typename Function::ArgumentTuple& args) { - typedef ActionResultHolder ResultHolder; - - if (expectations_.size() == 0) { - // No expectation is set on this mock method - we have an - // uninteresting call. - - // We must get Google Mock's reaction on uninteresting calls - // made on this mock object BEFORE performing the action, - // because the action may DELETE the mock object and make the - // following expression meaningless. - const CallReaction reaction = - Mock::GetReactionOnUninterestingCalls(MockObject()); - - // True iff we need to print this call's arguments and return - // value. This definition must be kept in sync with - // the behavior of ReportUninterestingCall(). - const bool need_to_report_uninteresting_call = - // If the user allows this uninteresting call, we print it - // only when he wants informational messages. - reaction == ALLOW ? LogIsVisible(INFO) : - // If the user wants this to be a warning, we print it only - // when he wants to see warnings. - reaction == WARN ? LogIsVisible(WARNING) : - // Otherwise, the user wants this to be an error, and we - // should always print detailed information in the error. - true; - - if (!need_to_report_uninteresting_call) { - // Perform the action without printing the call information. - return PerformDefaultAction(args, ""); - } - - // Warns about the uninteresting call. - ::std::stringstream ss; - DescribeUninterestingCall(args, &ss); - - // Calculates the function result. - const ResultHolder result = - ResultHolder::PerformDefaultAction(this, args, ss.str()); - - // Prints the function result. - result.PrintAsActionResult(&ss); - - ReportUninterestingCall(reaction, ss.str()); - return result.value(); - } - - bool is_excessive = false; - ::std::stringstream ss; - ::std::stringstream why; - ::std::stringstream loc; - Action action; - TypedExpectation* exp; - - // The FindMatchingExpectationAndAction() function acquires and - // releases g_gmock_mutex. - const bool found = FindMatchingExpectationAndAction( - args, &exp, &action, &is_excessive, &ss, &why); - - // True iff we need to print the call's arguments and return value. - // This definition must be kept in sync with the uses of Expect() - // and Log() in this function. - const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO); - if (!need_to_report_call) { - // Perform the action without printing the call information. - return action.IsDoDefault() ? PerformDefaultAction(args, "") : - action.Perform(args); - } - - ss << " Function call: " << Name(); - UniversalPrint(args, &ss); - - // In case the action deletes a piece of the expectation, we - // generate the message beforehand. - if (found && !is_excessive) { - exp->DescribeLocationTo(&loc); - } - - const ResultHolder result = action.IsDoDefault() ? - ResultHolder::PerformDefaultAction(this, args, ss.str()) : - ResultHolder::PerformAction(action, args); - result.PrintAsActionResult(&ss); - ss << "\n" << why.str(); - - if (!found) { - // No expectation matches this call - reports a failure. - Expect(false, NULL, -1, ss.str()); - } else if (is_excessive) { - // We had an upper-bound violation and the failure message is in ss. - Expect(false, exp->file(), exp->line(), ss.str()); - } else { - // We had an expected call and the matching expectation is - // described in ss. - Log(INFO, loc.str() + ss.str(), 2); - } - return result.value(); -} - } // namespace internal // The style guide prohibits "using" statements in a namespace scope diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index f7932b5e..ab923efb 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -261,8 +261,8 @@ def _IncompleteByReferenceArgumentDiagnoser(msg): r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation of member function ' - r'\'testing::internal::FunctionMocker<.*>::Invoke\' ' - r'requested here') + r'\'testing::internal2::TypeWithoutFormatter<.*>::' + r'PrintValue\' requested here') diagnosis = """ In order to mock this function, Google Mock needs to see the definition of type "%(type)s" - declaration alone is not enough. Either #include diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 0d40d9cd..a99caef2 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -55,6 +55,15 @@ namespace internal { // mockers, and all expectations. GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex); +// Logs a message including file and line number information. +void LogWithLocation(testing::internal::LogSeverity severity, + const char* file, int line, + const string& message) { + ::std::ostringstream s; + s << file << ":" << line << ": " << message << ::std::endl; + Log(severity, s.str(), 0); +} + // Constructs an ExpectationBase object. ExpectationBase::ExpectationBase(const char* a_file, int a_line, @@ -65,8 +74,12 @@ ExpectationBase::ExpectationBase(const char* a_file, cardinality_specified_(false), cardinality_(Exactly(1)), call_count_(0), - retired_(false) { -} + retired_(false), + extra_matcher_specified_(false), + repeated_action_specified_(false), + retires_on_saturation_(false), + last_clause_(kNone), + action_count_checked_(false) {} // Destructs an ExpectationBase object. ExpectationBase::~ExpectationBase() {} @@ -132,6 +145,99 @@ void ExpectationBase::FindUnsatisfiedPrerequisites( } } +// Describes how many times a function call matching this +// expectation has occurred. +// L >= g_gmock_mutex +void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const { + g_gmock_mutex.AssertHeld(); + + // Describes how many times the function is expected to be called. + *os << " Expected: to be "; + cardinality().DescribeTo(os); + *os << "\n Actual: "; + Cardinality::DescribeActualCallCountTo(call_count(), os); + + // Describes the state of the expectation (e.g. is it satisfied? + // is it active?). + *os << " - " << (IsOverSaturated() ? "over-saturated" : + IsSaturated() ? "saturated" : + IsSatisfied() ? "satisfied" : "unsatisfied") + << " and " + << (is_retired() ? "retired" : "active"); +} + +// Checks the action count (i.e. the number of WillOnce() and +// WillRepeatedly() clauses) against the cardinality if this hasn't +// been done before. Prints a warning if there are too many or too +// few actions. +// L < mutex_ +void ExpectationBase::CheckActionCountIfNotDone() const { + bool should_check = false; + { + MutexLock l(&mutex_); + if (!action_count_checked_) { + action_count_checked_ = true; + should_check = true; + } + } + + if (should_check) { + if (!cardinality_specified_) { + // The cardinality was inferred - no need to check the action + // count against it. + return; + } + + // The cardinality was explicitly specified. + const int action_count = static_cast(untyped_actions_.size()); + const int upper_bound = cardinality().ConservativeUpperBound(); + const int lower_bound = cardinality().ConservativeLowerBound(); + bool too_many; // True if there are too many actions, or false + // if there are too few. + if (action_count > upper_bound || + (action_count == upper_bound && repeated_action_specified_)) { + too_many = true; + } else if (0 < action_count && action_count < lower_bound && + !repeated_action_specified_) { + too_many = false; + } else { + return; + } + + ::std::stringstream ss; + DescribeLocationTo(&ss); + ss << "Too " << (too_many ? "many" : "few") + << " actions specified in " << source_text() << "...\n" + << "Expected to be "; + cardinality().DescribeTo(&ss); + ss << ", but has " << (too_many ? "" : "only ") + << action_count << " WillOnce()" + << (action_count == 1 ? "" : "s"); + if (repeated_action_specified_) { + ss << " and a WillRepeatedly()"; + } + ss << "."; + Log(WARNING, ss.str(), -1); // -1 means "don't print stack trace". + } +} + +// Implements the .Times() clause. +void ExpectationBase::UntypedTimes(const Cardinality& a_cardinality) { + if (last_clause_ == kTimes) { + ExpectSpecProperty(false, + ".Times() cannot appear " + "more than once in an EXPECT_CALL()."); + } else { + ExpectSpecProperty(last_clause_ < kTimes, + ".Times() cannot appear after " + ".InSequence(), .WillOnce(), .WillRepeatedly(), " + "or .RetiresOnSaturation()."); + } + last_clause_ = kTimes; + + SpecifyCardinality(a_cardinality); +} + // Points to the implicit sequence introduced by a living InSequence // object (if any) in the current thread or NULL. ThreadLocal g_gmock_implicit_sequence; @@ -151,6 +257,233 @@ void ReportUninterestingCall(CallReaction reaction, const string& msg) { } } +UntypedFunctionMockerBase::UntypedFunctionMockerBase() + : mock_obj_(NULL), name_("") {} + +UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {} + +// Sets the mock object this mock method belongs to, and registers +// this information in the global mock registry. Will be called +// whenever an EXPECT_CALL() or ON_CALL() is executed on this mock +// method. +// L < g_gmock_mutex +void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj) { + { + MutexLock l(&g_gmock_mutex); + mock_obj_ = mock_obj; + } + Mock::Register(mock_obj, this); +} + +// Sets the mock object this mock method belongs to, and sets the name +// of the mock function. Will be called upon each invocation of this +// mock function. +// L < g_gmock_mutex +void UntypedFunctionMockerBase::SetOwnerAndName( + const void* mock_obj, const char* name) { + // We protect name_ under g_gmock_mutex in case this mock function + // is called from two threads concurrently. + MutexLock l(&g_gmock_mutex); + mock_obj_ = mock_obj; + name_ = name; +} + +// Returns the name of the function being mocked. Must be called +// after RegisterOwner() or SetOwnerAndName() has been called. +// L < g_gmock_mutex +const void* UntypedFunctionMockerBase::MockObject() const { + const void* mock_obj; + { + // We protect mock_obj_ under g_gmock_mutex in case this mock + // function is called from two threads concurrently. + MutexLock l(&g_gmock_mutex); + Assert(mock_obj_ != NULL, __FILE__, __LINE__, + "MockObject() must not be called before RegisterOwner() or " + "SetOwnerAndName() has been called."); + mock_obj = mock_obj_; + } + return mock_obj; +} + +// Returns the name of this mock method. Must be called after +// SetOwnerAndName() has been called. +// L < g_gmock_mutex +const char* UntypedFunctionMockerBase::Name() const { + const char* name; + { + // We protect name_ under g_gmock_mutex in case this mock + // function is called from two threads concurrently. + MutexLock l(&g_gmock_mutex); + Assert(name_ != NULL, __FILE__, __LINE__, + "Name() must not be called before SetOwnerAndName() has " + "been called."); + name = name_; + } + return name; +} + +// Calculates the result of invoking this mock function with the given +// arguments, prints it, and returns it. The caller is responsible +// for deleting the result. +// L < g_gmock_mutex +const UntypedActionResultHolderBase* +UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) { + if (untyped_expectations_.size() == 0) { + // No expectation is set on this mock method - we have an + // uninteresting call. + + // We must get Google Mock's reaction on uninteresting calls + // made on this mock object BEFORE performing the action, + // because the action may DELETE the mock object and make the + // following expression meaningless. + const CallReaction reaction = + Mock::GetReactionOnUninterestingCalls(MockObject()); + + // True iff we need to print this call's arguments and return + // value. This definition must be kept in sync with + // the behavior of ReportUninterestingCall(). + const bool need_to_report_uninteresting_call = + // If the user allows this uninteresting call, we print it + // only when he wants informational messages. + reaction == ALLOW ? LogIsVisible(INFO) : + // If the user wants this to be a warning, we print it only + // when he wants to see warnings. + reaction == WARN ? LogIsVisible(WARNING) : + // Otherwise, the user wants this to be an error, and we + // should always print detailed information in the error. + true; + + if (!need_to_report_uninteresting_call) { + // Perform the action without printing the call information. + return this->UntypedPerformDefaultAction(untyped_args, ""); + } + + // Warns about the uninteresting call. + ::std::stringstream ss; + this->UntypedDescribeUninterestingCall(untyped_args, &ss); + + // Calculates the function result. + const UntypedActionResultHolderBase* const result = + this->UntypedPerformDefaultAction(untyped_args, ss.str()); + + // Prints the function result. + if (result != NULL) + result->PrintAsActionResult(&ss); + + ReportUninterestingCall(reaction, ss.str()); + return result; + } + + bool is_excessive = false; + ::std::stringstream ss; + ::std::stringstream why; + ::std::stringstream loc; + const void* untyped_action = NULL; + + // The UntypedFindMatchingExpectation() function acquires and + // releases g_gmock_mutex. + const ExpectationBase* const untyped_expectation = + this->UntypedFindMatchingExpectation( + untyped_args, &untyped_action, &is_excessive, + &ss, &why); + const bool found = untyped_expectation != NULL; + + // True iff we need to print the call's arguments and return value. + // This definition must be kept in sync with the uses of Expect() + // and Log() in this function. + const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO); + if (!need_to_report_call) { + // Perform the action without printing the call information. + return + untyped_action == NULL ? + this->UntypedPerformDefaultAction(untyped_args, "") : + this->UntypedPerformAction(untyped_action, untyped_args); + } + + ss << " Function call: " << Name(); + this->UntypedPrintArgs(untyped_args, &ss); + + // In case the action deletes a piece of the expectation, we + // generate the message beforehand. + if (found && !is_excessive) { + untyped_expectation->DescribeLocationTo(&loc); + } + + const UntypedActionResultHolderBase* const result = + untyped_action == NULL ? + this->UntypedPerformDefaultAction(untyped_args, ss.str()) : + this->UntypedPerformAction(untyped_action, untyped_args); + if (result != NULL) + result->PrintAsActionResult(&ss); + ss << "\n" << why.str(); + + if (!found) { + // No expectation matches this call - reports a failure. + Expect(false, NULL, -1, ss.str()); + } else if (is_excessive) { + // We had an upper-bound violation and the failure message is in ss. + Expect(false, untyped_expectation->file(), + untyped_expectation->line(), ss.str()); + } else { + // We had an expected call and the matching expectation is + // described in ss. + Log(INFO, loc.str() + ss.str(), 2); + } + + return result; +} + +// Returns an Expectation object that references and co-owns exp, +// which must be an expectation on this mock function. +Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) { + for (UntypedExpectations::const_iterator it = + untyped_expectations_.begin(); + it != untyped_expectations_.end(); ++it) { + if (it->get() == exp) { + return Expectation(*it); + } + } + + Assert(false, __FILE__, __LINE__, "Cannot find expectation."); + return Expectation(); + // The above statement is just to make the code compile, and will + // never be executed. +} + +// Verifies that all expectations on this mock function have been +// satisfied. Reports one or more Google Test non-fatal failures +// and returns false if not. +// L >= g_gmock_mutex +bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked() { + g_gmock_mutex.AssertHeld(); + bool expectations_met = true; + for (UntypedExpectations::const_iterator it = + untyped_expectations_.begin(); + it != untyped_expectations_.end(); ++it) { + ExpectationBase* const untyped_expectation = it->get(); + if (untyped_expectation->IsOverSaturated()) { + // There was an upper-bound violation. Since the error was + // already reported when it occurred, there is no need to do + // anything here. + expectations_met = false; + } else if (!untyped_expectation->IsSatisfied()) { + expectations_met = false; + ::std::stringstream ss; + ss << "Actual function call count doesn't match " + << untyped_expectation->source_text() << "...\n"; + // No need to show the source file location of the expectation + // in the description, as the Expect() call that follows already + // takes care of it. + untyped_expectation->MaybeDescribeExtraMatcherTo(&ss); + untyped_expectation->DescribeCallCountTo(&ss); + Expect(false, untyped_expectation->file(), + untyped_expectation->line(), ss.str()); + } + } + untyped_expectations_.clear(); + return expectations_met; +} + } // namespace internal // Class Mock. @@ -190,7 +523,6 @@ class MockObjectRegistry { // object alive. Therefore we report any living object as test // failure, unless the user explicitly asked us to ignore it. ~MockObjectRegistry() { - // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is // a macro. diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index e12402b9..b3f8d52b 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -334,8 +334,7 @@ class MyActionImpl : public ActionInterface { TEST(ActionInterfaceTest, CanBeImplementedByDefiningPerform) { MyActionImpl my_action_impl; - - EXPECT_FALSE(my_action_impl.IsDoDefault()); + (void)my_action_impl; } TEST(ActionInterfaceTest, MakeAction) { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 737bcfff..aea5228b 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -103,6 +103,34 @@ using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; #endif +class Incomplete; + +class MockIncomplete { + public: + // This line verifies that a mock method can take a by-reference + // argument of an incomplete type. + MOCK_METHOD1(ByRefFunc, void(const Incomplete& x)); +}; + +// Tells Google Mock how to print a value of type Incomplete. +void PrintTo(const Incomplete& x, ::std::ostream* os); + +TEST(MockMethodTest, CanInstantiateWithIncompleteArgType) { + // Even though this mock class contains a mock method that takes + // by-reference an argument whose type is incomplete, we can still + // use the mock, as long as Google Mock knows how to print the + // argument. + MockIncomplete incomplete; + EXPECT_CALL(incomplete, ByRefFunc(_)) + .Times(AnyNumber()); +} + +// The definition of the printer for the argument type doesn't have to +// be visible where the mock is used. +void PrintTo(const Incomplete& /* x */, ::std::ostream* os) { + *os << "incomplete"; +} + class Result {}; class MockA { @@ -1327,12 +1355,33 @@ TEST(SequenceTest, Retirement) { TEST(ExpectationTest, ConstrutorsWork) { MockA a; Expectation e1; // Default ctor. - Expectation e2 = EXPECT_CALL(a, DoA(1)); // Ctor from EXPECT_CALL. - Expectation e3 = e2; // Copy ctor. + + // Ctor from various forms of EXPECT_CALL. + Expectation e2 = EXPECT_CALL(a, DoA(2)); + Expectation e3 = EXPECT_CALL(a, DoA(3)).With(_); + { + Sequence s; + Expectation e4 = EXPECT_CALL(a, DoA(4)).Times(1); + Expectation e5 = EXPECT_CALL(a, DoA(5)).InSequence(s); + } + Expectation e6 = EXPECT_CALL(a, DoA(6)).After(e2); + Expectation e7 = EXPECT_CALL(a, DoA(7)).WillOnce(Return()); + Expectation e8 = EXPECT_CALL(a, DoA(8)).WillRepeatedly(Return()); + Expectation e9 = EXPECT_CALL(a, DoA(9)).RetiresOnSaturation(); + + Expectation e10 = e2; // Copy ctor. EXPECT_THAT(e1, Ne(e2)); - EXPECT_THAT(e2, Eq(e3)); - a.DoA(1); + EXPECT_THAT(e2, Eq(e10)); + + a.DoA(2); + a.DoA(3); + a.DoA(4); + a.DoA(5); + a.DoA(6); + a.DoA(7); + a.DoA(8); + a.DoA(9); } TEST(ExpectationTest, AssignmentWorks) { -- cgit v1.2.3 From 658ac0b71a350cc833ee4520536b6c4964c7b944 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Feb 2011 07:29:13 +0000 Subject: Indents preprocessor directives. --- include/gmock/gmock-actions.h | 2 +- include/gmock/gmock-generated-actions.h | 6 +++--- include/gmock/gmock-generated-actions.h.pump | 6 +++--- include/gmock/gmock-matchers.h | 6 +++--- include/gmock/gmock-more-actions.h | 26 +++++++++++++------------- include/gmock/gmock-spec-builders.h | 6 +++--- include/gmock/internal/gmock-internal-utils.h | 5 +++-- include/gmock/internal/gmock-port.h | 2 +- src/gmock-spec-builders.cc | 2 +- src/gmock_main.cc | 2 +- test/gmock-generated-actions_test.cc | 6 +++--- test/gmock-generated-function-mockers_test.cc | 4 ++-- test/gmock-generated-matchers_test.cc | 6 +++--- test/gmock-internal-utils_test.cc | 11 +++++++---- test/gmock-spec-builders_test.cc | 19 +++++++++++-------- test/gmock_link_test.h | 8 ++++---- 16 files changed, 62 insertions(+), 55 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index af3483f7..cfd5850e 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -40,7 +40,7 @@ #include #ifndef _WIN32_WCE -#include +# include #endif #include "gmock/internal/gmock-internal-utils.h" diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 6ab014dd..635bb595 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -2228,8 +2228,8 @@ namespace testing { // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif // Various overloads for InvokeArgument(). @@ -2411,7 +2411,7 @@ ACTION_TEMPLATE(ReturnNew, } #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif } // namespace testing diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 4d7c5cee..001fd7d0 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -751,8 +751,8 @@ namespace testing { // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif // Various overloads for InvokeArgument(). @@ -817,7 +817,7 @@ ACTION_TEMPLATE(ReturnNew, ]] #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif } // namespace testing diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 86c3db73..dfb72599 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1394,12 +1394,12 @@ class TrulyMatcher { MatchResultListener* /* listener */) const { #if GTEST_OS_WINDOWS // MSVC warns about converting a value into bool (warning 4800). -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4800) // Temporarily disables warning 4800. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4800) // Temporarily disables warning 4800. #endif // GTEST_OS_WINDOWS return predicate_(x); #if GTEST_OS_WINDOWS -#pragma warning(pop) // Restores the warning state. +# pragma warning(pop) // Restores the warning state. #endif // GTEST_OS_WINDOWS } diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index a547a648..fc5e5ca8 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -136,8 +136,8 @@ WithArg(const InnerAction& action) { // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif // Action ReturnArg() returns the k-th argument of the mock function. @@ -188,12 +188,12 @@ ACTION_TEMPLATE(SetArrayArgument, // Microsoft compiler deprecates ::std::copy, so we want to suppress warning // 4996 (Function call with parameters that may be unsafe) there. #ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. #endif ::std::copy(first, last, ::std::tr1::get(args)); #ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. +# pragma warning(pop) // Restores the warning state. #endif } @@ -213,19 +213,19 @@ ACTION_P(ReturnPointee, pointer) { return *pointer; } #if GTEST_HAS_EXCEPTIONS // Suppresses the 'unreachable code' warning that VC generates in opt modes. -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4702) // Temporarily disables warning 4702. -#endif +# ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4702) // Temporarily disables warning 4702. +# endif ACTION_P(Throw, exception) { throw exception; } -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif +# ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +# endif #endif // GTEST_HAS_EXCEPTIONS #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif } // namespace testing diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 9e185085..6ae807a2 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1279,8 +1279,8 @@ class MockSpec { // the constructor only. #ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4355) // Temporarily disables warning 4355. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355. #endif // _MSV_VER // C++ treats the void type specially. For example, you cannot define @@ -1686,7 +1686,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { }; // class FunctionMockerBase #ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. +# pragma warning(pop) // Restores the warning state. #endif // _MSV_VER // Implements methods of FunctionMockerBase. diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 7aaf6de5..48fadba2 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -101,7 +101,7 @@ struct LinkedPtrLessThan { (defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)) // wchar_t is a typedef. #else -#define GMOCK_WCHAR_T_IS_NATIVE_ 1 +# define GMOCK_WCHAR_T_IS_NATIVE_ 1 #endif // signed wchar_t and unsigned wchar_t are NOT in the C++ standard. @@ -114,7 +114,8 @@ struct LinkedPtrLessThan { // To gcc, // wchar_t == signed wchar_t != unsigned wchar_t == unsigned int #ifdef __GNUC__ -#define GMOCK_HAS_SIGNED_WCHAR_T_ 1 // signed/unsigned wchar_t are valid types. +// signed/unsigned wchar_t are valid types. +# define GMOCK_HAS_SIGNED_WCHAR_T_ 1 #endif // In what follows, we use the term "kind" to indicate whether a type diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index bb3f5838..3b9cc479 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -53,7 +53,7 @@ // For MS Visual C++, check the compiler version. At least VS 2003 is // required to compile Google Mock. #if defined(_MSC_VER) && _MSC_VER < 1310 -#error "At least Visual C++ 2003 (7.1) is required to compile Google Mock." +# error "At least Visual C++ 2003 (7.1) is required to compile Google Mock." #endif // Macro for referencing flags. This is public as we want the user to diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index a99caef2..aa33cc44 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -45,7 +45,7 @@ #include "gtest/gtest.h" #if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC -#include // NOLINT +# include // NOLINT #endif namespace testing { diff --git a/src/gmock_main.cc b/src/gmock_main.cc index 3725ae72..9d8aea22 100644 --- a/src/gmock_main.cc +++ b/src/gmock_main.cc @@ -39,7 +39,7 @@ // Windows. See the following link to track the current status of this bug: // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=394464 // NOLINT #if GTEST_OS_WINDOWS_MOBILE -#include // NOLINT +# include // NOLINT int _tmain(int argc, TCHAR** argv) { #else diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 982be1b9..436f1a2e 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -593,8 +593,8 @@ TEST(DoAllTest, TenActions) { // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif // Tests the ACTION*() macro family. @@ -1205,7 +1205,7 @@ TEST(ActionTemplateTest, CanBeOverloadedOnNumberOfValueParameters) { } #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif } // namespace gmock_generated_actions_test diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index d000386d..0d90ded7 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -44,14 +44,14 @@ // MSDN says the header file to be included for STDMETHOD is BaseTyps.h but // we are getting compiler errors if we use basetyps.h, hence including // objbase.h for definition of STDMETHOD. -#include +# include #endif // GTEST_OS_WINDOWS // There is a bug in MSVC (fixed in VS 2008) that prevents creating a // mock for a function with const arguments, so we don't test such // cases for MSVC versions older than 2008. #if !GTEST_OS_WINDOWS || (_MSC_VER >= 1500) -#define GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS +# define GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS #endif // !GTEST_OS_WINDOWS || (_MSC_VER >= 1500) namespace testing { diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 2a7f498a..5e18471d 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -144,8 +144,8 @@ TEST(ArgsTest, AcceptsDecreasingTemplateArgs) { // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif MATCHER(SumIsZero, "") { @@ -1092,7 +1092,7 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { } #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif } // namespace diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 5b0e8043..ae743c1c 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -45,7 +45,7 @@ #include "gtest/gtest-spi.h" #if GTEST_OS_CYGWIN -#include // For ssize_t. NOLINT +# include // For ssize_t. NOLINT #endif class ProtocolMessage; @@ -416,18 +416,21 @@ TEST(LogTest, NoSkippingStackFrameInOptMode) { CaptureStdout(); Log(WARNING, "Test log.\n", 100); const String log = GetCapturedStdout(); -#if defined(NDEBUG) && GTEST_GOOGLE3_MODE_ + +# if defined(NDEBUG) && GTEST_GOOGLE3_MODE_ + // In opt mode, no stack frame should be skipped. EXPECT_THAT(log, ContainsRegex("\nGMOCK WARNING:\n" "Test log\\.\n" "Stack trace:\n" ".+")); -#else +# else + // In dbg mode, the stack frames should be skipped. EXPECT_STREQ("\nGMOCK WARNING:\n" "Test log.\n" "Stack trace:\n", log.c_str()); -#endif +# endif } // Tests that all logs are printed when the value of the diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index aea5228b..29d47d12 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1717,14 +1717,14 @@ TEST(DeletingMockEarlyTest, Success2) { // Suppresses warning on unreferenced formal parameter in MSVC with // -W4. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif ACTION_P(Delete, ptr) { delete ptr; } #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif TEST(DeletingMockEarlyTest, CanDeleteSelfInActionReturningVoid) { @@ -1890,7 +1890,9 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { const String output = GetCapturedStdout(); EXPECT_PRED_FORMAT2(IsSubstring, "GMOCK WARNING", output); EXPECT_PRED_FORMAT2(IsSubstring, "Stack trace:", output); -#ifndef NDEBUG + +# ifndef NDEBUG + // We check the stack trace content in dbg-mode only, as opt-mode // may inline the call we are interested in seeing. @@ -1904,7 +1906,8 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { c.NonVoidMethod(); const String output2 = GetCapturedStdout(); EXPECT_PRED_FORMAT2(IsSubstring, "NonVoidMethod(", output2); -#endif // NDEBUG + +# endif // NDEBUG } // Tests that an uninteresting mock function call causes the function @@ -1949,14 +1952,14 @@ class GMockVerboseFlagTest : public VerboseFlagPreservingFixture { const string& function_name) { if (should_print) { EXPECT_THAT(output.c_str(), HasSubstr(expected_substring)); -#ifndef NDEBUG +# ifndef NDEBUG // We check the stack trace content in dbg-mode only, as opt-mode // may inline the call we are interested in seeing. EXPECT_THAT(output.c_str(), HasSubstr(function_name)); -#else +# else // Suppresses 'unused function parameter' warnings. static_cast(function_name); -#endif // NDEBUG +# endif // NDEBUG } else { EXPECT_STREQ("", output.c_str()); } diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index 499cc186..ab5af4b4 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -117,7 +117,7 @@ #include "gmock/gmock.h" #if !GTEST_OS_WINDOWS_MOBILE -#include +# include #endif #include "gmock/internal/gmock-port.h" @@ -419,8 +419,8 @@ TEST(LinkTest, TestThrow) { // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4100) +# pragma warning(push) +# pragma warning(disable:4100) #endif // Tests the linkage of actions created using ACTION macro. @@ -455,7 +455,7 @@ ACTION_P2(ReturnEqualsEitherOf, first, second) { } #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif TEST(LinkTest, TestActionP2Macro) { -- cgit v1.2.3 From 79d82b6ef75c470e1bc2fd61a8cfd1671ca19aee Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Feb 2011 07:31:48 +0000 Subject: Changes gmock's version to 1.6.0 and adds release notes. --- CHANGES | 23 +++++++++++++++++++++++ configure.ac | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 21ab4882..80a01d4a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,26 @@ +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(). +* 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 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 diff --git a/configure.ac b/configure.ac index 8498a6c5..e8b65bdc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ m4_include(gtest/m4/acx_pthread.m4) AC_INIT([Google C++ Mocking Framework], - [1.5.0], + [1.6.0], [googlemock@googlegroups.com], [gmock]) @@ -101,7 +101,7 @@ AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" -GTEST_MIN_VERSION="1.5.0" +GTEST_MIN_VERSION="1.6.0" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. -- cgit v1.2.3 From 62a35fbc5d316c4f82f37cb6e183eb8de210a94c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 24 Feb 2011 21:59:54 +0000 Subject: Adds CMake scripts to gmock's release package. --- CHANGES | 1 + Makefile.am | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 80a01d4a..ba7cfc41 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ Changes for 1.6.0: 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. diff --git a/Makefile.am b/Makefile.am index e02c07e1..cf7dee92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -153,6 +153,10 @@ EXTRA_DIST += \ scripts/generator/cpp/utils.py \ scripts/generator/gmock_gen.py +# CMake scripts. +EXTRA_DIST += \ + CMakeLists.txt + # Microsoft Visual Studio 2005 projects. EXTRA_DIST += \ msvc/2005/gmock.sln \ -- cgit v1.2.3 From fc8c6c479a5250b709ed7b4406e025439037e18e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 9 Mar 2011 01:18:08 +0000 Subject: Disables SetArgPointee("string literal") for GCC 4.0- and Symbian, and adds support for SetArgPointee(L"wide string literal") -- by Vlad Losev. --- include/gmock/gmock-actions.h | 14 ++++++++++++ test/gmock-actions_test.cc | 51 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index cfd5850e..d6a3e148 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -981,7 +981,11 @@ 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 > @@ -989,6 +993,16 @@ 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< diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index b3f8d52b..b7803fe9 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -714,23 +714,44 @@ TEST(SetArgPointeeTest, SetsTheNthPointee) { EXPECT_EQ('a', ch); } +#if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN) // Tests that SetArgPointee() accepts a string literal. +// GCC prior to v4.0 and the Symbian compiler do not support this. TEST(SetArgPointeeTest, AcceptsStringLiteral) { - typedef void MyFunction(bool, std::string*, const char**); - Action a = SetArgPointee<1>("hi"); + typedef void MyFunction(std::string*, const char**); + Action a = SetArgPointee<0>("hi"); std::string str; const char* ptr = NULL; - a.Perform(make_tuple(true, &str, &ptr)); + a.Perform(make_tuple(&str, &ptr)); EXPECT_EQ("hi", str); EXPECT_TRUE(ptr == NULL); - a = SetArgPointee<2>("world"); + a = SetArgPointee<1>("world"); str = ""; - a.Perform(make_tuple(true, &str, &ptr)); + a.Perform(make_tuple(&str, &ptr)); EXPECT_EQ("", str); EXPECT_STREQ("world", ptr); } +TEST(SetArgPointeeTest, AcceptsWideStringLiteral) { + typedef void MyFunction(const wchar_t**); + Action a = SetArgPointee<0>(L"world"); + const wchar_t* ptr = NULL; + a.Perform(make_tuple(&ptr)); + EXPECT_STREQ(L"world", ptr); + +# if GTEST_HAS_STD_WSTRING + + typedef void MyStringFunction(std::wstring*); + Action a2 = SetArgPointee<0>(L"world"); + std::wstring str = L""; + a2.Perform(make_tuple(&str)); + EXPECT_EQ(L"world", str); + +# endif +} +#endif + // Tests that SetArgPointee() accepts a char pointer. TEST(SetArgPointeeTest, AcceptsCharPointer) { typedef void MyFunction(bool, std::string*, const char**); @@ -751,6 +772,26 @@ TEST(SetArgPointeeTest, AcceptsCharPointer) { EXPECT_EQ(world, ptr); } +TEST(SetArgPointeeTest, AcceptsWideCharPointer) { + typedef void MyFunction(bool, const wchar_t**); + const wchar_t* const hi = L"hi"; + Action a = SetArgPointee<1>(hi); + const wchar_t* ptr = NULL; + a.Perform(make_tuple(true, &ptr)); + EXPECT_EQ(hi, ptr); + +# if GTEST_HAS_STD_WSTRING + + typedef void MyStringFunction(bool, std::wstring*); + wchar_t world_array[] = L"world"; + wchar_t* const world = world_array; + Action a2 = SetArgPointee<1>(world); + std::wstring str; + a2.Perform(make_tuple(true, &str)); + EXPECT_EQ(world_array, str); +# endif +} + #if GTEST_HAS_PROTOBUF_ // Tests that SetArgPointee(proto_buffer) sets the v1 protobuf -- cgit v1.2.3 From 86d2eeb1120a330cec8396aee97914dae909e237 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 16 Mar 2011 17:10:39 +0000 Subject: Prevents ADL in AllOf() and AnyOf() (by Manuel Klimek). --- include/gmock/gmock-generated-matchers.h | 39 ++++++++++++++------------- include/gmock/gmock-generated-matchers.h.pump | 8 +++--- test/gmock-generated-matchers_test.cc | 29 ++++++++++++++++++++ 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 68af306b..6feaf1a2 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -850,7 +850,7 @@ ElementsAreArray(const T (&array)[N]) { } // AllOf(m1, m2, ..., mk) matches any value that matches all of the given -// sub-matchers. +// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. template inline internal::BothOfMatcher @@ -862,7 +862,7 @@ template inline internal::BothOfMatcher > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { - return AllOf(m1, AllOf(m2, m3)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3)); } template > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { - return AllOf(m1, AllOf(m2, m3, m4)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4)); } template > > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { - return AllOf(m1, AllOf(m2, m3, m4, m5)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5)); } template > > > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6) { - return AllOf(m1, AllOf(m2, m3, m4, m5, m6)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6)); } template > > > > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7) { - return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7)); } template > > > > > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7, Matcher8 m8) { - return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7, m8)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7, m8)); } template > > > > > > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9) { - return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7, m8, m9)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7, m8, m9)); } template > > > > > > > > AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9, Matcher10 m10) { - return AllOf(m1, AllOf(m2, m3, m4, m5, m6, m7, m8, m9, m10)); + return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7, m8, m9, + m10)); } // AnyOf(m1, m2, ..., mk) matches any value that matches any of the given -// sub-matchers. +// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. template inline internal::EitherOfMatcher @@ -954,7 +955,7 @@ template inline internal::EitherOfMatcher > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { - return AnyOf(m1, AnyOf(m2, m3)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3)); } template > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { - return AnyOf(m1, AnyOf(m2, m3, m4)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4)); } template > > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5)); } template > > > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6)); } template > > > > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7)); } template > > > > > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7, Matcher8 m8) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7, m8)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7, m8)); } template > > > > > > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7, m8, m9)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7, m8, m9)); } template > > > > > > > > AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9, Matcher10 m10) { - return AnyOf(m1, AnyOf(m2, m3, m4, m5, m6, m7, m8, m9, m10)); + return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7, m8, m9, + m10)); } } // namespace testing + // The MATCHER* family of macros can be used in a namespace scope to // define custom matchers easily. // diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index cebdd0e6..8c09444c 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -303,7 +303,7 @@ ElementsAreArray(const T (&array)[N]) { } // AllOf(m1, m2, ..., mk) matches any value that matches all of the given -// sub-matchers. +// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. $range i 2..n $for i [[ @@ -318,7 +318,7 @@ AllOf($for j, [[Matcher$j m$j]]) { $if i == 2 [[ return internal::BothOfMatcher(m1, m2); ]] $else [[ - return AllOf(m1, AllOf($for k, [[m$(k + 1)]])); + return ::testing::AllOf(m1, ::testing::AllOf($for k, [[m$(k + 1)]])); ]] } @@ -326,7 +326,7 @@ $if i == 2 [[ ]] // AnyOf(m1, m2, ..., mk) matches any value that matches any of the given -// sub-matchers. +// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. $range i 2..n $for i [[ @@ -341,7 +341,7 @@ AnyOf($for j, [[Matcher$j m$j]]) { $if i == 2 [[ return internal::EitherOfMatcher(m1, m2); ]] $else [[ - return AnyOf(m1, AnyOf($for k, [[m$(k + 1)]])); + return ::testing::AnyOf(m1, ::testing::AnyOf($for k, [[m$(k + 1)]])); ]] } diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 5e18471d..819f1a83 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -1091,6 +1091,35 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { EXPECT_THAT(a, Contains(Not(Contains(5)))); } +namespace adl_test { + +// Verifies that the implementation of ::testing::AllOf and ::testing::AnyOf +// don't issue unqualified recursive calls. If they do, the argument dependent +// name lookup will cause AllOf/AnyOf in the 'adl_test' namespace to be found +// as a candidate and the compilation will break due to an ambiguous overload. + +// The matcher must be in the same namespace as AllOf/AnyOf to make argument +// dependent lookup find those. +MATCHER(M, "") { return true; } + +template +bool AllOf(const T1& t1, const T2& t2) { return true; } + +TEST(AllOfTest, DoesNotCallAllOfUnqualified) { + EXPECT_THAT(42, testing::AllOf( + M(), M(), M(), M(), M(), M(), M(), M(), M(), M())); +} + +template bool +AnyOf(const T1& t1, const T2& t2) { return true; } + +TEST(AnyOfTest, DoesNotCallAnyOfUnqualified) { + EXPECT_THAT(42, testing::AnyOf( + M(), M(), M(), M(), M(), M(), M(), M(), M(), M())); +} + +} // namespace adl_test + #ifdef _MSC_VER # pragma warning(pop) #endif -- cgit v1.2.3 From 71d08627a373895c2dad99c8e88d9c33f7e31a17 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 29 Mar 2011 22:29:51 +0000 Subject: Fixes Google Mock Doctor affected by the latest tweaks to Clang. --- scripts/gmock_doctor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index ab923efb..afd59101 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -463,7 +463,7 @@ def _TypeInTemplatedBaseDiagnoser(msg): _CLANG_FILE_LINE_RE + r'error: use of undeclared identifier \'(?P.*)\'\n' r'(.*\n)*?' - r'(?P=file):(?P=line):(?P=column): error: ' + r'(?P=file):(?P=line):\d+: error: ' r'non-friend class member \'Result\' cannot have a qualified name' ) clang_regex_type_of_a_param = ( -- cgit v1.2.3 From aa43220fe5d34f7283f3a55e11dda5e3f25e5632 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 1 Apr 2011 21:58:42 +0000 Subject: Changes diagnostic output of the question mark from '\?' to '?'. --- test/gmock-matchers_test.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index deff9b23..6f93fbd7 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -1004,8 +1004,8 @@ TEST(StrEqTest, MatchesEqualString) { } TEST(StrEqTest, CanDescribeSelf) { - Matcher m = StrEq("Hi-\'\"\?\\\a\b\f\n\r\t\v\xD3"); - EXPECT_EQ("is equal to \"Hi-\'\\\"\\?\\\\\\a\\b\\f\\n\\r\\t\\v\\xD3\"", + Matcher m = StrEq("Hi-\'\"?\\\a\b\f\n\r\t\v\xD3"); + EXPECT_EQ("is equal to \"Hi-\'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\xD3\"", Describe(m)); string str("01204500800"); @@ -1393,8 +1393,8 @@ TEST(StdWideStrEqTest, MatchesEqual) { } TEST(StdWideStrEqTest, CanDescribeSelf) { - Matcher< ::std::wstring> m = StrEq(L"Hi-\'\"\?\\\a\b\f\n\r\t\v"); - EXPECT_EQ("is equal to L\"Hi-\'\\\"\\?\\\\\\a\\b\\f\\n\\r\\t\\v\"", + Matcher< ::std::wstring> m = StrEq(L"Hi-\'\"?\\\a\b\f\n\r\t\v"); + EXPECT_EQ("is equal to L\"Hi-\'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\"", Describe(m)); Matcher< ::std::wstring> m2 = StrEq(L"\xD3\x576\x8D3\xC74D"); @@ -1584,8 +1584,8 @@ TEST(GlobalWideStrEqTest, MatchesEqual) { } TEST(GlobalWideStrEqTest, CanDescribeSelf) { - Matcher< ::wstring> m = StrEq(L"Hi-\'\"\?\\\a\b\f\n\r\t\v"); - EXPECT_EQ("is equal to L\"Hi-\'\\\"\\?\\\\\\a\\b\\f\\n\\r\\t\\v\"", + Matcher< ::wstring> m = StrEq(L"Hi-\'\"?\\\a\b\f\n\r\t\v"); + EXPECT_EQ("is equal to L\"Hi-\'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\"", Describe(m)); Matcher< ::wstring> m2 = StrEq(L"\xD3\x576\x8D3\xC74D"); -- cgit v1.2.3 From 8e68753288986fd689e30efdaf4324f2f473ade7 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 7 Apr 2011 07:19:40 +0000 Subject: fixes link errors in 'make check' --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index cf7dee92..0c1a802a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,14 +68,14 @@ 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 works. +# 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 +test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la # Tests that fused gmock files compile and work. TESTS += test/gmock_fused_test -- cgit v1.2.3 From 52277c919e6cc47a6169d5bec48c0b03aecaa874 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 7 Apr 2011 07:37:28 +0000 Subject: disables 'make install' --- Makefile.am | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0c1a802a..adc21d7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,10 +7,6 @@ EXTRA_DIST = # included in the 'subdirs' variable. SUBDIRS = $(subdirs) -# Scripts and utilities to be installed by 'make install'. -dist_bin_SCRIPTS = scripts/gmock_doctor.py -bin_SCRIPTS = scripts/gmock-config - # This is generated by the configure script, so clean it for distribution. DISTCLEANFILES = scripts/gmock-config @@ -199,3 +195,15 @@ maintainer-clean-local: # 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 -- cgit v1.2.3 From ab29bb6fcd992d76625a139418e80599cd2c8823 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 8 Apr 2011 01:32:32 +0000 Subject: Removes commas from last items in enums (a C++ standard compliance fix). --- include/gmock/gmock-spec-builders.h | 6 +++--- include/gmock/internal/gmock-internal-utils.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 6ae807a2..400d4d71 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -254,7 +254,7 @@ class UntypedOnCallSpecBase { // syntax checking relies on it. kNone, kWith, - kWillByDefault, + kWillByDefault }; // Asserts that the ON_CALL() statement has a certain property. @@ -357,7 +357,7 @@ class OnCallSpec : public UntypedOnCallSpecBase { enum CallReaction { ALLOW, WARN, - FAIL, + FAIL }; } // namespace internal @@ -715,7 +715,7 @@ class ExpectationBase { kAfter, kWillOnce, kWillRepeatedly, - kRetiresOnSaturation, + kRetiresOnSaturation }; typedef std::vector UntypedActions; diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 48fadba2..f0fd8682 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -305,7 +305,7 @@ inline void Expect(bool condition, const char* file, int line) { // Severity level of a log. enum LogSeverity { INFO = 0, - WARNING = 1, + WARNING = 1 }; // Valid values for the --gmock_verbose flag. -- cgit v1.2.3 From e73cf452a50801cf2adeb600b225ae17156f40f1 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 13 Apr 2011 22:12:00 +0000 Subject: Corrects condition to compile out MSVC's pragmas. This fixes the build on MinGW. --- include/gmock/gmock-matchers.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index dfb72599..f401725b 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1392,15 +1392,15 @@ class TrulyMatcher { template bool MatchAndExplain(T& x, // NOLINT MatchResultListener* /* listener */) const { -#if GTEST_OS_WINDOWS +#if _MSC_VER // MSVC warns about converting a value into bool (warning 4800). # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4800) // Temporarily disables warning 4800. -#endif // GTEST_OS_WINDOWS +#endif return predicate_(x); -#if GTEST_OS_WINDOWS +#if _MSC_VER # pragma warning(pop) // Restores the warning state. -#endif // GTEST_OS_WINDOWS +#endif } void DescribeTo(::std::ostream* os) const { -- cgit v1.2.3 From dd28d536eb16f98a68825c9805913969b57c5bbc Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 14 Apr 2011 02:42:15 +0000 Subject: Updates conditional directives to be consistent with the rest of the project. --- include/gmock/gmock-matchers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index f401725b..b92450ca 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1392,13 +1392,13 @@ class TrulyMatcher { template bool MatchAndExplain(T& x, // NOLINT MatchResultListener* /* listener */) const { -#if _MSC_VER +#ifdef _MSC_VER // MSVC warns about converting a value into bool (warning 4800). # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4800) // Temporarily disables warning 4800. #endif return predicate_(x); -#if _MSC_VER +#ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif } -- cgit v1.2.3 From 8d7c5ad6d3f8aa9715815613b5d244bd4a0e073e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 Apr 2011 07:49:05 +0000 Subject: Documents latest changes and pulls in gtest r570 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index ba7cfc41..90f88a59 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,8 @@ Changes for 1.6.0: types now. * Compatibility fixes. * Bug fixes and implementation clean-ups. +* Potentially incompatible changes: disables the harmful 'make install' + command in autotools. Potentially breaking changes: -- cgit v1.2.3 From 8d3dc0cdd870ecc53d8a8ba30566b3cd70910863 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 14 Apr 2011 19:37:06 +0000 Subject: simplifies TrulyMatcher and adds a test for it --- include/gmock/gmock-matchers.h | 18 +++++++++--------- test/gmock-matchers_test.cc | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index b92450ca..c21fa515 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1392,15 +1392,15 @@ class TrulyMatcher { template bool MatchAndExplain(T& x, // NOLINT MatchResultListener* /* listener */) const { -#ifdef _MSC_VER - // MSVC warns about converting a value into bool (warning 4800). -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4800) // Temporarily disables warning 4800. -#endif - return predicate_(x); -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif + // Without the if-statement, MSVC sometimes warns about converting + // a value to bool (warning 4800). + // + // We cannot write 'return !!predicate_(x);' as that doesn't work + // when predicate_(x) returns a class convertible to bool but + // having no operator!(). + if (predicate_(x)) + return true; + return false; } void DescribeTo(::std::ostream* os) const { diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 6f93fbd7..9ad62c47 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -2256,6 +2256,29 @@ TEST(TrulyTest, CanBeUsedWithFunctor) { EXPECT_FALSE(m.Matches(4)); } +// A class that can be implicitly converted to bool. +class ConvertibleToBool { + public: + explicit ConvertibleToBool(int number) : number_(number) {} + operator bool() const { return number_ != 0; } + + private: + int number_; +}; + +ConvertibleToBool IsNotZero(int number) { + return ConvertibleToBool(number); +} + +// Tests that the predicate used in Truly() may return a class that's +// implicitly convertible to bool, even when the class has no +// operator!(). +TEST(TrulyTest, PredicateCanReturnAClassConvertibleToBool) { + Matcher m = Truly(IsNotZero); + EXPECT_TRUE(m.Matches(1)); + EXPECT_FALSE(m.Matches(0)); +} + // Tests that Truly(predicate) can describe itself properly. TEST(TrulyTest, CanDescribeSelf) { Matcher m = Truly(IsPositive); -- cgit v1.2.3 From a63da04126993d381778fda3cd7ca45305ec74b3 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 21 Apr 2011 21:56:01 +0000 Subject: Makes generation of fused sources contingent on availability of Python and pulls in gtest r580. --- Makefile.am | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Makefile.am b/Makefile.am index adc21d7f..3e11b328 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,16 +73,18 @@ test_gmock_link_test_SOURCES = \ test/gmock_link_test.h test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la -# 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" +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 = \ @@ -169,6 +171,7 @@ EXTRA_DIST += \ 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 @@ -191,6 +194,7 @@ fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ 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. -- cgit v1.2.3 From 47be72a952e672e2635c62353d25e611e9a70dac Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 11 May 2011 08:18:45 +0000 Subject: A test to verify correcteness of Google Mock on multiple threads. --- CMakeLists.txt | 5 +- test/gmock_stress_test.cc | 322 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 test/gmock_stress_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 061c2fc5..3cabd161 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,9 +114,12 @@ if (gmock_build_tests) 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_stress_test gmock) 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) diff --git a/test/gmock_stress_test.cc b/test/gmock_stress_test.cc new file mode 100644 index 00000000..0e97aeed --- /dev/null +++ b/test/gmock_stress_test.cc @@ -0,0 +1,322 @@ +// 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) + +// Tests that Google Mock constructs can be used in a large number of +// threads concurrently. + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace testing { +namespace { + +// From . +using ::testing::internal::ThreadWithParam; + +// The maximum number of test threads (not including helper threads) +// to create. +const int kMaxTestThreads = 50; + +// How many times to repeat a task in a test thread. +const int kRepeat = 50; + +class MockFoo { + public: + MOCK_METHOD1(Bar, int(int n)); // NOLINT + MOCK_METHOD2(Baz, char(const char* s1, const internal::string& s2)); // NOLINT +}; + +// Helper for waiting for the given thread to finish and then deleting it. +template +void JoinAndDelete(ThreadWithParam* t) { + t->Join(); + delete t; +} + +using internal::linked_ptr; + +// Helper classes for testing using linked_ptr concurrently. + +class Base { + public: + explicit Base(int a_x) : x_(a_x) {} + virtual ~Base() {} + int x() const { return x_; } + private: + int x_; +}; + +class Derived1 : public Base { + public: + Derived1(int a_x, int a_y) : Base(a_x), y_(a_y) {} + int y() const { return y_; } + private: + int y_; +}; + +class Derived2 : public Base { + public: + Derived2(int a_x, int a_z) : Base(a_x), z_(a_z) {} + int z() const { return z_; } + private: + int z_; +}; + +linked_ptr pointer1(new Derived1(1, 2)); +linked_ptr pointer2(new Derived2(3, 4)); + +struct Dummy {}; + +// Tests that we can copy from a linked_ptr and read it concurrently. +void TestConcurrentCopyAndReadLinkedPtr(Dummy /* dummy */) { + // Reads pointer1 and pointer2 while they are being copied from in + // another thread. + EXPECT_EQ(1, pointer1->x()); + EXPECT_EQ(2, pointer1->y()); + EXPECT_EQ(3, pointer2->x()); + EXPECT_EQ(4, pointer2->z()); + + // Copies from pointer1. + linked_ptr p1(pointer1); + EXPECT_EQ(1, p1->x()); + EXPECT_EQ(2, p1->y()); + + // Assigns from pointer2 where the LHS was empty. + linked_ptr p2; + p2 = pointer1; + EXPECT_EQ(1, p2->x()); + + // Assigns from pointer2 where the LHS was not empty. + p2 = pointer2; + EXPECT_EQ(3, p2->x()); +} + +const linked_ptr p0(new Derived1(1, 2)); + +// Tests that we can concurrently modify two linked_ptrs that point to +// the same object. +void TestConcurrentWriteToEqualLinkedPtr(Dummy /* dummy */) { + // p1 and p2 point to the same, shared thing. One thread resets p1. + // Another thread assigns to p2. This will cause the same + // underlying "ring" to be updated concurrently. + linked_ptr p1(p0); + linked_ptr p2(p0); + + EXPECT_EQ(1, p1->x()); + EXPECT_EQ(2, p1->y()); + + EXPECT_EQ(1, p2->x()); + EXPECT_EQ(2, p2->y()); + + p1.reset(); + p2 = p0; + + EXPECT_EQ(1, p2->x()); + EXPECT_EQ(2, p2->y()); +} + +// Tests that different mock objects can be used in their respective +// threads. This should generate no Google Test failure. +void TestConcurrentMockObjects(Dummy /* dummy */) { + // Creates a mock and does some typical operations on it. + MockFoo foo; + ON_CALL(foo, Bar(_)) + .WillByDefault(Return(1)); + ON_CALL(foo, Baz(_, _)) + .WillByDefault(Return('b')); + ON_CALL(foo, Baz(_, "you")) + .WillByDefault(Return('a')); + + EXPECT_CALL(foo, Bar(0)) + .Times(AtMost(3)); + EXPECT_CALL(foo, Baz(_, _)); + EXPECT_CALL(foo, Baz("hi", "you")) + .WillOnce(Return('z')) + .WillRepeatedly(DoDefault()); + + EXPECT_EQ(1, foo.Bar(0)); + EXPECT_EQ(1, foo.Bar(0)); + EXPECT_EQ('z', foo.Baz("hi", "you")); + EXPECT_EQ('a', foo.Baz("hi", "you")); + EXPECT_EQ('b', foo.Baz("hi", "me")); +} + +// Tests invoking methods of the same mock object in multiple threads. + +struct Helper1Param { + MockFoo* mock_foo; + int* count; +}; + +void Helper1(Helper1Param param) { + for (int i = 0; i < kRepeat; i++) { + const char ch = param.mock_foo->Baz("a", "b"); + if (ch == 'a') { + // It was an expected call. + (*param.count)++; + } else { + // It was an excessive call. + EXPECT_EQ('\0', ch); + } + + // An unexpected call. + EXPECT_EQ('\0', param.mock_foo->Baz("x", "y")) << "Expected failure."; + + // An uninteresting call. + EXPECT_EQ(1, param.mock_foo->Bar(5)); + } +} + +// This should generate 3*kRepeat + 1 failures in total. +void TestConcurrentCallsOnSameObject(Dummy /* dummy */) { + MockFoo foo; + + ON_CALL(foo, Bar(_)) + .WillByDefault(Return(1)); + EXPECT_CALL(foo, Baz(_, "b")) + .Times(kRepeat) + .WillRepeatedly(Return('a')); + EXPECT_CALL(foo, Baz(_, "c")); // Expected to be unsatisfied. + + // This chunk of code should generate kRepeat failures about + // excessive calls, and 2*kRepeat failures about unexpected calls. + int count1 = 0; + const Helper1Param param = { &foo, &count1 }; + ThreadWithParam* const t = + new ThreadWithParam(Helper1, param, NULL); + + int count2 = 0; + const Helper1Param param2 = { &foo, &count2 }; + Helper1(param2); + JoinAndDelete(t); + + EXPECT_EQ(kRepeat, count1 + count2); + + // foo's destructor should generate one failure about unsatisfied + // expectation. +} + +// Tests using the same mock object in multiple threads when the +// expectations are partially ordered. + +void Helper2(MockFoo* foo) { + for (int i = 0; i < kRepeat; i++) { + foo->Bar(2); + foo->Bar(3); + } +} + +// This should generate no Google Test failures. +void TestPartiallyOrderedExpectationsWithThreads(Dummy /* dummy */) { + MockFoo foo; + Sequence s1, s2; + + { + InSequence dummy; + EXPECT_CALL(foo, Bar(0)); + EXPECT_CALL(foo, Bar(1)) + .InSequence(s1, s2); + } + + EXPECT_CALL(foo, Bar(2)) + .Times(2*kRepeat) + .InSequence(s1) + .RetiresOnSaturation(); + EXPECT_CALL(foo, Bar(3)) + .Times(2*kRepeat) + .InSequence(s2); + + { + InSequence dummy; + EXPECT_CALL(foo, Bar(2)) + .InSequence(s1, s2); + EXPECT_CALL(foo, Bar(4)); + } + + foo.Bar(0); + foo.Bar(1); + + ThreadWithParam* const t = + new ThreadWithParam(Helper2, &foo, NULL); + Helper2(&foo); + JoinAndDelete(t); + + foo.Bar(2); + foo.Bar(4); +} + +// Tests using Google Mock constructs in many threads concurrently. +TEST(StressTest, CanUseGMockWithThreads) { + void (*test_routines[])(Dummy dummy) = { + &TestConcurrentCopyAndReadLinkedPtr, + &TestConcurrentWriteToEqualLinkedPtr, + &TestConcurrentMockObjects, + &TestConcurrentCallsOnSameObject, + &TestPartiallyOrderedExpectationsWithThreads, + }; + + const int kRoutines = sizeof(test_routines)/sizeof(test_routines[0]); + const int kCopiesOfEachRoutine = kMaxTestThreads / kRoutines; + const int kTestThreads = kCopiesOfEachRoutine * kRoutines; + ThreadWithParam* threads[kTestThreads] = {}; + for (int i = 0; i < kTestThreads; i++) { + // Creates a thread to run the test function. + threads[i] = + new ThreadWithParam(test_routines[i % kRoutines], Dummy(), NULL); + GTEST_LOG_(INFO) << "Thread #" << i << " running . . ."; + } + + // At this point, we have many threads running. + for (int i = 0; i < kTestThreads; i++) { + JoinAndDelete(threads[i]); + } + + // Ensures that the correct number of failures have been reported. + const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); + const TestResult& result = *info->result(); + const int kExpectedFailures = (3*kRepeat + 1)*kCopiesOfEachRoutine; + GTEST_CHECK_(kExpectedFailures == result.total_part_count()) + << "Expected " << kExpectedFailures << " failures, but got " + << result.total_part_count(); +} + +} // namespace +} // namespace testing + +int main(int argc, char **argv) { + testing::InitGoogleMock(&argc, argv); + + const int exit_code = RUN_ALL_TESTS(); // Expected to fail. + GTEST_CHECK_(exit_code != 0) << "RUN_ALL_TESTS() did not fail as expected"; + + printf("\nPASS\n"); + return 0; +} -- cgit v1.2.3 From 587c1b37c2f0b6d430fb13ce09326db0135b557c Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 20 May 2011 00:42:22 +0000 Subject: Adds support for building Google Mock as a shared library (DLL). --- CMakeLists.txt | 34 ++++++++++++++++++++------- include/gmock/gmock-cardinalities.h | 12 +++++----- include/gmock/gmock-matchers.h | 9 +++---- include/gmock/gmock-spec-builders.h | 22 ++++++++--------- include/gmock/gmock.h | 4 ++-- include/gmock/internal/gmock-internal-utils.h | 10 ++++---- include/gmock/internal/gmock-port.h | 12 +++++----- src/gmock-cardinalities.cc | 10 ++++---- src/gmock-internal-utils.cc | 11 +++++---- src/gmock-matchers.cc | 7 +++--- src/gmock-spec-builders.cc | 10 ++++---- src/gmock.cc | 4 ++-- src/gmock_main.cc | 4 ++-- test/gmock-matchers_test.cc | 2 +- 14 files changed, 86 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cabd161..ded9ca9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,11 +9,6 @@ # make it prominent in the GUI. option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) -# Forces BUILD_SHARED_LIBS to OFF as Google Mock currently does not support -# working in a DLL. -# TODO(vladl@google.com): Implement building gMock as a DLL. -set(BUILD_SHARED_LIBS OFF) - option(gmock_build_tests "Build all of Google Mock's own tests." OFF) # A directory to find Google Test sources. @@ -76,11 +71,16 @@ include_directories("${gmock_SOURCE_DIR}/include" # 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}" src/gmock-all.cc) -target_link_libraries(gmock gtest) +cxx_library(gmock + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc) -cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc) -target_link_libraries(gmock_main gmock) +cxx_library(gmock_main + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc + src/gmock_main.cc) ######################################################################## # @@ -129,8 +129,10 @@ if (gmock_build_tests) 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) + 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) @@ -143,6 +145,20 @@ if (gmock_build_tests) cxx_test_with_flags(gmock_use_own_tuple_test "${cxx_use_own_tuple}" gmock_main_use_own_tuple 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. diff --git a/include/gmock/gmock-cardinalities.h b/include/gmock/gmock-cardinalities.h index 954a86ea..759dcf8c 100644 --- a/include/gmock/gmock-cardinalities.h +++ b/include/gmock/gmock-cardinalities.h @@ -80,7 +80,7 @@ class CardinalityInterface { // 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 Cardinality { +class GTEST_API_ Cardinality { public: // Constructs a null cardinality. Needed for storing Cardinality // objects in STL containers. @@ -122,19 +122,19 @@ class Cardinality { }; // Creates a cardinality that allows at least n calls. -Cardinality AtLeast(int n); +GTEST_API_ Cardinality AtLeast(int n); // Creates a cardinality that allows at most n calls. -Cardinality AtMost(int n); +GTEST_API_ Cardinality AtMost(int n); // Creates a cardinality that allows any number of calls. -Cardinality AnyNumber(); +GTEST_API_ Cardinality AnyNumber(); // Creates a cardinality that allows between min and max calls. -Cardinality Between(int min, int max); +GTEST_API_ Cardinality Between(int min, int max); // Creates a cardinality that allows exactly n calls. -Cardinality Exactly(int n); +GTEST_API_ Cardinality Exactly(int n); // Creates a cardinality from its implementation. inline Cardinality MakeCardinality(const CardinalityInterface* c) { diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index c21fa515..9445bf91 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -268,7 +268,7 @@ class Matcher : public internal::MatcherBase { // instead of Eq(str) and "foo" instead of Eq("foo") when a string // matcher is expected. template <> -class Matcher +class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} @@ -285,7 +285,7 @@ class Matcher }; template <> -class Matcher +class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} @@ -2548,8 +2548,9 @@ class ElementsAreArrayMatcher { // 'negation' is false; otherwise returns the description of the // negation of the matcher. 'param_values' contains a list of strings // that are the print-out of the matcher's parameters. -string FormatMatcherDescription(bool negation, const char* matcher_name, - const Strings& param_values); +GTEST_API_ string FormatMatcherDescription(bool negation, + const char* matcher_name, + const Strings& param_values); } // namespace internal diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 400d4d71..66a36e8a 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -111,7 +111,7 @@ template class FunctionMockerBase; // expectations when InSequence() is used, and thus affect which // expectation gets picked. Therefore, we sequence all mock function // calls to ensure the integrity of the mock objects' states. -GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); // Untyped base class for ActionResultHolder. class UntypedActionResultHolderBase; @@ -119,7 +119,7 @@ class UntypedActionResultHolderBase; // Abstract base class of FunctionMockerBase. This is the // type-agnostic part of the function mocker interface. Its pure // virtual methods are implemented by FunctionMockerBase. -class UntypedFunctionMockerBase { +class GTEST_API_ UntypedFunctionMockerBase { public: UntypedFunctionMockerBase(); virtual ~UntypedFunctionMockerBase(); @@ -363,7 +363,7 @@ enum CallReaction { } // namespace internal // Utilities for manipulating mock objects. -class Mock { +class GTEST_API_ Mock { public: // The following public methods can be called concurrently. @@ -471,7 +471,7 @@ class Mock { // ExpectationBase available yet, leading to incorrect destruction // in the linked_ptr (or compilation errors if using a checking // linked_ptr). -class Expectation { +class GTEST_API_ Expectation { public: // Constructs a null object that doesn't reference any expectation. Expectation(); @@ -603,7 +603,7 @@ class ExpectationSet { // Sequence objects are used by a user to specify the relative order // in which the expectations should match. They are copyable (we rely // on the compiler-defined copy constructor and assignment operator). -class Sequence { +class GTEST_API_ Sequence { public: // Constructs an empty sequence. Sequence() : last_expectation_(new Expectation) {} @@ -644,7 +644,7 @@ class Sequence { // thread. However, for clarity of your tests we recommend you to set // up mocks in the main thread unless you have a good reason not to do // so. -class InSequence { +class GTEST_API_ InSequence { public: InSequence(); ~InSequence(); @@ -658,7 +658,7 @@ namespace internal { // Points to the implicit sequence introduced by a living InSequence // object (if any) in the current thread or NULL. -extern ThreadLocal g_gmock_implicit_sequence; +GTEST_API_ extern ThreadLocal g_gmock_implicit_sequence; // Base class for implementing expectations. // @@ -674,7 +674,7 @@ extern ThreadLocal g_gmock_implicit_sequence; // on the template argument of Expectation to the base class. // // This class is internal and mustn't be used by user code directly. -class ExpectationBase { +class GTEST_API_ ExpectationBase { public: // source_text is the EXPECT_CALL(...) source that created this Expectation. ExpectationBase(const char* file, int line, const string& source_text); @@ -1222,9 +1222,9 @@ class TypedExpectation : public ExpectationBase { // ::testing::internal and import it into ::testing. // Logs a message including file and line number information. -void LogWithLocation(testing::internal::LogSeverity severity, - const char* file, int line, - const string& message); +GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity, + const char* file, int line, + const string& message); template class MockSpec { diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index ba9fa286..481e5706 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -82,11 +82,11 @@ GMOCK_DECLARE_string_(verbose); // Since Google Test is needed for Google Mock to work, this function // also initializes Google Test and parses its flags, if that hasn't // been done. -void InitGoogleMock(int* argc, char** argv); +GTEST_API_ void InitGoogleMock(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. -void InitGoogleMock(int* argc, wchar_t** argv); +GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv); } // namespace testing diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index f0fd8682..34131ef6 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -53,7 +53,7 @@ namespace internal { // words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is // treated as one word. For example, both "FooBar123" and // "foo_bar_123" are converted to "foo bar 123". -string ConvertIdentifierNameToWords(const char* id_name); +GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name); // PointeeOf::type is the type of a value pointed to by a // Pointer, which can be either a smart pointer or a raw pointer. The @@ -271,7 +271,7 @@ class FailureReporterInterface { }; // Returns the failure reporter used by Google Mock. -FailureReporterInterface* GetFailureReporter(); +GTEST_API_ FailureReporterInterface* GetFailureReporter(); // Asserts that condition is true; aborts the process with the given // message if condition is false. We cannot use LOG(FATAL) or CHECK() @@ -319,7 +319,7 @@ const char kErrorVerbosity[] = "error"; // Returns true iff a log with the given severity is visible according // to the --gmock_verbose flag. -bool LogIsVisible(LogSeverity severity); +GTEST_API_ bool LogIsVisible(LogSeverity severity); // Prints the given message to stdout iff 'severity' >= the level // specified by the --gmock_verbose flag. If stack_frames_to_skip >= @@ -328,7 +328,9 @@ bool LogIsVisible(LogSeverity severity); // stack_frames_to_skip is treated as 0, since we don't know which // function calls will be inlined by the compiler and need to be // conservative. -void Log(LogSeverity severity, const string& message, int stack_frames_to_skip); +GTEST_API_ void Log(LogSeverity severity, + const string& message, + int stack_frames_to_skip); // TODO(wan@google.com): group all type utilities together. diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 3b9cc479..6a515d87 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -61,18 +61,18 @@ #define GMOCK_FLAG(name) FLAGS_gmock_##name // Macros for declaring flags. -#define GMOCK_DECLARE_bool_(name) extern bool GMOCK_FLAG(name) +#define GMOCK_DECLARE_bool_(name) extern GTEST_API_ bool GMOCK_FLAG(name) #define GMOCK_DECLARE_int32_(name) \ - extern ::testing::internal::Int32 GMOCK_FLAG(name) + extern GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) #define GMOCK_DECLARE_string_(name) \ - extern ::testing::internal::String GMOCK_FLAG(name) + extern GTEST_API_ ::testing::internal::String GMOCK_FLAG(name) // Macros for defining flags. #define GMOCK_DEFINE_bool_(name, default_val, doc) \ - bool GMOCK_FLAG(name) = (default_val) + GTEST_API_ bool GMOCK_FLAG(name) = (default_val) #define GMOCK_DEFINE_int32_(name, default_val, doc) \ - ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val) + GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val) #define GMOCK_DEFINE_string_(name, default_val, doc) \ - ::testing::internal::String GMOCK_FLAG(name) = (default_val) + GTEST_API_ ::testing::internal::String GMOCK_FLAG(name) = (default_val) #endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ diff --git a/src/gmock-cardinalities.cc b/src/gmock-cardinalities.cc index 1a7902b4..274f98a9 100644 --- a/src/gmock-cardinalities.cc +++ b/src/gmock-cardinalities.cc @@ -136,20 +136,20 @@ void Cardinality::DescribeActualCallCountTo(int actual_call_count, } // Creates a cardinality that allows at least n calls. -Cardinality AtLeast(int n) { return Between(n, INT_MAX); } +GTEST_API_ Cardinality AtLeast(int n) { return Between(n, INT_MAX); } // Creates a cardinality that allows at most n calls. -Cardinality AtMost(int n) { return Between(0, n); } +GTEST_API_ Cardinality AtMost(int n) { return Between(0, n); } // Creates a cardinality that allows any number of calls. -Cardinality AnyNumber() { return AtLeast(0); } +GTEST_API_ Cardinality AnyNumber() { return AtLeast(0); } // Creates a cardinality that allows between min and max calls. -Cardinality Between(int min, int max) { +GTEST_API_ Cardinality Between(int min, int max) { return Cardinality(new BetweenCardinalityImpl(min, max)); } // Creates a cardinality that allows exactly n calls. -Cardinality Exactly(int n) { return Between(n, n); } +GTEST_API_ Cardinality Exactly(int n) { return Between(n, n); } } // namespace testing diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index dd38132a..470fc447 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -51,7 +51,7 @@ namespace internal { // words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is // treated as one word. For example, both "FooBar123" and // "foo_bar_123" are converted to "foo bar 123". -string ConvertIdentifierNameToWords(const char* id_name) { +GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name) { string result; char prev_char = '\0'; for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) { @@ -91,7 +91,7 @@ class GoogleTestFailureReporter : public FailureReporterInterface { // Returns the global failure reporter. Will create a // GoogleTestFailureReporter and return it the first time called. -FailureReporterInterface* GetFailureReporter() { +GTEST_API_ FailureReporterInterface* GetFailureReporter() { // Points to the global failure reporter used by Google Mock. gcc // guarantees that the following use of failure_reporter is // thread-safe. We may need to add additional synchronization to @@ -107,7 +107,7 @@ static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex); // Returns true iff a log with the given severity is visible according // to the --gmock_verbose flag. -bool LogIsVisible(LogSeverity severity) { +GTEST_API_ bool LogIsVisible(LogSeverity severity) { if (GMOCK_FLAG(verbose) == kInfoVerbosity) { // Always show the log if --gmock_verbose=info. return true; @@ -128,8 +128,9 @@ bool LogIsVisible(LogSeverity severity) { // stack_frames_to_skip is treated as 0, since we don't know which // function calls will be inlined by the compiler and need to be // conservative. -void Log(LogSeverity severity, const string& message, - int stack_frames_to_skip) { +GTEST_API_ void Log(LogSeverity severity, + const string& message, + int stack_frames_to_skip) { if (!LogIsVisible(severity)) return; diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc index a5e6824d..63f3859b 100644 --- a/src/gmock-matchers.cc +++ b/src/gmock-matchers.cc @@ -67,7 +67,7 @@ namespace internal { // Joins a vector of strings as if they are fields of a tuple; returns // the joined string. -string JoinAsTuple(const Strings& fields) { +GTEST_API_ string JoinAsTuple(const Strings& fields) { switch (fields.size()) { case 0: return ""; @@ -89,8 +89,9 @@ string JoinAsTuple(const Strings& fields) { // 'negation' is false; otherwise returns the description of the // negation of the matcher. 'param_values' contains a list of strings // that are the print-out of the matcher's parameters. -string FormatMatcherDescription(bool negation, const char* matcher_name, - const Strings& param_values) { +GTEST_API_ string FormatMatcherDescription(bool negation, + const char* matcher_name, + const Strings& param_values) { string result = ConvertIdentifierNameToWords(matcher_name); if (param_values.size() >= 1) result += " " + JoinAsTuple(param_values); diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index aa33cc44..c192f96c 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -53,12 +53,12 @@ namespace internal { // Protects the mock object registry (in class Mock), all function // mockers, and all expectations. -GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex); +GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex); // Logs a message including file and line number information. -void LogWithLocation(testing::internal::LogSeverity severity, - const char* file, int line, - const string& message) { +GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity, + const char* file, int line, + const string& message) { ::std::ostringstream s; s << file << ":" << line << ": " << message << ::std::endl; Log(severity, s.str(), 0); @@ -240,7 +240,7 @@ void ExpectationBase::UntypedTimes(const Cardinality& a_cardinality) { // Points to the implicit sequence introduced by a living InSequence // object (if any) in the current thread or NULL. -ThreadLocal g_gmock_implicit_sequence; +GTEST_API_ ThreadLocal g_gmock_implicit_sequence; // Reports an uninteresting call (whose description is in msg) in the // manner specified by 'reaction'. diff --git a/src/gmock.cc b/src/gmock.cc index 700bcb2e..e06acc5c 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -169,13 +169,13 @@ void InitGoogleMockImpl(int* argc, CharType** argv) { // Since Google Test is needed for Google Mock to work, this function // also initializes Google Test and parses its flags, if that hasn't // been done. -void InitGoogleMock(int* argc, char** argv) { +GTEST_API_ void InitGoogleMock(int* argc, char** argv) { internal::InitGoogleMockImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. -void InitGoogleMock(int* argc, wchar_t** argv) { +GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv) { internal::InitGoogleMockImpl(argc, argv); } diff --git a/src/gmock_main.cc b/src/gmock_main.cc index 9d8aea22..bd5be03b 100644 --- a/src/gmock_main.cc +++ b/src/gmock_main.cc @@ -41,9 +41,9 @@ #if GTEST_OS_WINDOWS_MOBILE # include // NOLINT -int _tmain(int argc, TCHAR** argv) { +GTEST_API_ int _tmain(int argc, TCHAR** argv) { #else -int main(int argc, char** argv) { +GTEST_API_ int main(int argc, char** argv) { #endif // GTEST_OS_WINDOWS_MOBILE std::cout << "Running main() from gmock_main.cc\n"; // Since Google Mock depends on Google Test, InitGoogleMock() is diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 9ad62c47..8f96efc2 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -52,7 +52,7 @@ namespace testing { namespace internal { -string JoinAsTuple(const Strings& fields); +GTEST_API_ string JoinAsTuple(const Strings& fields); } // namespace internal namespace gmock_matchers_test { -- cgit v1.2.3 From bce8134d89f6932231140265e2ccbb12483f2874 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 20 May 2011 21:15:36 +0000 Subject: Adds a DLL-related section to Google Mock's README. --- README | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README b/README index aa3283d7..e414f3a6 100644 --- a/README +++ b/README @@ -265,7 +265,14 @@ 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. -### Tweaking Google Test ### +### 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 +file 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 file ${GTEST_DIR}/README for how to tweak them. -- cgit v1.2.3 From f4eeaedb39b6935f6236fe55a52bd9af0b8390ef Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 20 May 2011 21:44:14 +0000 Subject: Fixes issue 139 and issue 140. --- scripts/generator/cpp/gmock_class.py | 40 ++++++++++++++++++--------- scripts/generator/cpp/gmock_class_test.py | 45 +++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py index 645c295b..427d206a 100755 --- a/scripts/generator/cpp/gmock_class.py +++ b/scripts/generator/cpp/gmock_class.py @@ -82,20 +82,36 @@ def _GenerateMethods(output_lines, source, class_node): return_type += '*' if node.return_type.reference: return_type += '&' - mock_method_macro = 'MOCK_%sMETHOD%d' % (const, len(node.parameters)) + num_parameters = len(node.parameters) + if len(node.parameters) == 1: + first_param = node.parameters[0] + if source[first_param.start:first_param.end].strip() == 'void': + # We must treat T(void) as a function with no parameters. + num_parameters = 0 + mock_method_macro = 'MOCK_%sMETHOD%d' % (const, num_parameters) args = '' if node.parameters: - # Get the full text of the parameters from the start - # of the first parameter to the end of the last parameter. - start = node.parameters[0].start - end = node.parameters[-1].end - # Remove // comments. - args_strings = re.sub(r'//.*', '', source[start:end]) - # Condense multiple spaces and eliminate newlines putting the - # parameters together on a single line. Ensure there is a - # space in an argument which is split by a newline without - # intervening whitespace, e.g.: int\nBar - args = re.sub(' +', ' ', args_strings.replace('\n', ' ')) + # Due to the parser limitations, it is impossible to keep comments + # while stripping the default parameters. When defaults are + # present, we choose to strip them and comments (and produce + # compilable code). + # TODO(nnorwitz@google.com): Investigate whether it is possible to + # preserve parameter name when reconstructing parameter text from + # the AST. + if len([param for param in node.parameters if param.default]) > 0: + args = ', '.join(param.type.name for param in node.parameters) + else: + # Get the full text of the parameters from the start + # of the first parameter to the end of the last parameter. + start = node.parameters[0].start + end = node.parameters[-1].end + # Remove // comments. + args_strings = re.sub(r'//.*', '', source[start:end]) + # Condense multiple spaces and eliminate newlines putting the + # parameters together on a single line. Ensure there is a + # space in an argument which is split by a newline without + # intervening whitespace, e.g.: int\nBar + args = re.sub(' +', ' ', args_strings.replace('\n', ' ')) # Create the mock method definition. output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name), diff --git a/scripts/generator/cpp/gmock_class_test.py b/scripts/generator/cpp/gmock_class_test.py index 494720cd..7aa70276 100755 --- a/scripts/generator/cpp/gmock_class_test.py +++ b/scripts/generator/cpp/gmock_class_test.py @@ -76,6 +76,17 @@ class Foo { 'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));', self.GenerateMethodSource(source)) + def testExplicitVoid(self): + source = """ +class Foo { + public: + virtual int Bar(void); +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint(void));', + self.GenerateMethodSource(source)) + def testStrangeNewlineInParameter(self): source = """ class Foo { @@ -88,6 +99,40 @@ a) = 0; 'MOCK_METHOD1(Bar,\nvoid(int a));', self.GenerateMethodSource(source)) + def testDefaultParameters(self): + source = """ +class Foo { + public: + virtual void Bar(int a, char c = 'x') = 0; +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nvoid(int, char));', + self.GenerateMethodSource(source)) + + def testMultipleDefaultParameters(self): + source = """ +class Foo { + public: + virtual void Bar(int a = 42, char c = 'x') = 0; +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nvoid(int, char));', + self.GenerateMethodSource(source)) + + def testRemovesCommentsWhenDefaultsArePresent(self): + source = """ +class Foo { + public: + virtual void Bar(int a = 42 /* a comment */, + char /* other comment */ c= 'x') = 0; +}; +""" + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nvoid(int, char));', + self.GenerateMethodSource(source)) + def testDoubleSlashCommentsInParameterListAreRemoved(self): source = """ class Foo { -- cgit v1.2.3 From 787146bdb730e9c3731c989a8707ff8f018a0a0d Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 16 Aug 2011 00:51:14 +0000 Subject: Improves support for Clang in Google Mock Doctor. --- scripts/gmock_doctor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index afd59101..e086c919 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -394,8 +394,9 @@ def _NeedToUseSymbolDiagnoser(msg): gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P.+)\' ' r'(was not declared in this scope|has not been declared)') - clang_regex = (_CLANG_FILE_LINE_RE + r'error: use of undeclared identifier ' - r'\'(?P.+)\'') + clang_regex = (_CLANG_FILE_LINE_RE + + r'error: (use of undeclared identifier|unknown type name) ' + r'\'(?P[^\']+)\'') diagnosis = """ '%(symbol)s' is defined by Google Mock in the testing namespace. Did you forget to write -- cgit v1.2.3 From eca38cd7ecf009251c6830d4c3286200b3450bbb Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 25 Aug 2011 21:35:10 +0000 Subject: More Clang support improvements in Google Mock Doctor. --- scripts/gmock_doctor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index e086c919..ea930a38 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -173,7 +173,7 @@ def _NeedToReturnReferenceDiagnoser(msg): r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation of function template specialization ' - r'\'testing::internal::ReturnAction<(?P).*>' + r'\'testing::internal::ReturnAction<(?P.*)>' r'::operator Action<.*>\' requested here') diagnosis = """ You are using a Return() action in a function that returns a reference to @@ -192,11 +192,11 @@ def _NeedToReturnSomethingDiagnoser(msg): r'|(error: control reaches end of non-void function)') clang_regex1 = (_CLANG_FILE_LINE_RE + r'error: cannot initialize return object ' - r'of type \'Result\' \(aka \'(?P).*\'\) ' + r'of type \'Result\' \(aka \'(?P.*)\'\) ' r'with an rvalue of type \'void\'') clang_regex2 = (_CLANG_FILE_LINE_RE + r'error: cannot initialize return object ' - r'of type \'(?P).*\' ' + r'of type \'(?P.*)\' ' r'with an rvalue of type \'void\'') diagnosis = """ You are using an action that returns void, but it needs to return @@ -395,8 +395,8 @@ def _NeedToUseSymbolDiagnoser(msg): gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P.+)\' ' r'(was not declared in this scope|has not been declared)') clang_regex = (_CLANG_FILE_LINE_RE + - r'error: (use of undeclared identifier|unknown type name) ' - r'\'(?P[^\']+)\'') + r'error: (use of undeclared identifier|unknown type name|' + r'no template named) \'(?P[^\']+)\'') diagnosis = """ '%(symbol)s' is defined by Google Mock in the testing namespace. Did you forget to write -- cgit v1.2.3 From 5aa8dd99e2ec575f99801f122b6317caa0dd8584 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Fri, 9 Sep 2011 07:06:32 +0000 Subject: Renames the license files. --- COPYING | 28 ------- LICENSE | 28 +++++++ Makefile.am | 2 +- configure.ac | 2 +- scripts/generator/COPYING | 203 ---------------------------------------------- scripts/generator/LICENSE | 203 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 233 insertions(+), 233 deletions(-) delete mode 100644 COPYING create mode 100644 LICENSE delete mode 100644 scripts/generator/COPYING create mode 100644 scripts/generator/LICENSE diff --git a/COPYING b/COPYING deleted file mode 100644 index 1941a11f..00000000 --- a/COPYING +++ /dev/null @@ -1,28 +0,0 @@ -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/LICENSE b/LICENSE new file mode 100644 index 00000000..1941a11f --- /dev/null +++ b/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/Makefile.am b/Makefile.am index 3e11b328..0afce2f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -140,7 +140,7 @@ EXTRA_DIST += scripts/fuse_gmock_files.py # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ - scripts/generator/COPYING \ + scripts/generator/LICENSE \ scripts/generator/README \ scripts/generator/README.cppclean \ scripts/generator/cpp/__init__.py \ diff --git a/configure.ac b/configure.ac index e8b65bdc..05b90c4b 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ AC_INIT([Google C++ Mocking Framework], # Provide various options to initialize the Autoconf and configure processes. AC_PREREQ([2.59]) -AC_CONFIG_SRCDIR([./COPYING]) +AC_CONFIG_SRCDIR([./LICENSE]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([build-aux/config.h]) AC_CONFIG_FILES([Makefile]) diff --git a/scripts/generator/COPYING b/scripts/generator/COPYING deleted file mode 100644 index 87ea0636..00000000 --- a/scripts/generator/COPYING +++ /dev/null @@ -1,203 +0,0 @@ - - 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 [2007] Neal Norwitz - Portions Copyright [2007] Google Inc. - - 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/scripts/generator/LICENSE b/scripts/generator/LICENSE new file mode 100644 index 00000000..87ea0636 --- /dev/null +++ b/scripts/generator/LICENSE @@ -0,0 +1,203 @@ + + 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 [2007] Neal Norwitz + Portions Copyright [2007] Google Inc. + + 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. -- cgit v1.2.3 From 898725cf47aacd45c385bb6c537c130ac8cd224c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 16 Sep 2011 16:45:39 +0000 Subject: Implements matchers WhenSorted() and WhenSortedBy(); pulls in gtest r595. --- include/gmock/gmock-matchers.h | 99 ++++++++++++++++++++++++++++++++++++++++++ test/gmock-matchers_test.cc | 81 ++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 9445bf91..89a9e2ec 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1970,6 +1970,85 @@ class ContainerEqMatcher { GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; +// A comparator functor that uses the < operator to compare two values. +struct LessComparator { + template + bool operator()(const T& lhs, const U& rhs) const { return lhs < rhs; } +}; + +// Implements WhenSortedBy(comparator, container_matcher). +template +class WhenSortedByMatcher { + public: + WhenSortedByMatcher(const Comparator& comparator, + const ContainerMatcher& matcher) + : comparator_(comparator), matcher_(matcher) {} + + template + operator Matcher() const { + return MakeMatcher(new Impl(comparator_, matcher_)); + } + + template + class Impl : public MatcherInterface { + public: + typedef internal::StlContainerView< + GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView; + typedef typename LhsView::type LhsStlContainer; + typedef typename LhsView::const_reference LhsStlContainerReference; + typedef typename LhsStlContainer::value_type LhsValue; + + Impl(const Comparator& comparator, const ContainerMatcher& matcher) + : comparator_(comparator), matcher_(matcher) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "(when sorted) "; + matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "(when sorted) "; + matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(LhsContainer lhs, + MatchResultListener* listener) const { + LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + std::vector sorted_container(lhs_stl_container.begin(), + lhs_stl_container.end()); + std::sort(sorted_container.begin(), sorted_container.end(), comparator_); + + if (!listener->IsInterested()) { + // If the listener is not interested, we do not need to + // construct the inner explanation. + return matcher_.Matches(sorted_container); + } + + *listener << "which is "; + UniversalPrint(sorted_container, listener->stream()); + *listener << " when sorted"; + + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(sorted_container, + &inner_listener); + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return match; + } + + private: + const Comparator comparator_; + const Matcher&> matcher_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl); + }; + + private: + const Comparator comparator_; + const ContainerMatcher matcher_; + + GTEST_DISALLOW_ASSIGN_(WhenSortedByMatcher); +}; + // Implements Pointwise(tuple_matcher, rhs_container). tuple_matcher // must be able to be safely cast to Matcher >, where T1 and T2 are the types of elements in the LHS @@ -2930,6 +3009,26 @@ inline PolymorphicMatcher(rhs)); } +// Returns a matcher that matches a container that, when sorted using +// the given comparator, matches container_matcher. +template +inline internal::WhenSortedByMatcher +WhenSortedBy(const Comparator& comparator, + const ContainerMatcher& container_matcher) { + return internal::WhenSortedByMatcher( + comparator, container_matcher); +} + +// Returns a matcher that matches a container that, when sorted using +// the < operator, matches container_matcher. +template +inline internal::WhenSortedByMatcher +WhenSorted(const ContainerMatcher& container_matcher) { + return + internal::WhenSortedByMatcher( + internal::LessComparator(), container_matcher); +} + // Matches an STL-style container or a native array that contains the // same number of elements as in rhs, where its i-th element and rhs's // i-th element (as a pair) satisfy the given pair matcher, for all i. diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 8f96efc2..c4ed96ba 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -57,6 +57,8 @@ GTEST_API_ string JoinAsTuple(const Strings& fields); namespace gmock_matchers_test { +using std::greater; +using std::less; using std::list; using std::make_pair; using std::map; @@ -118,6 +120,8 @@ using testing::StrNe; using testing::Truly; using testing::TypedEq; using testing::Value; +using testing::WhenSorted; +using testing::WhenSortedBy; using testing::_; using testing::internal::DummyMatchResultListener; using testing::internal::ExplainMatchFailureTupleTo; @@ -3725,6 +3729,83 @@ TEST(ContainerEqExtraTest, CopiesNativeArrayParameter) { EXPECT_THAT(a1, m); } +TEST(WhenSortedByTest, WorksForEmptyContainer) { + const vector numbers; + EXPECT_THAT(numbers, WhenSortedBy(less(), ElementsAre())); + EXPECT_THAT(numbers, Not(WhenSortedBy(less(), ElementsAre(1)))); +} + +TEST(WhenSortedByTest, WorksForNonEmptyContainer) { + vector numbers; + numbers.push_back(3); + numbers.push_back(1); + numbers.push_back(2); + numbers.push_back(2); + EXPECT_THAT(numbers, WhenSortedBy(greater(), + ElementsAre(3, 2, 2, 1))); + EXPECT_THAT(numbers, Not(WhenSortedBy(greater(), + ElementsAre(1, 2, 2, 3)))); +} + +TEST(WhenSortedByTest, WorksForNonVectorContainer) { + list words; + words.push_back("say"); + words.push_back("hello"); + words.push_back("world"); + EXPECT_THAT(words, WhenSortedBy(less(), + ElementsAre("hello", "say", "world"))); + EXPECT_THAT(words, Not(WhenSortedBy(less(), + ElementsAre("say", "hello", "world")))); +} + +TEST(WhenSortedByTest, WorksForNativeArray) { + const int numbers[] = { 1, 3, 2, 4 }; + const int sorted_numbers[] = { 1, 2, 3, 4 }; + EXPECT_THAT(numbers, WhenSortedBy(less(), ElementsAre(1, 2, 3, 4))); + EXPECT_THAT(numbers, WhenSortedBy(less(), + ElementsAreArray(sorted_numbers))); + EXPECT_THAT(numbers, Not(WhenSortedBy(less(), ElementsAre(1, 3, 2, 4)))); +} + +TEST(WhenSortedByTest, CanDescribeSelf) { + const Matcher > m = WhenSortedBy(less(), ElementsAre(1, 2)); + EXPECT_EQ("(when sorted) has 2 elements where\n" + "element #0 is equal to 1,\n" + "element #1 is equal to 2", + Describe(m)); + EXPECT_EQ("(when sorted) doesn't have 2 elements, or\n" + "element #0 isn't equal to 1, or\n" + "element #1 isn't equal to 2", + DescribeNegation(m)); +} + +TEST(WhenSortedByTest, ExplainsMatchResult) { + const int a[] = { 2, 1 }; + EXPECT_EQ("which is { 1, 2 } when sorted, whose element #0 doesn't match", + Explain(WhenSortedBy(less(), ElementsAre(2, 3)), a)); + EXPECT_EQ("which is { 1, 2 } when sorted", + Explain(WhenSortedBy(less(), ElementsAre(1, 2)), a)); +} + +// WhenSorted() is a simple wrapper on WhenSortedBy(). Hence we don't +// need to test it as exhaustively as we test the latter. + +TEST(WhenSortedTest, WorksForEmptyContainer) { + const vector numbers; + EXPECT_THAT(numbers, WhenSorted(ElementsAre())); + EXPECT_THAT(numbers, Not(WhenSorted(ElementsAre(1)))); +} + +TEST(WhenSortedTest, WorksForNonEmptyContainer) { + list words; + words.push_back("3"); + words.push_back("1"); + words.push_back("2"); + words.push_back("2"); + EXPECT_THAT(words, WhenSorted(ElementsAre("1", "2", "2", "3"))); + EXPECT_THAT(words, Not(WhenSorted(ElementsAre("3", "1", "2", "2")))); +} + // Tests IsReadableTypeName(). TEST(IsReadableTypeNameTest, ReturnsTrueForShortNames) { -- cgit v1.2.3 From 0fd839682765307c49f9aa67b5c168e3d30bc356 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 28 Sep 2011 18:32:59 +0000 Subject: Modifies gmock_doctor.py to work with GCC output that contains file:line:char positions and left and right quote characters (U+2018 and U+2019) instead of apostrophes (U+0027). --- scripts/gmock_doctor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index ea930a38..4cfd1493 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -128,7 +128,7 @@ _COMMON_GMOCK_SYMBOLS = [ ] # Regex for matching source file path and line number in the compiler's errors. -_GCC_FILE_LINE_RE = r'(?P.*):(?P\d+):\s+' +_GCC_FILE_LINE_RE = r'(?P.*):(?P\d+):(\d+:)?\s+' _CLANG_FILE_LINE_RE = r'(?P.*):(?P\d+):(?P\d+):\s+' _CLANG_NON_GMOCK_FILE_LINE_RE = ( r'(?P.*[/\\^](?!gmock-)[^/\\]+):(?P\d+):(?P\d+):\s+') @@ -559,6 +559,9 @@ def Diagnose(msg): """Generates all possible diagnoses given the compiler error message.""" msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting. + # Assuming the string is using the UTF-8 encoding, replaces the left and + # the right single quote characters with apostrophes. + msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg) diagnoses = [] for diagnoser in _DIAGNOSERS: -- cgit v1.2.3 From f44bdc739896bf4085c0aeddb50b5e8f96957901 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 24 Oct 2011 17:48:54 +0000 Subject: Fixed Google Mock Doctor Clang regexes to work on both k8 and piii (by Greg Miller). --- scripts/gmock_doctor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 4cfd1493..61bbea62 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -422,7 +422,7 @@ def _NeedToUseReturnNullDiagnoser(msg): r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' r'of function template specialization ' - r'\'testing::internal::ReturnAction::operator ' + r'\'testing::internal::ReturnAction<(int|long)>::operator ' r'Action<(?P.*)\(\)>\' requested here') diagnosis = """ You are probably calling Return(NULL) and the compiler isn't sure how to turn -- cgit v1.2.3 From 4d60a596b4135c5a7e21ef7b4fe24a5c90329e0f Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 24 Oct 2011 21:16:22 +0000 Subject: Expressed the thread-safety annotations in code, replacing the existing comment-based system (by Aaron Jacobs). --- include/gmock/gmock-spec-builders.h | 222 +++++++++++++++++++----------------- src/gmock-spec-builders.cc | 104 ++++++++--------- 2 files changed, 168 insertions(+), 158 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 66a36e8a..1953e43a 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -127,12 +127,12 @@ class GTEST_API_ UntypedFunctionMockerBase { // Verifies that all expectations on this mock function have been // satisfied. Reports one or more Google Test non-fatal failures // and returns false if not. - // L >= g_gmock_mutex - bool VerifyAndClearExpectationsLocked(); + bool VerifyAndClearExpectationsLocked() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex); // Clears the ON_CALL()s set on this mock function. - // L >= g_gmock_mutex - virtual void ClearDefaultActionsLocked() = 0; + virtual void ClearDefaultActionsLocked() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) = 0; // In all of the following Untyped* functions, it's the caller's // responsibility to guarantee the correctness of the arguments' @@ -157,9 +157,10 @@ class GTEST_API_ UntypedFunctionMockerBase { // Writes a message that the call is uninteresting (i.e. neither // explicitly expected nor explicitly unexpected) to the given // ostream. - // L < g_gmock_mutex - virtual void UntypedDescribeUninterestingCall(const void* untyped_args, - ::std::ostream* os) const = 0; + virtual void UntypedDescribeUninterestingCall( + const void* untyped_args, + ::std::ostream* os) const + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) = 0; // Returns the expectation that matches the given function arguments // (or NULL is there's no match); when a match is found, @@ -167,11 +168,11 @@ class GTEST_API_ UntypedFunctionMockerBase { // performed (or NULL if the action is "do default"), and // is_excessive is modified to indicate whether the call exceeds the // expected number. - // L < g_gmock_mutex virtual const ExpectationBase* UntypedFindMatchingExpectation( const void* untyped_args, const void** untyped_action, bool* is_excessive, - ::std::ostream* what, ::std::ostream* why) = 0; + ::std::ostream* what, ::std::ostream* why) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) = 0; // Prints the given function arguments to the ostream. virtual void UntypedPrintArgs(const void* untyped_args, @@ -182,33 +183,33 @@ class GTEST_API_ UntypedFunctionMockerBase { // whenever an EXPECT_CALL() or ON_CALL() is executed on this mock // method. // TODO(wan@google.com): rename to SetAndRegisterOwner(). - // L < g_gmock_mutex - void RegisterOwner(const void* mock_obj); + void RegisterOwner(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex); // Sets the mock object this mock method belongs to, and sets the // name of the mock function. Will be called upon each invocation // of this mock function. - // L < g_gmock_mutex - void SetOwnerAndName(const void* mock_obj, const char* name); + void SetOwnerAndName(const void* mock_obj, const char* name) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex); // Returns the mock object this mock method belongs to. Must be // called after RegisterOwner() or SetOwnerAndName() has been // called. - // L < g_gmock_mutex - const void* MockObject() const; + const void* MockObject() const + GTEST_LOCK_EXCLUDED_(g_gmock_mutex); // Returns the name of this mock method. Must be called after // SetOwnerAndName() has been called. - // L < g_gmock_mutex - const char* Name() const; + const char* Name() const + GTEST_LOCK_EXCLUDED_(g_gmock_mutex); // Returns the result of invoking this mock function with the given // arguments. This function can be safely called from multiple // threads concurrently. The caller is responsible for deleting the // result. - // L < g_gmock_mutex const UntypedActionResultHolderBase* UntypedInvokeWith( - const void* untyped_args); + const void* untyped_args) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex); protected: typedef std::vector UntypedOnCallSpecs; @@ -369,17 +370,20 @@ class GTEST_API_ Mock { // Tells Google Mock to ignore mock_obj when checking for leaked // mock objects. - static void AllowLeak(const void* mock_obj); + static void AllowLeak(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Verifies and clears all expectations on the given mock object. // If the expectations aren't satisfied, generates one or more // Google Test non-fatal failures and returns false. - static bool VerifyAndClearExpectations(void* mock_obj); + static bool VerifyAndClearExpectations(void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Verifies all expectations on the given mock object and clears its // default actions and expectations. Returns true iff the // verification was successful. - static bool VerifyAndClear(void* mock_obj); + static bool VerifyAndClear(void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); private: friend class internal::UntypedFunctionMockerBase; @@ -396,58 +400,59 @@ class GTEST_API_ Mock { // Tells Google Mock to allow uninteresting calls on the given mock // object. - // L < g_gmock_mutex - static void AllowUninterestingCalls(const void* mock_obj); + static void AllowUninterestingCalls(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Tells Google Mock to warn the user about uninteresting calls on // the given mock object. - // L < g_gmock_mutex - static void WarnUninterestingCalls(const void* mock_obj); + static void WarnUninterestingCalls(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Tells Google Mock to fail uninteresting calls on the given mock // object. - // L < g_gmock_mutex - static void FailUninterestingCalls(const void* mock_obj); + static void FailUninterestingCalls(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Tells Google Mock the given mock object is being destroyed and // its entry in the call-reaction table should be removed. - // L < g_gmock_mutex - static void UnregisterCallReaction(const void* mock_obj); + static void UnregisterCallReaction(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Returns the reaction Google Mock will have on uninteresting calls // made on the given mock object. - // L < g_gmock_mutex static internal::CallReaction GetReactionOnUninterestingCalls( const void* mock_obj); + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Verifies that all expectations on the given mock object have been // satisfied. Reports one or more Google Test non-fatal failures // and returns false if not. - // L >= g_gmock_mutex - static bool VerifyAndClearExpectationsLocked(void* mock_obj); + static bool VerifyAndClearExpectationsLocked(void* mock_obj) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex); // Clears all ON_CALL()s set on the given mock object. - // L >= g_gmock_mutex - static void ClearDefaultActionsLocked(void* mock_obj); + static void ClearDefaultActionsLocked(void* mock_obj) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex); // Registers a mock object and a mock method it owns. - // L < g_gmock_mutex - static void Register(const void* mock_obj, - internal::UntypedFunctionMockerBase* mocker); + static void Register( + const void* mock_obj, + internal::UntypedFunctionMockerBase* mocker) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Tells Google Mock where in the source code mock_obj is used in an // ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this // information helps the user identify which object it is. - // L < g_gmock_mutex static void RegisterUseByOnCallOrExpectCall( - const void* mock_obj, const char* file, int line); + const void* mock_obj, const char* file, int line) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Unregisters a mock method; removes the owning mock object from // the registry when the last mock method associated with it has // been unregistered. This is called only in the destructor of // FunctionMockerBase. - // L >= g_gmock_mutex - static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker); + static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex); }; // class Mock // An abstract handle of an expectation. Useful in the .After() @@ -695,8 +700,8 @@ class GTEST_API_ ExpectationBase { // Describes how many times a function call matching this // expectation has occurred. - // L >= g_gmock_mutex - void DescribeCallCountTo(::std::ostream* os) const; + void DescribeCallCountTo(::std::ostream* os) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex); // If this mock method has an extra matcher (i.e. .With(matcher)), // describes it to the ostream. @@ -752,62 +757,62 @@ class GTEST_API_ ExpectationBase { // the current thread. // Retires all pre-requisites of this expectation. - // L >= g_gmock_mutex - void RetireAllPreRequisites(); + void RetireAllPreRequisites() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex); // Returns true iff this expectation is retired. - // L >= g_gmock_mutex - bool is_retired() const { + bool is_retired() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); return retired_; } // Retires this expectation. - // L >= g_gmock_mutex - void Retire() { + void Retire() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); retired_ = true; } // Returns true iff this expectation is satisfied. - // L >= g_gmock_mutex - bool IsSatisfied() const { + bool IsSatisfied() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); return cardinality().IsSatisfiedByCallCount(call_count_); } // Returns true iff this expectation is saturated. - // L >= g_gmock_mutex - bool IsSaturated() const { + bool IsSaturated() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); return cardinality().IsSaturatedByCallCount(call_count_); } // Returns true iff this expectation is over-saturated. - // L >= g_gmock_mutex - bool IsOverSaturated() const { + bool IsOverSaturated() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); return cardinality().IsOverSaturatedByCallCount(call_count_); } // Returns true iff all pre-requisites of this expectation are satisfied. - // L >= g_gmock_mutex - bool AllPrerequisitesAreSatisfied() const; + bool AllPrerequisitesAreSatisfied() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex); // Adds unsatisfied pre-requisites of this expectation to 'result'. - // L >= g_gmock_mutex - void FindUnsatisfiedPrerequisites(ExpectationSet* result) const; + void FindUnsatisfiedPrerequisites(ExpectationSet* result) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex); // Returns the number this expectation has been invoked. - // L >= g_gmock_mutex - int call_count() const { + int call_count() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); return call_count_; } // Increments the number this expectation has been invoked. - // L >= g_gmock_mutex - void IncrementCallCount() { + void IncrementCallCount() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); call_count_++; } @@ -816,8 +821,8 @@ class GTEST_API_ ExpectationBase { // WillRepeatedly() clauses) against the cardinality if this hasn't // been done before. Prints a warning if there are too many or too // few actions. - // L < mutex_ - void CheckActionCountIfNotDone() const; + void CheckActionCountIfNotDone() const + GTEST_LOCK_EXCLUDED_(mutex_); friend class ::testing::Sequence; friend class ::testing::internal::ExpectationTester; @@ -1069,15 +1074,15 @@ class TypedExpectation : public ExpectationBase { // g_gmock_mutex. // Returns true iff this expectation matches the given arguments. - // L >= g_gmock_mutex - bool Matches(const ArgumentTuple& args) const { + bool Matches(const ArgumentTuple& args) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); return TupleMatches(matchers_, args) && extra_matcher_.Matches(args); } // Returns true iff this expectation should handle the given arguments. - // L >= g_gmock_mutex - bool ShouldHandleArguments(const ArgumentTuple& args) const { + bool ShouldHandleArguments(const ArgumentTuple& args) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); // In case the action count wasn't checked when the expectation @@ -1090,9 +1095,10 @@ class TypedExpectation : public ExpectationBase { // Describes the result of matching the arguments against this // expectation to the given ostream. - // L >= g_gmock_mutex - void ExplainMatchResultTo(const ArgumentTuple& args, - ::std::ostream* os) const { + void ExplainMatchResultTo( + const ArgumentTuple& args, + ::std::ostream* os) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); if (is_retired()) { @@ -1134,9 +1140,10 @@ class TypedExpectation : public ExpectationBase { } // Returns the action that should be taken for the current invocation. - // L >= g_gmock_mutex - const Action& GetCurrentAction(const FunctionMockerBase* mocker, - const ArgumentTuple& args) const { + const Action& GetCurrentAction( + const FunctionMockerBase* mocker, + const ArgumentTuple& args) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); const int count = call_count(); Assert(count >= 1, __FILE__, __LINE__, @@ -1170,11 +1177,12 @@ class TypedExpectation : public ExpectationBase { // Mock does it to 'why'. This method is not const as it calls // IncrementCallCount(). A return value of NULL means the default // action. - // L >= g_gmock_mutex - const Action* GetActionForArguments(const FunctionMockerBase* mocker, - const ArgumentTuple& args, - ::std::ostream* what, - ::std::ostream* why) { + const Action* GetActionForArguments( + const FunctionMockerBase* mocker, + const ArgumentTuple& args, + ::std::ostream* what, + ::std::ostream* why) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); if (IsSaturated()) { // We have an excessive call. @@ -1393,8 +1401,8 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // The destructor verifies that all expectations on this mock // function have been satisfied. If not, it will report Google Test // non-fatal failures for the violations. - // L < g_gmock_mutex - virtual ~FunctionMockerBase() { + virtual ~FunctionMockerBase() + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { MutexLock l(&g_gmock_mutex); VerifyAndClearExpectationsLocked(); Mock::UnregisterLocked(this); @@ -1464,8 +1472,8 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Implements UntypedFunctionMockerBase::ClearDefaultActionsLocked(): // clears the ON_CALL()s set on this mock function. - // L >= g_gmock_mutex - virtual void ClearDefaultActionsLocked() { + virtual void ClearDefaultActionsLocked() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); for (UntypedOnCallSpecs::const_iterator it = untyped_on_call_specs_.begin(); @@ -1484,17 +1492,17 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Returns the result of invoking this mock function with the given // arguments. This function can be safely called from multiple // threads concurrently. - // L < g_gmock_mutex - Result InvokeWith(const ArgumentTuple& args) { + Result InvokeWith(const ArgumentTuple& args) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { return static_cast( this->UntypedInvokeWith(&args))->GetValueAndDelete(); } // Adds and returns a default action spec for this mock function. - // L < g_gmock_mutex OnCallSpec& AddNewOnCallSpec( const char* file, int line, - const ArgumentMatcherTuple& m) { + const ArgumentMatcherTuple& m) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); OnCallSpec* const on_call_spec = new OnCallSpec(file, line, m); untyped_on_call_specs_.push_back(on_call_spec); @@ -1502,12 +1510,12 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { } // Adds and returns an expectation spec for this mock function. - // L < g_gmock_mutex TypedExpectation& AddNewExpectation( const char* file, int line, const string& source_text, - const ArgumentMatcherTuple& m) { + const ArgumentMatcherTuple& m) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); TypedExpectation* const expectation = new TypedExpectation(this, file, line, source_text, m); @@ -1552,9 +1560,10 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Writes a message that the call is uninteresting (i.e. neither // explicitly expected nor explicitly unexpected) to the given // ostream. - // L < g_gmock_mutex - virtual void UntypedDescribeUninterestingCall(const void* untyped_args, - ::std::ostream* os) const { + virtual void UntypedDescribeUninterestingCall( + const void* untyped_args, + ::std::ostream* os) const + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { const ArgumentTuple& args = *static_cast(untyped_args); *os << "Uninteresting mock function call - "; @@ -1579,11 +1588,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // section. The reason is that we have no control on what the // action does (it can invoke an arbitrary user function or even a // mock function) and excessive locking could cause a dead lock. - // L < g_gmock_mutex virtual const ExpectationBase* UntypedFindMatchingExpectation( const void* untyped_args, const void** untyped_action, bool* is_excessive, - ::std::ostream* what, ::std::ostream* why) { + ::std::ostream* what, ::std::ostream* why) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { const ArgumentTuple& args = *static_cast(untyped_args); MutexLock l(&g_gmock_mutex); @@ -1614,9 +1623,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Returns the expectation that matches the arguments, or NULL if no // expectation matches them. - // L >= g_gmock_mutex TypedExpectation* FindMatchingExpectationLocked( - const ArgumentTuple& args) const { + const ArgumentTuple& args) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); for (typename UntypedExpectations::const_reverse_iterator it = untyped_expectations_.rbegin(); @@ -1631,10 +1640,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { } // Returns a message that the arguments don't match any expectation. - // L >= g_gmock_mutex - void FormatUnexpectedCallMessageLocked(const ArgumentTuple& args, - ::std::ostream* os, - ::std::ostream* why) const { + void FormatUnexpectedCallMessageLocked( + const ArgumentTuple& args, + ::std::ostream* os, + ::std::ostream* why) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); *os << "\nUnexpected mock function call - "; DescribeDefaultActionTo(args, os); @@ -1643,9 +1653,10 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Prints a list of expectations that have been tried against the // current mock function call. - // L >= g_gmock_mutex - void PrintTriedExpectationsLocked(const ArgumentTuple& args, - ::std::ostream* why) const { + void PrintTriedExpectationsLocked( + const ArgumentTuple& args, + ::std::ostream* why) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); const int count = static_cast(untyped_expectations_.size()); *why << "Google Mock tried the following " << count << " " @@ -1694,7 +1705,6 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // Verifies that all expectations on this mock function have been // satisfied. Reports one or more Google Test non-fatal failures and // returns false if not. -// L >= g_gmock_mutex // Reports an uninteresting call (whose description is in msg) in the // manner specified by 'reaction'. diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index c192f96c..06299784 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -92,7 +92,8 @@ void ExpectationBase::SpecifyCardinality(const Cardinality& a_cardinality) { } // Retires all pre-requisites of this expectation. -void ExpectationBase::RetireAllPreRequisites() { +void ExpectationBase::RetireAllPreRequisites() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { if (is_retired()) { // We can take this short-cut as we never retire an expectation // until we have retired all its pre-requisites. @@ -111,8 +112,8 @@ void ExpectationBase::RetireAllPreRequisites() { // Returns true iff all pre-requisites of this expectation have been // satisfied. -// L >= g_gmock_mutex -bool ExpectationBase::AllPrerequisitesAreSatisfied() const { +bool ExpectationBase::AllPrerequisitesAreSatisfied() const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin(); it != immediate_prerequisites_.end(); ++it) { @@ -124,9 +125,8 @@ bool ExpectationBase::AllPrerequisitesAreSatisfied() const { } // Adds unsatisfied pre-requisites of this expectation to 'result'. -// L >= g_gmock_mutex -void ExpectationBase::FindUnsatisfiedPrerequisites( - ExpectationSet* result) const { +void ExpectationBase::FindUnsatisfiedPrerequisites(ExpectationSet* result) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin(); it != immediate_prerequisites_.end(); ++it) { @@ -147,8 +147,8 @@ void ExpectationBase::FindUnsatisfiedPrerequisites( // Describes how many times a function call matching this // expectation has occurred. -// L >= g_gmock_mutex -void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const { +void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); // Describes how many times the function is expected to be called. @@ -170,8 +170,8 @@ void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const { // WillRepeatedly() clauses) against the cardinality if this hasn't // been done before. Prints a warning if there are too many or too // few actions. -// L < mutex_ -void ExpectationBase::CheckActionCountIfNotDone() const { +void ExpectationBase::CheckActionCountIfNotDone() const + GTEST_LOCK_EXCLUDED_(mutex_) { bool should_check = false; { MutexLock l(&mutex_); @@ -266,8 +266,8 @@ UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {} // this information in the global mock registry. Will be called // whenever an EXPECT_CALL() or ON_CALL() is executed on this mock // method. -// L < g_gmock_mutex -void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj) { +void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { { MutexLock l(&g_gmock_mutex); mock_obj_ = mock_obj; @@ -278,9 +278,9 @@ void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj) { // Sets the mock object this mock method belongs to, and sets the name // of the mock function. Will be called upon each invocation of this // mock function. -// L < g_gmock_mutex -void UntypedFunctionMockerBase::SetOwnerAndName( - const void* mock_obj, const char* name) { +void UntypedFunctionMockerBase::SetOwnerAndName(const void* mock_obj, + const char* name) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { // We protect name_ under g_gmock_mutex in case this mock function // is called from two threads concurrently. MutexLock l(&g_gmock_mutex); @@ -290,8 +290,8 @@ void UntypedFunctionMockerBase::SetOwnerAndName( // Returns the name of the function being mocked. Must be called // after RegisterOwner() or SetOwnerAndName() has been called. -// L < g_gmock_mutex -const void* UntypedFunctionMockerBase::MockObject() const { +const void* UntypedFunctionMockerBase::MockObject() const + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { const void* mock_obj; { // We protect mock_obj_ under g_gmock_mutex in case this mock @@ -307,8 +307,8 @@ const void* UntypedFunctionMockerBase::MockObject() const { // Returns the name of this mock method. Must be called after // SetOwnerAndName() has been called. -// L < g_gmock_mutex -const char* UntypedFunctionMockerBase::Name() const { +const char* UntypedFunctionMockerBase::Name() const + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { const char* name; { // We protect name_ under g_gmock_mutex in case this mock @@ -325,9 +325,9 @@ const char* UntypedFunctionMockerBase::Name() const { // Calculates the result of invoking this mock function with the given // arguments, prints it, and returns it. The caller is responsible // for deleting the result. -// L < g_gmock_mutex const UntypedActionResultHolderBase* -UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) { +UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { if (untyped_expectations_.size() == 0) { // No expectation is set on this mock method - we have an // uninteresting call. @@ -453,8 +453,8 @@ Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) { // Verifies that all expectations on this mock function have been // satisfied. Reports one or more Google Test non-fatal failures // and returns false if not. -// L >= g_gmock_mutex -bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked() { +bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked() + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); bool expectations_met = true; for (UntypedExpectations::const_iterator it = @@ -578,9 +578,9 @@ std::map g_uninteresting_call_reaction; // Sets the reaction Google Mock should have when an uninteresting // method of the given mock object is called. -// L < g_gmock_mutex void SetReactionOnUninterestingCalls(const void* mock_obj, - internal::CallReaction reaction) { + internal::CallReaction reaction) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); g_uninteresting_call_reaction[mock_obj] = reaction; } @@ -589,38 +589,38 @@ void SetReactionOnUninterestingCalls(const void* mock_obj, // Tells Google Mock to allow uninteresting calls on the given mock // object. -// L < g_gmock_mutex -void Mock::AllowUninterestingCalls(const void* mock_obj) { +void Mock::AllowUninterestingCalls(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { SetReactionOnUninterestingCalls(mock_obj, internal::ALLOW); } // Tells Google Mock to warn the user about uninteresting calls on the // given mock object. -// L < g_gmock_mutex -void Mock::WarnUninterestingCalls(const void* mock_obj) { +void Mock::WarnUninterestingCalls(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { SetReactionOnUninterestingCalls(mock_obj, internal::WARN); } // Tells Google Mock to fail uninteresting calls on the given mock // object. -// L < g_gmock_mutex -void Mock::FailUninterestingCalls(const void* mock_obj) { +void Mock::FailUninterestingCalls(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { SetReactionOnUninterestingCalls(mock_obj, internal::FAIL); } // Tells Google Mock the given mock object is being destroyed and its // entry in the call-reaction table should be removed. -// L < g_gmock_mutex -void Mock::UnregisterCallReaction(const void* mock_obj) { +void Mock::UnregisterCallReaction(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); g_uninteresting_call_reaction.erase(mock_obj); } // Returns the reaction Google Mock will have on uninteresting calls // made on the given mock object. -// L < g_gmock_mutex internal::CallReaction Mock::GetReactionOnUninterestingCalls( - const void* mock_obj) { + const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); return (g_uninteresting_call_reaction.count(mock_obj) == 0) ? internal::WARN : g_uninteresting_call_reaction[mock_obj]; @@ -628,8 +628,8 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls( // Tells Google Mock to ignore mock_obj when checking for leaked mock // objects. -// L < g_gmock_mutex -void Mock::AllowLeak(const void* mock_obj) { +void Mock::AllowLeak(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); g_mock_object_registry.states()[mock_obj].leakable = true; } @@ -637,8 +637,8 @@ void Mock::AllowLeak(const void* mock_obj) { // Verifies and clears all expectations on the given mock object. If // the expectations aren't satisfied, generates one or more Google // Test non-fatal failures and returns false. -// L < g_gmock_mutex -bool Mock::VerifyAndClearExpectations(void* mock_obj) { +bool Mock::VerifyAndClearExpectations(void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); return VerifyAndClearExpectationsLocked(mock_obj); } @@ -646,8 +646,8 @@ bool Mock::VerifyAndClearExpectations(void* mock_obj) { // Verifies all expectations on the given mock object and clears its // default actions and expectations. Returns true iff the // verification was successful. -// L < g_gmock_mutex -bool Mock::VerifyAndClear(void* mock_obj) { +bool Mock::VerifyAndClear(void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); ClearDefaultActionsLocked(mock_obj); return VerifyAndClearExpectationsLocked(mock_obj); @@ -656,8 +656,8 @@ bool Mock::VerifyAndClear(void* mock_obj) { // Verifies and clears all expectations on the given mock object. If // the expectations aren't satisfied, generates one or more Google // Test non-fatal failures and returns false. -// L >= g_gmock_mutex -bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) { +bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) { internal::g_gmock_mutex.AssertHeld(); if (g_mock_object_registry.states().count(mock_obj) == 0) { // No EXPECT_CALL() was set on the given mock object. @@ -682,9 +682,9 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) { } // Registers a mock object and a mock method it owns. -// L < g_gmock_mutex void Mock::Register(const void* mock_obj, - internal::UntypedFunctionMockerBase* mocker) { + internal::UntypedFunctionMockerBase* mocker) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker); } @@ -692,9 +692,9 @@ void Mock::Register(const void* mock_obj, // Tells Google Mock where in the source code mock_obj is used in an // ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this // information helps the user identify which object it is. -// L < g_gmock_mutex -void Mock::RegisterUseByOnCallOrExpectCall( - const void* mock_obj, const char* file, int line) { +void Mock::RegisterUseByOnCallOrExpectCall(const void* mock_obj, + const char* file, int line) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); MockObjectState& state = g_mock_object_registry.states()[mock_obj]; if (state.first_used_file == NULL) { @@ -716,8 +716,8 @@ void Mock::RegisterUseByOnCallOrExpectCall( // registry when the last mock method associated with it has been // unregistered. This is called only in the destructor of // FunctionMockerBase. -// L >= g_gmock_mutex -void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) { +void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) { internal::g_gmock_mutex.AssertHeld(); for (MockObjectRegistry::StateMap::iterator it = g_mock_object_registry.states().begin(); @@ -734,8 +734,8 @@ void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) { } // Clears all ON_CALL()s set on the given mock object. -// L >= g_gmock_mutex -void Mock::ClearDefaultActionsLocked(void* mock_obj) { +void Mock::ClearDefaultActionsLocked(void* mock_obj) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) { internal::g_gmock_mutex.AssertHeld(); if (g_mock_object_registry.states().count(mock_obj) == 0) { -- cgit v1.2.3 From 9bcb5f9146db42bc38b6bb744fb0cf518a0205be Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 24 Oct 2011 23:41:07 +0000 Subject: Fixes a lock reentrancy when destroying a mock causes destruction of another mock (issue 79) (by Aaron Jacobs). --- include/gmock/gmock-spec-builders.h | 21 ++++++++++++--- src/gmock-spec-builders.cc | 16 ++++++++++- test/gmock-spec-builders_test.cc | 53 ++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 1953e43a..36c47d67 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1475,12 +1475,27 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { virtual void ClearDefaultActionsLocked() GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); + + // Deleting our default actions may trigger other mock objects to be + // deleted, for example if an action contains a reference counted smart + // pointer to that mock object, and that is the last reference. So if we + // delete our actions within the context of the global mutex we may deadlock + // when this method is called again. Instead, make a copy of the set of + // actions to delete, clear our set within the mutex, and then delete the + // actions outside of the mutex. + UntypedOnCallSpecs specs_to_delete; + untyped_on_call_specs_.swap(specs_to_delete); + + g_gmock_mutex.Unlock(); for (UntypedOnCallSpecs::const_iterator it = - untyped_on_call_specs_.begin(); - it != untyped_on_call_specs_.end(); ++it) { + specs_to_delete.begin(); + it != specs_to_delete.end(); ++it) { delete static_cast*>(*it); } - untyped_on_call_specs_.clear(); + + // Lock the mutex again, since the caller expects it to be locked when we + // return. + g_gmock_mutex.Lock(); } protected: diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 06299784..6599325d 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -480,7 +480,21 @@ bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked() untyped_expectation->line(), ss.str()); } } - untyped_expectations_.clear(); + + // Deleting our expectations may trigger other mock objects to be deleted, for + // example if an action contains a reference counted smart pointer to that + // mock object, and that is the last reference. So if we delete our + // expectations within the context of the global mutex we may deadlock when + // this method is called again. Instead, make a copy of the set of + // expectations to delete, clear our set within the mutex, and then clear the + // copied set outside of it. + UntypedExpectations expectations_to_delete; + untyped_expectations_.swap(expectations_to_delete); + + g_gmock_mutex.Unlock(); + expectations_to_delete.clear(); + g_gmock_mutex.Lock(); + return expectations_met; } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 29d47d12..9177b322 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -88,13 +88,14 @@ using testing::Mock; using testing::Ne; using testing::Return; using testing::Sequence; +using testing::SetArgPointee; using testing::internal::ExpectationTester; using testing::internal::FormatFileLocation; -using testing::internal::g_gmock_mutex; using testing::internal::kErrorVerbosity; using testing::internal::kInfoVerbosity; using testing::internal::kWarningVerbosity; using testing::internal::String; +using testing::internal::linked_ptr; using testing::internal::string; #if GTEST_HAS_STREAM_REDIRECTION @@ -157,6 +158,16 @@ class MockB { GTEST_DISALLOW_COPY_AND_ASSIGN_(MockB); }; +class ReferenceHoldingMock { + public: + ReferenceHoldingMock() {} + + MOCK_METHOD1(AcceptReference, void(linked_ptr*)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReferenceHoldingMock); +}; + // Tests that EXPECT_CALL and ON_CALL compile in a presence of macro // redefining a mock method name. This could happen, for example, when // the tested code #includes Win32 API headers which define many APIs @@ -2439,6 +2450,46 @@ TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) { EXPECT_EQ(2, b1.DoB(0)); } +TEST(VerifyAndClearTest, + DestroyingChainedMocksDoesNotDeadlockThroughExpectations) { + linked_ptr a(new MockA); + ReferenceHoldingMock test_mock; + + // EXPECT_CALL stores a reference to a inside test_mock. + EXPECT_CALL(test_mock, AcceptReference(_)) + .WillRepeatedly(SetArgPointee<0>(a)); + + // Throw away the reference to the mock that we have in a. After this, the + // only reference to it is stored by test_mock. + a.reset(); + + // When test_mock goes out of scope, it destroys the last remaining reference + // to the mock object originally pointed to by a. This will cause the MockA + // destructor to be called from inside the ReferenceHoldingMock destructor. + // The state of all mocks is protected by a single global lock, but there + // should be no deadlock. +} + +TEST(VerifyAndClearTest, + DestroyingChainedMocksDoesNotDeadlockThroughDefaultAction) { + linked_ptr a(new MockA); + ReferenceHoldingMock test_mock; + + // ON_CALL stores a reference to a inside test_mock. + ON_CALL(test_mock, AcceptReference(_)) + .WillByDefault(SetArgPointee<0>(a)); + + // Throw away the reference to the mock that we have in a. After this, the + // only reference to it is stored by test_mock. + a.reset(); + + // When test_mock goes out of scope, it destroys the last remaining reference + // to the mock object originally pointed to by a. This will cause the MockA + // destructor to be called from inside the ReferenceHoldingMock destructor. + // The state of all mocks is protected by a single global lock, but there + // should be no deadlock. +} + // Tests that a mock function's action can call a mock function // (either the same function or a different one) either as an explicit // action or as a default action without causing a dead lock. It -- cgit v1.2.3 From 79a367eb217fcd47e2beaf8c0f87fe6d5926f739 Mon Sep 17 00:00:00 2001 From: jgm Date: Tue, 10 Apr 2012 16:02:11 +0000 Subject: Reduced template instantiation depth for the AllOf and AnyOf matchers. Also some formatting changes. --- include/gmock/gmock-actions.h | 8 +- include/gmock/gmock-cardinalities.h | 1 + include/gmock/gmock-generated-actions.h | 27 +- include/gmock/gmock-generated-actions.h.pump | 9 +- include/gmock/gmock-generated-matchers.h | 488 ++++++++++++++------- include/gmock/gmock-generated-matchers.h.pump | 110 +++-- include/gmock/gmock-matchers.h | 185 +++++--- include/gmock/gmock-spec-builders.h | 1 + .../internal/gmock-generated-internal-utils.h | 6 +- .../internal/gmock-generated-internal-utils.h.pump | 2 +- include/gmock/internal/gmock-internal-utils.h | 8 +- scripts/gmock_doctor.py | 2 +- src/gmock-cardinalities.cc | 3 +- src/gmock-spec-builders.cc | 1 + test/gmock-actions_test.cc | 13 +- test/gmock-generated-function-mockers_test.cc | 10 +- test/gmock-generated-matchers_test.cc | 14 + test/gmock-matchers_test.cc | 92 +++- test/gmock-more-actions_test.cc | 1 + test/gmock_link_test.h | 16 +- 20 files changed, 661 insertions(+), 336 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index d6a3e148..7e9708ec 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -36,13 +36,13 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ -#include -#include - #ifndef _WIN32_WCE # include #endif +#include +#include + #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" @@ -189,6 +189,7 @@ class DefaultValue { return value_ == NULL ? internal::BuiltInDefaultValue::Get() : *value_; } + private: static const T* value_; }; @@ -224,6 +225,7 @@ class DefaultValue { return address_ == NULL ? internal::BuiltInDefaultValue::Get() : *address_; } + private: static T* address_; }; diff --git a/include/gmock/gmock-cardinalities.h b/include/gmock/gmock-cardinalities.h index 759dcf8c..fc315f92 100644 --- a/include/gmock/gmock-cardinalities.h +++ b/include/gmock/gmock-cardinalities.h @@ -117,6 +117,7 @@ class GTEST_API_ Cardinality { // Describes the given actual call count to an ostream. static void DescribeActualCallCountTo(int actual_call_count, ::std::ostream* os); + private: internal::linked_ptr impl_; }; diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 635bb595..3b599b36 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -381,7 +381,6 @@ class CallableHelper { A7 a7, A8 a8, A9 a9, A10 a10) { return function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } - }; // class CallableHelper // An INTERNAL macro for extracting the type of a tuple field. It's @@ -1018,16 +1017,16 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, // 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_,\ + 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 @@ -1433,9 +1432,9 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, template \ template \ - template \ typename ::testing::internal::Function::Result\ GMOCK_ACTION_CLASS_(name, value_params)<\ diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 001fd7d0..57a7811a 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -136,7 +136,6 @@ $var Ts = [[$for j, [[T$j]]]] } ]] - }; // class CallableHelper // An INTERNAL macro for extracting the type of a tuple field. It's @@ -427,7 +426,7 @@ $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 [[,\ +$for k [[, \ arg$k[[]]_type arg$k GTEST_ATTRIBUTE_UNUSED_]] @@ -657,9 +656,9 @@ $for k [[, arg$k[[]]_type arg$k]]) const;\ template \ template \ - template \ typename ::testing::internal::Function::Result\ GMOCK_ACTION_CLASS_(name, value_params)<\ diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 6feaf1a2..5527ed3e 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -661,6 +661,182 @@ class ElementsAreMatcher10 { GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher10); }; +// 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 @@ -852,187 +1028,167 @@ ElementsAreArray(const T (&array)[N]) { // 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 internal::BothOfMatcher -AllOf(Matcher1 m1, Matcher2 m2) { - return internal::BothOfMatcher(m1, m2); +template +inline typename internal::AllOfResult2::type +AllOf(M1 m1, M2 m2) { + return typename internal::AllOfResult2::type( + m1, + m2); } -template -inline internal::BothOfMatcher > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3)); +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 internal::BothOfMatcher > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4)); +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 internal::BothOfMatcher > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5)); +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 internal::BothOfMatcher > > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6)); +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 internal::BothOfMatcher > > > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7)); +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 internal::BothOfMatcher > > > > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7, Matcher8 m8) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7, m8)); +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 internal::BothOfMatcher > > > > > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7, m8, m9)); +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 internal::BothOfMatcher > > > > > > > > -AllOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9, Matcher10 m10) { - return ::testing::AllOf(m1, ::testing::AllOf(m2, m3, m4, m5, m6, m7, m8, m9, - m10)); +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 internal::EitherOfMatcher -AnyOf(Matcher1 m1, Matcher2 m2) { - return internal::EitherOfMatcher(m1, m2); +template +inline typename internal::AnyOfResult2::type +AnyOf(M1 m1, M2 m2) { + return typename internal::AnyOfResult2::type( + m1, + m2); } -template -inline internal::EitherOfMatcher > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3)); +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 internal::EitherOfMatcher > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4)); +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 internal::EitherOfMatcher > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5)); +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 internal::EitherOfMatcher > > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6)); +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 internal::EitherOfMatcher > > > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7)); +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 internal::EitherOfMatcher > > > > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7, Matcher8 m8) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7, m8)); +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 internal::EitherOfMatcher > > > > > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7, m8, m9)); +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 internal::EitherOfMatcher > > > > > > > > -AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, - Matcher6 m6, Matcher7 m7, Matcher8 m8, Matcher9 m9, Matcher10 m10) { - return ::testing::AnyOf(m1, ::testing::AnyOf(m2, m3, m4, m5, m6, m7, m8, m9, - m10)); +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 @@ -1275,7 +1431,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple<>()));\ }\ @@ -1296,7 +1452,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, }\ template \ bool name##Matcher::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1324,7 +1480,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0)));\ }\ @@ -1348,7 +1504,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ template \ bool name##MatcherP::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1377,7 +1533,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1)));\ }\ @@ -1405,7 +1561,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ bool name##MatcherP2::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1435,7 +1591,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1, \ p2)));\ @@ -1465,7 +1621,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ bool name##MatcherP3::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1498,7 +1654,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1, p2, p3)));\ @@ -1534,7 +1690,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ bool name##MatcherP4::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1569,7 +1725,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1, p2, p3, p4)));\ @@ -1607,7 +1763,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ bool name##MatcherP5::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1643,7 +1799,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1, p2, p3, p4, p5)));\ @@ -1682,7 +1838,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ bool name##MatcherP6::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1721,7 +1877,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1, p2, p3, p4, p5, \ @@ -1766,7 +1922,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, template \ bool name##MatcherP7::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1806,7 +1962,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple(p0, p1, p2, \ @@ -1855,7 +2011,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, bool name##MatcherP8::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1897,7 +2053,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const @@ -1993,7 +2149,7 @@ AnyOf(Matcher1 m1, Matcher2 m2, Matcher3 m3, Matcher4 m4, Matcher5 m5, if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 8c09444c..7cdb84bf 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -242,6 +242,66 @@ $for j [[ ]] +// 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 @@ -308,19 +368,16 @@ ElementsAreArray(const T (&array)[N]) { $range i 2..n $for i [[ $range j 1..i -$range k 1..i-1 - -template <$for j, [[typename Matcher$j]]> -inline $for k[[internal::BothOfMatcher ]] - -AllOf($for j, [[Matcher$j m$j]]) { - -$if i == 2 [[ - return internal::BothOfMatcher(m1, m2); -]] $else [[ - return ::testing::AllOf(m1, ::testing::AllOf($for k, [[m$(k + 1)]])); -]] - +$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]])]]); } ]] @@ -331,19 +388,16 @@ $if i == 2 [[ $range i 2..n $for i [[ $range j 1..i -$range k 1..i-1 - -template <$for j, [[typename Matcher$j]]> -inline $for k[[internal::EitherOfMatcher ]] - -AnyOf($for j, [[Matcher$j m$j]]) { - -$if i == 2 [[ - return internal::EitherOfMatcher(m1, m2); -]] $else [[ - return ::testing::AnyOf(m1, ::testing::AnyOf($for k, [[m$(k + 1)]])); -]] - +$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]])]]); } ]] @@ -621,7 +675,7 @@ $var param_field_decls2 = [[$for j if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ - negation, #name,\ + negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::std::tr1::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]])));\ }\ @@ -642,7 +696,7 @@ $var param_field_decls2 = [[$for j }\$template template \ bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ - arg_type arg,\ + arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const ]] diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 89a9e2ec..4f1c433c 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -384,12 +384,119 @@ 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(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(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(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 -Matcher MatcherCast(M m); +inline Matcher MatcherCast(M matcher) { + return internal::MatcherCastImpl::Cast(matcher); +} // Implements SafeMatcherCast(). // @@ -401,11 +508,11 @@ Matcher MatcherCast(M m); template class SafeMatcherCastImpl { public: - // This overload handles polymorphic matchers only since monomorphic - // matchers are handled by the next one. + // This overload handles polymorphic matchers and values only since + // monomorphic matchers are handled by the next one. template - static inline Matcher Cast(M polymorphic_matcher) { - return Matcher(polymorphic_matcher); + static inline Matcher Cast(M polymorphic_matcher_or_value) { + return internal::MatcherCastImpl::Cast(polymorphic_matcher_or_value); } // This overload handles monomorphic matchers. @@ -600,67 +707,6 @@ void ExplainMatchFailureTupleTo(const MatcherTuple& matchers, matchers, values, os); } -// 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)). -template -class MatcherCastImpl { - public: - static Matcher Cast(M polymorphic_matcher) { - return Matcher(polymorphic_matcher); - } -}; - -// 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; } -}; - // Implements A(). template class AnyMatcherImpl : public MatcherInterface { @@ -1596,6 +1642,7 @@ class FloatingEqMatcher { operator Matcher() const { return MakeMatcher(new Impl(rhs_, nan_eq_nan_)); } + private: const FloatType rhs_; const bool nan_eq_nan_; @@ -2633,12 +2680,6 @@ GTEST_API_ string FormatMatcherDescription(bool negation, } // namespace internal -// Implements MatcherCast(). -template -inline Matcher MatcherCast(M matcher) { - return internal::MatcherCastImpl::Cast(matcher); -} - // _ is a matcher that matches anything of any type. // // This definition is fine as: diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 36c47d67..30721ce6 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -384,6 +384,7 @@ class GTEST_API_ Mock { // verification was successful. static bool VerifyAndClear(void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); + private: friend class internal::UntypedFunctionMockerBase; diff --git a/include/gmock/internal/gmock-generated-internal-utils.h b/include/gmock/internal/gmock-generated-internal-utils.h index 1b52dceb..02258451 100644 --- a/include/gmock/internal/gmock-generated-internal-utils.h +++ b/include/gmock/internal/gmock-generated-internal-utils.h @@ -1,4 +1,6 @@ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! +// This file was GENERATED by command: +// pump.py gmock-generated-internal-utils.h.pump +// DO NOT EDIT BY HAND!!! // Copyright 2007, Google Inc. // All rights reserved. @@ -58,7 +60,7 @@ class IgnoredValue { // deliberately omit the 'explicit' keyword in order to allow the // conversion to be implicit. template - IgnoredValue(const T&) {} + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) }; // MatcherTuple::type is a tuple type where each field is a Matcher diff --git a/include/gmock/internal/gmock-generated-internal-utils.h.pump b/include/gmock/internal/gmock-generated-internal-utils.h.pump index 821e474e..e7ecc8b8 100644 --- a/include/gmock/internal/gmock-generated-internal-utils.h.pump +++ b/include/gmock/internal/gmock-generated-internal-utils.h.pump @@ -61,7 +61,7 @@ class IgnoredValue { // deliberately omit the 'explicit' keyword in order to allow the // conversion to be implicit. template - IgnoredValue(const T&) {} + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) }; // MatcherTuple::type is a tuple type where each field is a Matcher diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 34131ef6..aef9388e 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -354,7 +354,8 @@ template struct remove_reference { typedef T type; }; // NOLINT // crashes). template inline T Invalid() { - return *static_cast::type*>(NULL); + return const_cast::type&>( + *static_cast::type*>(NULL)); } template <> inline void Invalid() {} @@ -459,6 +460,11 @@ class StlContainerView< ::std::tr1::tuple > { // StlContainer with a reference type. template class StlContainerView; +// Mapping from booleans to types. Similar to boost::bool_ and +// std::integral_constant. +template +struct BooleanConstant {}; + } // namespace internal } // namespace testing diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index 61bbea62..d5c45180 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -416,7 +416,7 @@ def _NeedToUseReturnNullDiagnoser(msg): '::operator testing::Action\(\) const.*\n' + _GCC_FILE_LINE_RE + r'instantiated from here\n' r'.*error: no matching function for call to \'ImplicitCast_\(' - r'long int&\)') + r'(:?long )?int&\)') clang_regex = (r'\bgmock-actions.h:.* error: no matching function for ' r'call to \'ImplicitCast_\'\r?\n' r'(.*\n)*?' + diff --git a/src/gmock-cardinalities.cc b/src/gmock-cardinalities.cc index 274f98a9..50ec7286 100644 --- a/src/gmock-cardinalities.cc +++ b/src/gmock-cardinalities.cc @@ -75,7 +75,7 @@ class BetweenCardinalityImpl : public CardinalityInterface { virtual int ConservativeUpperBound() const { return max_; } virtual bool IsSatisfiedByCallCount(int call_count) const { - return min_ <= call_count && call_count <= max_ ; + return min_ <= call_count && call_count <= max_; } virtual bool IsSaturatedByCallCount(int call_count) const { @@ -83,6 +83,7 @@ class BetweenCardinalityImpl : public CardinalityInterface { } virtual void DescribeTo(::std::ostream* os) const; + private: const int min_; const int max_; diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 6599325d..a93ea71a 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -579,6 +579,7 @@ class MockObjectRegistry { } StateMap& states() { return states_; } + private: StateMap states_; }; diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index b7803fe9..fd87c74c 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -518,7 +518,7 @@ TEST(ReturnTest, IsCovariant) { // gmock-actions.h for more information. class FromType { public: - FromType(bool* is_converted) : converted_(is_converted) {} + explicit FromType(bool* is_converted) : converted_(is_converted) {} bool* converted() const { return converted_; } private: @@ -529,7 +529,8 @@ class FromType { class ToType { public: - ToType(const FromType& x) { *x.converted() = true; } + // Must allow implicit conversion due to use in ImplicitCast_. + ToType(const FromType& x) { *x.converted() = true; } // NOLINT }; TEST(ReturnTest, ConvertsArgumentWhenConverted) { @@ -541,7 +542,7 @@ TEST(ReturnTest, ConvertsArgumentWhenConverted) { converted = false; action.Perform(tuple<>()); EXPECT_FALSE(converted) << "Action must NOT convert its argument " - << "when performed." ; + << "when performed."; } class DestinationType {}; @@ -1226,7 +1227,8 @@ TEST(ByRefTest, IsCopyable) { const std::string s1 = "Hi"; const std::string s2 = "Hello"; - ::testing::internal::ReferenceWrapper ref_wrapper = ByRef(s1); + ::testing::internal::ReferenceWrapper ref_wrapper = + ByRef(s1); const std::string& r1 = ref_wrapper; EXPECT_EQ(&s1, &r1); @@ -1235,7 +1237,8 @@ TEST(ByRefTest, IsCopyable) { const std::string& r2 = ref_wrapper; EXPECT_EQ(&s2, &r2); - ::testing::internal::ReferenceWrapper ref_wrapper1 = ByRef(s1); + ::testing::internal::ReferenceWrapper ref_wrapper1 = + ByRef(s1); // Copies ref_wrapper1 to ref_wrapper. ref_wrapper = ref_wrapper1; const std::string& r3 = ref_wrapper; diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index 0d90ded7..2087f991 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -35,11 +35,6 @@ #include "gmock/gmock-generated-function-mockers.h" -#include -#include -#include "gmock/gmock.h" -#include "gtest/gtest.h" - #if GTEST_OS_WINDOWS // MSDN says the header file to be included for STDMETHOD is BaseTyps.h but // we are getting compiler errors if we use basetyps.h, hence including @@ -47,6 +42,11 @@ # include #endif // GTEST_OS_WINDOWS +#include +#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" + // There is a bug in MSVC (fixed in VS 2008) that prevents creating a // mock for a function with const arguments, so we don't test such // cases for MSVC versions older than 2008. diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 819f1a83..b35c4505 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -1091,6 +1091,20 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { EXPECT_THAT(a, Contains(Not(Contains(5)))); } +TEST(AllOfTest, HugeMatcher) { + // Verify that using AllOf with many arguments doesn't cause + // the compiler to exceed template instantiation depth limit. + EXPECT_THAT(0, testing::AllOf(_, _, _, _, _, _, _, _, _, + testing::AllOf(_, _, _, _, _, _, _, _, _, _))); +} + +TEST(AnyOfTest, HugeMatcher) { + // Verify that using AnyOf with many arguments doesn't cause + // the compiler to exceed template instantiation depth limit. + EXPECT_THAT(0, testing::AnyOf(_, _, _, _, _, _, _, _, _, + testing::AnyOf(_, _, _, _, _, _, _, _, _, _))); +} + namespace adl_test { // Verifies that the implementation of ::testing::AllOf and ::testing::AnyOf diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index c4ed96ba..35d59fa8 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -545,6 +545,37 @@ TEST(MatcherCastTest, FromSameType) { EXPECT_FALSE(m2.Matches(1)); } +// Implicitly convertible form any type. +struct ConvertibleFromAny { + ConvertibleFromAny(int a_value) : value(a_value) {} + template + ConvertibleFromAny(const T& a_value) : value(-1) { + ADD_FAILURE() << "Conversion constructor called"; + } + int value; +}; + +bool operator==(const ConvertibleFromAny& a, const ConvertibleFromAny& b) { + return a.value == b.value; +} + +ostream& operator<<(ostream& os, const ConvertibleFromAny& a) { + return os << a.value; +} + +TEST(MatcherCastTest, ConversionConstructorIsUsed) { + Matcher m = MatcherCast(1); + EXPECT_TRUE(m.Matches(ConvertibleFromAny(1))); + EXPECT_FALSE(m.Matches(ConvertibleFromAny(2))); +} + +TEST(MatcherCastTest, FromConvertibleFromAny) { + Matcher m = + MatcherCast(Eq(ConvertibleFromAny(1))); + EXPECT_TRUE(m.Matches(ConvertibleFromAny(1))); + EXPECT_FALSE(m.Matches(ConvertibleFromAny(2))); +} + class Base {}; class Derived : public Base {}; @@ -620,6 +651,19 @@ TEST(SafeMatcherCastTest, FromSameType) { EXPECT_FALSE(m2.Matches(1)); } +TEST(SafeMatcherCastTest, ConversionConstructorIsUsed) { + Matcher m = SafeMatcherCast(1); + EXPECT_TRUE(m.Matches(ConvertibleFromAny(1))); + EXPECT_FALSE(m.Matches(ConvertibleFromAny(2))); +} + +TEST(SafeMatcherCastTest, FromConvertibleFromAny) { + Matcher m = + SafeMatcherCast(Eq(ConvertibleFromAny(1))); + EXPECT_TRUE(m.Matches(ConvertibleFromAny(1))); + EXPECT_FALSE(m.Matches(ConvertibleFromAny(2))); +} + // Tests that A() matches any value of type T. TEST(ATest, MatchesAnyValue) { // Tests a matcher for a value type. @@ -1940,19 +1984,19 @@ TEST(AllOfTest, CanDescribeSelf) { m = AllOf(Gt(0), Ne(1), Ne(2), Ne(3)); - EXPECT_EQ("(is > 0) and " - "((isn't equal to 1) and " + EXPECT_EQ("((is > 0) and " + "(isn't equal to 1)) and " "((isn't equal to 2) and " - "(isn't equal to 3)))", + "(isn't equal to 3))", Describe(m)); m = AllOf(Ge(0), Lt(10), Ne(3), Ne(5), Ne(7)); - EXPECT_EQ("(is >= 0) and " - "((is < 10) and " + EXPECT_EQ("((is >= 0) and " + "(is < 10)) and " "((isn't equal to 3) and " "((isn't equal to 5) and " - "(isn't equal to 7))))", + "(isn't equal to 7)))", Describe(m)); } @@ -1972,19 +2016,19 @@ TEST(AllOfTest, CanDescribeNegation) { m = AllOf(Gt(0), Ne(1), Ne(2), Ne(3)); - EXPECT_EQ("(isn't > 0) or " - "((is equal to 1) or " + EXPECT_EQ("((isn't > 0) or " + "(is equal to 1)) or " "((is equal to 2) or " - "(is equal to 3)))", + "(is equal to 3))", DescribeNegation(m)); m = AllOf(Ge(0), Lt(10), Ne(3), Ne(5), Ne(7)); - EXPECT_EQ("(isn't >= 0) or " - "((isn't < 10) or " + EXPECT_EQ("((isn't >= 0) or " + "(isn't < 10)) or " "((is equal to 3) or " "((is equal to 5) or " - "(is equal to 7))))", + "(is equal to 7)))", DescribeNegation(m)); } @@ -2112,18 +2156,18 @@ TEST(AnyOfTest, CanDescribeSelf) { Describe(m)); m = AnyOf(Lt(0), Eq(1), Eq(2), Eq(3)); - EXPECT_EQ("(is < 0) or " - "((is equal to 1) or " + EXPECT_EQ("((is < 0) or " + "(is equal to 1)) or " "((is equal to 2) or " - "(is equal to 3)))", + "(is equal to 3))", Describe(m)); m = AnyOf(Le(0), Gt(10), 3, 5, 7); - EXPECT_EQ("(is <= 0) or " - "((is > 10) or " + EXPECT_EQ("((is <= 0) or " + "(is > 10)) or " "((is equal to 3) or " "((is equal to 5) or " - "(is equal to 7))))", + "(is equal to 7)))", Describe(m)); } @@ -2140,18 +2184,18 @@ TEST(AnyOfTest, CanDescribeNegation) { DescribeNegation(m)); m = AnyOf(Lt(0), Eq(1), Eq(2), Eq(3)); - EXPECT_EQ("(isn't < 0) and " - "((isn't equal to 1) and " + EXPECT_EQ("((isn't < 0) and " + "(isn't equal to 1)) and " "((isn't equal to 2) and " - "(isn't equal to 3)))", + "(isn't equal to 3))", DescribeNegation(m)); m = AnyOf(Le(0), Gt(10), 3, 5, 7); - EXPECT_EQ("(isn't <= 0) and " - "((isn't > 10) and " + EXPECT_EQ("((isn't <= 0) and " + "(isn't > 10)) and " "((isn't equal to 3) and " "((isn't equal to 5) and " - "(isn't equal to 7))))", + "(isn't equal to 7)))", DescribeNegation(m)); } diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index 43ff55d8..9fa9e2ec 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -225,6 +225,7 @@ class Foo { const char* s10) { return string(s1) + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; } + private: int value_; }; diff --git a/test/gmock_link_test.h b/test/gmock_link_test.h index ab5af4b4..1f55f5bd 100644 --- a/test/gmock_link_test.h +++ b/test/gmock_link_test.h @@ -195,8 +195,8 @@ class Interface { virtual char* StringFromString(char* str) = 0; virtual int IntFromString(char* str) = 0; virtual int& IntRefFromString(char* str) = 0; - virtual void VoidFromFunc(void(*)(char*)) = 0; - virtual void VoidFromIntRef(int& n) = 0; + virtual void VoidFromFunc(void(*func)(char* str)) = 0; + virtual void VoidFromIntRef(int& n) = 0; // NOLINT virtual void VoidFromFloat(float n) = 0; virtual void VoidFromDouble(double n) = 0; virtual void VoidFromVector(const std::vector& v) = 0; @@ -211,7 +211,7 @@ class Mock: public Interface { MOCK_METHOD1(IntFromString, int(char* str)); MOCK_METHOD1(IntRefFromString, int&(char* str)); MOCK_METHOD1(VoidFromFunc, void(void(*func)(char* str))); - MOCK_METHOD1(VoidFromIntRef, void(int& n)); + MOCK_METHOD1(VoidFromIntRef, void(int& n)); // NOLINT MOCK_METHOD1(VoidFromFloat, void(float n)); MOCK_METHOD1(VoidFromDouble, void(double n)); MOCK_METHOD1(VoidFromVector, void(const std::vector& v)); @@ -224,15 +224,15 @@ class InvokeHelper { public: static void StaticVoidFromVoid() {} void VoidFromVoid() {} - static void StaticVoidFromString(char*) {} - void VoidFromString(char*) {} - static int StaticIntFromString(char*) { return 1; } - static bool StaticBoolFromString(const char*) { return true; } + static void StaticVoidFromString(char* /* str */) {} + void VoidFromString(char* /* str */) {} + static int StaticIntFromString(char* /* str */) { return 1; } + static bool StaticBoolFromString(const char* /* str */) { return true; } }; class FieldHelper { public: - FieldHelper(int a_field) : field_(a_field) {} + explicit FieldHelper(int a_field) : field_(a_field) {} int field() const { return field_; } int field_; // NOLINT -- need external access to field_ to test // the Field matcher. -- cgit v1.2.3 From 2fd619edd3d1ec053f6276debdb513f1122ebcf3 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 31 May 2012 20:40:56 +0000 Subject: Pulls in gtest r615. Renames internal enums to the kFoo naming style. Fixes gmock doctor to work with newer versions of Clang. --- include/gmock/gmock-generated-actions.h | 3 --- include/gmock/gmock-generated-actions.h.pump | 3 --- include/gmock/gmock-spec-builders.h | 17 +++++++------- include/gmock/internal/gmock-internal-utils.h | 10 ++++---- scripts/gmock_doctor.py | 16 ++++++++++--- src/gmock-internal-utils.cc | 8 +++---- src/gmock-spec-builders.cc | 27 +++++++++++---------- test/gmock-internal-utils_test.cc | 34 +++++++++++++-------------- 8 files changed, 61 insertions(+), 57 deletions(-) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index 3b599b36..2327393d 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -2216,9 +2216,6 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, p9##_type>::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const -// TODO(wan@google.com): move the following to a different .h file -// such that we don't have to run 'pump' every time the code is -// updated. namespace testing { // The ACTION*() macros trigger warning C4100 (unreferenced formal diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 57a7811a..8e2b5735 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -739,9 +739,6 @@ $$ } // This meta comment fixes auto-indentation in Emacs. It won't $$ // show up in the generated code. -// TODO(wan@google.com): move the following to a different .h file -// such that we don't have to run 'pump' every time the code is -// updated. namespace testing { // The ACTION*() macros trigger warning C4100 (unreferenced formal diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 30721ce6..c677333c 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -353,12 +353,11 @@ class OnCallSpec : public UntypedOnCallSpecBase { Action action_; }; // class OnCallSpec -// Possible reactions on uninteresting calls. TODO(wan@google.com): -// rename the enum values to the kFoo style. +// Possible reactions on uninteresting calls. enum CallReaction { - ALLOW, - WARN, - FAIL + kAllow, + kWarn, + kFail }; } // namespace internal @@ -422,7 +421,7 @@ class GTEST_API_ Mock { // Returns the reaction Google Mock will have on uninteresting calls // made on the given mock object. static internal::CallReaction GetReactionOnUninterestingCalls( - const void* mock_obj); + const void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); // Verifies that all expectations on the given mock object have been @@ -1163,7 +1162,7 @@ class TypedExpectation : public ExpectationBase { << action_count << " WillOnce()" << (action_count == 1 ? " is" : "s are") << " specified - "; mocker->DescribeDefaultActionTo(args, &ss); - Log(WARNING, ss.str(), 1); + Log(kWarning, ss.str(), 1); } return count <= action_count ? @@ -1251,7 +1250,7 @@ class MockSpec { // the newly created spec. internal::OnCallSpec& InternalDefaultActionSetAt( const char* file, int line, const char* obj, const char* call) { - LogWithLocation(internal::INFO, file, line, + LogWithLocation(internal::kInfo, file, line, string("ON_CALL(") + obj + ", " + call + ") invoked"); return function_mocker_->AddNewOnCallSpec(file, line, matchers_); } @@ -1261,7 +1260,7 @@ class MockSpec { internal::TypedExpectation& InternalExpectedAt( const char* file, int line, const char* obj, const char* call) { const string source_text(string("EXPECT_CALL(") + obj + ", " + call + ")"); - LogWithLocation(internal::INFO, file, line, source_text + " invoked"); + LogWithLocation(internal::kInfo, file, line, source_text + " invoked"); return function_mocker_->AddNewExpectation( file, line, source_text, matchers_); } diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index aef9388e..6b6de970 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -260,7 +260,7 @@ class FailureReporterInterface { public: // The type of a failure (either non-fatal or fatal). enum FailureType { - NONFATAL, FATAL + kNonfatal, kFatal }; virtual ~FailureReporterInterface() {} @@ -281,7 +281,7 @@ GTEST_API_ FailureReporterInterface* GetFailureReporter(); inline void Assert(bool condition, const char* file, int line, const string& msg) { if (!condition) { - GetFailureReporter()->ReportFailure(FailureReporterInterface::FATAL, + GetFailureReporter()->ReportFailure(FailureReporterInterface::kFatal, file, line, msg); } } @@ -294,7 +294,7 @@ inline void Assert(bool condition, const char* file, int line) { inline void Expect(bool condition, const char* file, int line, const string& msg) { if (!condition) { - GetFailureReporter()->ReportFailure(FailureReporterInterface::NONFATAL, + GetFailureReporter()->ReportFailure(FailureReporterInterface::kNonfatal, file, line, msg); } } @@ -304,8 +304,8 @@ inline void Expect(bool condition, const char* file, int line) { // Severity level of a log. enum LogSeverity { - INFO = 0, - WARNING = 1 + kInfo = 0, + kWarning = 1 }; // Valid values for the --gmock_verbose flag. diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index d5c45180..f7c3920f 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -332,7 +332,7 @@ def _OverloadedMethodActionDiagnoser(msg): r'(.*\n)*?' r'.*\bgmock-\w+-actions\.h:\d+:\d+: ' r'note: candidate function template not viable: ' - r'requires 1 argument, but 2 were provided') + r'requires .*, but 2 (arguments )?were provided') diagnosis = """ The second argument you gave to Invoke() is an overloaded method. Please tell your compiler which overloaded version you want to use. @@ -474,6 +474,10 @@ def _TypeInTemplatedBaseDiagnoser(msg): r'(?P=file):(?P=line):(?P=column): error: ' r'C\+\+ requires a type specifier for all declarations' ) + clang_regex_unknown_type = ( + _CLANG_FILE_LINE_RE + + r'error: unknown type name \'(?P[^\']+)\'' + ) diagnosis = """ In a mock class template, types or typedefs defined in the base class @@ -483,7 +487,7 @@ need to make it visible. One way to do it is: typedef typename Base::%(type)s %(type)s;""" - return _GenericDiagnoser( + for diag in _GenericDiagnoser( 'TTB', 'Type in Template Base', [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}), (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}), @@ -491,7 +495,13 @@ need to make it visible. One way to do it is: (gcc_regex_type_of_a_param, diagnosis), (clang_regex_type_of_retval_or_sole_param, diagnosis), (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})], - msg) + msg): + yield diag + # Avoid overlap with the NUS pattern. + for m in _FindAllMatches(clang_regex_unknown_type, msg): + type_ = m.groupdict()['type'] + if type_ not in _COMMON_GMOCK_SYMBOLS: + yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict()) def _WrongMockMethodMacroDiagnoser(msg): diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 470fc447..fb530801 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -77,13 +77,13 @@ class GoogleTestFailureReporter : public FailureReporterInterface { public: virtual void ReportFailure(FailureType type, const char* file, int line, const string& message) { - AssertHelper(type == FATAL ? + AssertHelper(type == kFatal ? TestPartResult::kFatalFailure : TestPartResult::kNonFatalFailure, file, line, message.c_str()) = Message(); - if (type == FATAL) { + if (type == kFatal) { posix::Abort(); } } @@ -117,7 +117,7 @@ GTEST_API_ bool LogIsVisible(LogSeverity severity) { } else { // If --gmock_verbose is neither "info" nor "error", we treat it // as "warning" (its default value). - return severity == WARNING; + return severity == kWarning; } } @@ -140,7 +140,7 @@ GTEST_API_ void Log(LogSeverity severity, // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is a // macro. - if (severity == WARNING) { + if (severity == kWarning) { // Prints a GMOCK WARNING marker to make the warnings easily searchable. std::cout << "\nGMOCK WARNING:"; } diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index a93ea71a..9fcb61ea 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -217,7 +217,7 @@ void ExpectationBase::CheckActionCountIfNotDone() const ss << " and a WillRepeatedly()"; } ss << "."; - Log(WARNING, ss.str(), -1); // -1 means "don't print stack trace". + Log(kWarning, ss.str(), -1); // -1 means "don't print stack trace". } } @@ -246,11 +246,11 @@ GTEST_API_ ThreadLocal g_gmock_implicit_sequence; // manner specified by 'reaction'. void ReportUninterestingCall(CallReaction reaction, const string& msg) { switch (reaction) { - case ALLOW: - Log(INFO, msg, 3); + case kAllow: + Log(kInfo, msg, 3); break; - case WARN: - Log(WARNING, msg, 3); + case kWarn: + Log(kWarning, msg, 3); break; default: // FAIL Expect(false, NULL, -1, msg); @@ -345,10 +345,10 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) const bool need_to_report_uninteresting_call = // If the user allows this uninteresting call, we print it // only when he wants informational messages. - reaction == ALLOW ? LogIsVisible(INFO) : + reaction == kAllow ? LogIsVisible(kInfo) : // If the user wants this to be a warning, we print it only // when he wants to see warnings. - reaction == WARN ? LogIsVisible(WARNING) : + reaction == kWarn ? LogIsVisible(kWarning) : // Otherwise, the user wants this to be an error, and we // should always print detailed information in the error. true; @@ -391,7 +391,8 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) // True iff we need to print the call's arguments and return value. // This definition must be kept in sync with the uses of Expect() // and Log() in this function. - const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO); + const bool need_to_report_call = + !found || is_excessive || LogIsVisible(kInfo); if (!need_to_report_call) { // Perform the action without printing the call information. return @@ -427,7 +428,7 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) } else { // We had an expected call and the matching expectation is // described in ss. - Log(INFO, loc.str() + ss.str(), 2); + Log(kInfo, loc.str() + ss.str(), 2); } return result; @@ -606,21 +607,21 @@ void SetReactionOnUninterestingCalls(const void* mock_obj, // object. void Mock::AllowUninterestingCalls(const void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { - SetReactionOnUninterestingCalls(mock_obj, internal::ALLOW); + SetReactionOnUninterestingCalls(mock_obj, internal::kAllow); } // Tells Google Mock to warn the user about uninteresting calls on the // given mock object. void Mock::WarnUninterestingCalls(const void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { - SetReactionOnUninterestingCalls(mock_obj, internal::WARN); + SetReactionOnUninterestingCalls(mock_obj, internal::kWarn); } // Tells Google Mock to fail uninteresting calls on the given mock // object. void Mock::FailUninterestingCalls(const void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { - SetReactionOnUninterestingCalls(mock_obj, internal::FAIL); + SetReactionOnUninterestingCalls(mock_obj, internal::kFail); } // Tells Google Mock the given mock object is being destroyed and its @@ -638,7 +639,7 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls( GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); return (g_uninteresting_call_reaction.count(mock_obj) == 0) ? - internal::WARN : g_uninteresting_call_reaction[mock_obj]; + internal::kWarn : g_uninteresting_call_reaction[mock_obj]; } // Tells Google Mock to ignore mock_obj when checking for leaked mock diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index ae743c1c..d53282eb 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -359,20 +359,20 @@ class LogIsVisibleTest : public ::testing::Test { TEST_F(LogIsVisibleTest, AlwaysReturnsTrueIfVerbosityIsInfo) { GMOCK_FLAG(verbose) = kInfoVerbosity; - EXPECT_TRUE(LogIsVisible(INFO)); - EXPECT_TRUE(LogIsVisible(WARNING)); + EXPECT_TRUE(LogIsVisible(kInfo)); + EXPECT_TRUE(LogIsVisible(kWarning)); } TEST_F(LogIsVisibleTest, AlwaysReturnsFalseIfVerbosityIsError) { GMOCK_FLAG(verbose) = kErrorVerbosity; - EXPECT_FALSE(LogIsVisible(INFO)); - EXPECT_FALSE(LogIsVisible(WARNING)); + EXPECT_FALSE(LogIsVisible(kInfo)); + EXPECT_FALSE(LogIsVisible(kWarning)); } TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) { GMOCK_FLAG(verbose) = kWarningVerbosity; - EXPECT_FALSE(LogIsVisible(INFO)); - EXPECT_TRUE(LogIsVisible(WARNING)); + EXPECT_FALSE(LogIsVisible(kInfo)); + EXPECT_TRUE(LogIsVisible(kWarning)); } #if GTEST_HAS_STREAM_REDIRECTION @@ -390,7 +390,7 @@ void TestLogWithSeverity(const string& verbosity, LogSeverity severity, if (should_print) { EXPECT_THAT(GetCapturedStdout().c_str(), ContainsRegex( - severity == WARNING ? + severity == kWarning ? "^\nGMOCK WARNING:\nTest log\\.\nStack trace:\n" : "^\nTest log\\.\nStack trace:\n")); } else { @@ -405,7 +405,7 @@ TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { const string saved_flag = GMOCK_FLAG(verbose); GMOCK_FLAG(verbose) = kInfoVerbosity; CaptureStdout(); - Log(INFO, "Test log.\n", -1); + Log(kInfo, "Test log.\n", -1); EXPECT_STREQ("\nTest log.\n", GetCapturedStdout().c_str()); GMOCK_FLAG(verbose) = saved_flag; } @@ -414,7 +414,7 @@ TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { // treated as 0. TEST(LogTest, NoSkippingStackFrameInOptMode) { CaptureStdout(); - Log(WARNING, "Test log.\n", 100); + Log(kWarning, "Test log.\n", 100); const String log = GetCapturedStdout(); # if defined(NDEBUG) && GTEST_GOOGLE3_MODE_ @@ -436,29 +436,29 @@ TEST(LogTest, NoSkippingStackFrameInOptMode) { // Tests that all logs are printed when the value of the // --gmock_verbose flag is "info". TEST(LogTest, AllLogsArePrintedWhenVerbosityIsInfo) { - TestLogWithSeverity(kInfoVerbosity, INFO, true); - TestLogWithSeverity(kInfoVerbosity, WARNING, true); + TestLogWithSeverity(kInfoVerbosity, kInfo, true); + TestLogWithSeverity(kInfoVerbosity, kWarning, true); } // Tests that only warnings are printed when the value of the // --gmock_verbose flag is "warning". TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsWarning) { - TestLogWithSeverity(kWarningVerbosity, INFO, false); - TestLogWithSeverity(kWarningVerbosity, WARNING, true); + TestLogWithSeverity(kWarningVerbosity, kInfo, false); + TestLogWithSeverity(kWarningVerbosity, kWarning, true); } // Tests that no logs are printed when the value of the // --gmock_verbose flag is "error". TEST(LogTest, NoLogsArePrintedWhenVerbosityIsError) { - TestLogWithSeverity(kErrorVerbosity, INFO, false); - TestLogWithSeverity(kErrorVerbosity, WARNING, false); + TestLogWithSeverity(kErrorVerbosity, kInfo, false); + TestLogWithSeverity(kErrorVerbosity, kWarning, false); } // Tests that only warnings are printed when the value of the // --gmock_verbose flag is invalid. TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsInvalid) { - TestLogWithSeverity("invalid", INFO, false); - TestLogWithSeverity("invalid", WARNING, true); + TestLogWithSeverity("invalid", kInfo, false); + TestLogWithSeverity("invalid", kWarning, true); } #endif // GTEST_HAS_STREAM_REDIRECTION -- cgit v1.2.3 From ada23475e27babd85fb9c13250243f6acfd3ffd8 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Tue, 14 Aug 2012 15:38:49 +0000 Subject: Makes gmock's Pointee() work for optional (by Jeffrey Yasskin). --- include/gmock/internal/gmock-internal-utils.h | 2 +- test/gmock-matchers_test.cc | 32 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 6b6de970..d63fb223 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -73,7 +73,7 @@ struct PointeeOf { typedef T type; }; // NOLINT // smart pointer, or returns p itself when p is already a raw pointer. // The following default implementation is for the smart pointer case. template -inline typename Pointer::element_type* GetRawPointer(const Pointer& p) { +inline const typename Pointer::element_type* GetRawPointer(const Pointer& p) { return p.get(); } // This overloaded version is for the raw pointer case. diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 35d59fa8..6e5d5c31 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -2824,6 +2824,38 @@ TEST(PointeeTest, ReferenceToNonConstRawPointer) { EXPECT_FALSE(m.Matches(p)); } +// Minimal const-propagating pointer. +template +class ConstPropagatingPtr { + public: + typedef T element_type; + + ConstPropagatingPtr() : val_() {} + explicit ConstPropagatingPtr(T* t) : val_(t) {} + ConstPropagatingPtr(const ConstPropagatingPtr& other) : val_(other.val_) {} + + T* get() { return val_; } + T& operator*() { return *val_; } + // Most smart pointers return non-const T* and T& from the next methods. + const T* get() const { return val_; } + const T& operator*() const { return *val_; } + + private: + T* val_; +}; + +TEST(PointeeTest, WorksWithConstPropagatingPointers) { + const Matcher< ConstPropagatingPtr > m = Pointee(Lt(5)); + int three = 3; + const ConstPropagatingPtr co(&three); + ConstPropagatingPtr o(&three); + EXPECT_TRUE(m.Matches(o)); + EXPECT_TRUE(m.Matches(co)); + *o = 6; + EXPECT_FALSE(m.Matches(o)); + EXPECT_FALSE(m.Matches(ConstPropagatingPtr())); +} + TEST(PointeeTest, NeverMatchesNull) { const Matcher m = Pointee(_); EXPECT_FALSE(m.Matches(NULL)); -- cgit v1.2.3 From 38513a8bb154f0b6d0a4088814fe92552696d465 Mon Sep 17 00:00:00 2001 From: jgm Date: Thu, 15 Nov 2012 15:50:36 +0000 Subject: Unfortunately, the svn repo is a bit out of date. This commit contains 8 changes that haven't made it to svn. The descriptions of each change are listed below. - Fixes some python shebang lines. - Add ElementsAreArray overloads to gmock. ElementsAreArray now makes a copy of its input elements before the conversion to a Matcher. ElementsAreArray can now take a vector as input. ElementsAreArray can now take an iterator pair as input. - Templatize MatchAndExplain to allow independent string types for the matcher and matchee. I also templatized the ConstCharPointer version of MatchAndExplain to avoid calls with "char*" from using the new templated MatchAndExplain. - Fixes the bug where the constructor of the return type of ElementsAre() saves a reference instead of a copy of the arguments. - Extends ElementsAre() to accept arrays whose sizes aren't known. - Switches gTest's internal FilePath class from testing::internal::String to std::string. testing::internal::String was introduced when gTest couldn't depend on std::string. It's now deprecated. - Switches gTest & gMock from using testing::internal::String objects to std::string. Some static methods of String are still in use. We may be able to remove some but not all of them. In particular, String::Format() should eventually be removed as it truncates the result at 4096 characters, often causing problems. --- include/gmock/gmock-generated-matchers.h | 196 ++++++++++++++++---------- include/gmock/gmock-generated-matchers.h.pump | 64 +++++++-- include/gmock/gmock-matchers.h | 151 ++++++++++++-------- include/gmock/internal/gmock-internal-utils.h | 13 ++ include/gmock/internal/gmock-port.h | 4 +- src/gmock.cc | 6 +- test/gmock-generated-matchers_test.cc | 97 ++++++++++++- test/gmock-internal-utils_test.cc | 18 +-- test/gmock-matchers_test.cc | 1 - test/gmock-nice-strict_test.cc | 4 +- test/gmock-spec-builders_test.cc | 29 ++-- 11 files changed, 392 insertions(+), 191 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 5527ed3e..bc3f610c 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -38,6 +38,7 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ +#include #include #include #include @@ -305,7 +306,9 @@ class ArgsMatcher { GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; -// Implements ElementsAre() of 1-10 arguments. +// Implements ElementsAre() of 1-10 arguments. The use of DecayArray in +// the implementation allows ElementsAre() to accept string literals, whose +// inferred type is const char[N] while we want to treat them as const char*. template class ElementsAreMatcher1 { @@ -326,11 +329,12 @@ class ElementsAreMatcher1 { // a local array. const Matcher matcher = MatcherCast(e1_); - return MakeMatcher(new ElementsAreMatcherImpl(&matcher, 1)); + return MakeMatcher(new ElementsAreMatcherImpl(&matcher, + &matcher + 1)); } private: - const T1& e1_; + const typename DecayArray::type e1_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher1); }; @@ -351,12 +355,13 @@ class ElementsAreMatcher2 { MatcherCast(e2_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 2)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 2)); } private: - const T1& e1_; - const T2& e2_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher2); }; @@ -379,13 +384,14 @@ class ElementsAreMatcher3 { MatcherCast(e3_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 3)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 3)); } private: - const T1& e1_; - const T2& e2_; - const T3& e3_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher3); }; @@ -409,14 +415,15 @@ class ElementsAreMatcher4 { MatcherCast(e4_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 4)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 4)); } private: - const T1& e1_; - const T2& e2_; - const T3& e3_; - const T4& e4_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher4); }; @@ -441,15 +448,16 @@ class ElementsAreMatcher5 { MatcherCast(e5_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 5)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 5)); } private: - const T1& e1_; - const T2& e2_; - const T3& e3_; - const T4& e4_; - const T5& e5_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; + const typename DecayArray::type e5_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher5); }; @@ -477,16 +485,17 @@ class ElementsAreMatcher6 { MatcherCast(e6_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 6)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 6)); } private: - const T1& e1_; - const T2& e2_; - const T3& e3_; - const T4& e4_; - const T5& e5_; - const T6& e6_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; + const typename DecayArray::type e5_; + const typename DecayArray::type e6_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher6); }; @@ -515,17 +524,18 @@ class ElementsAreMatcher7 { MatcherCast(e7_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 7)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 7)); } private: - const T1& e1_; - const T2& e2_; - const T3& e3_; - const T4& e4_; - const T5& e5_; - const T6& e6_; - const T7& e7_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; + const typename DecayArray::type e5_; + const typename DecayArray::type e6_; + const typename DecayArray::type e7_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher7); }; @@ -555,18 +565,19 @@ class ElementsAreMatcher8 { MatcherCast(e8_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 8)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 8)); } private: - 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 typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; + const typename DecayArray::type e5_; + const typename DecayArray::type e6_; + const typename DecayArray::type e7_; + const typename DecayArray::type e8_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher8); }; @@ -598,19 +609,20 @@ class ElementsAreMatcher9 { MatcherCast(e9_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 9)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 9)); } private: - 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 typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; + const typename DecayArray::type e5_; + const typename DecayArray::type e6_; + const typename DecayArray::type e7_; + const typename DecayArray::type e8_; + const typename DecayArray::type e9_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher9); }; @@ -643,20 +655,21 @@ class ElementsAreMatcher10 { MatcherCast(e10_), }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 10)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + 10)); } private: - 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_; + const typename DecayArray::type e1_; + const typename DecayArray::type e2_; + const typename DecayArray::type e3_; + const typename DecayArray::type e4_; + const typename DecayArray::type e5_; + const typename DecayArray::type e6_; + const typename DecayArray::type e7_; + const typename DecayArray::type e8_; + const typename DecayArray::type e9_; + const typename DecayArray::type e10_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher10); }; @@ -1007,24 +1020,55 @@ inline internal::ElementsAreMatcher10(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); } -// ElementsAreArray(array) and ElementAreArray(array, count) are like -// ElementsAre(), except that they take an array of values or -// matchers. The former form infers the size of 'array', which must -// be a static C-style array. In the latter form, 'array' can either -// be a static array or a pointer to a dynamically created array. - +// ElementsAreArray(array) +// ElementsAreArray(pointer, count) +// ElementsAreArray(vector) +// ElementsAreArray(first, last) +// +// The ElementsAreArray() functions are like ElementsAre(...), except that +// they are given a sequence of matchers or values rather than taking each +// element as a function argument. The sequence can be specified as a +// C-style array, a pointer and count, a vector, or an STL iterator range. +// +// * The array form infers the size of 'array', which must be of a +// statically-sized C-style array type. +// +// * The (pointer, count) form can take either a statically-sized C-style +// array or a pointer to a dynamically created array. It does not take +// ownership of the pointer. +// +// * The vector form can take a std::vector either of values or of matchers. +// +// * The (first, last) form can take any STL iterator range. +// +// All forms of ElementsAreArray() make a copy of the input sequence. template inline internal::ElementsAreArrayMatcher ElementsAreArray( const T* first, size_t count) { - return internal::ElementsAreArrayMatcher(first, count); + return internal::ElementsAreArrayMatcher(first, first + count); } template -inline internal::ElementsAreArrayMatcher -ElementsAreArray(const T (&array)[N]) { - return internal::ElementsAreArrayMatcher(array, N); +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const T (&array)[N]) { + return internal::ElementsAreArrayMatcher(array, array + N); +} + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const std::vector& vec) { + return internal::ElementsAreArrayMatcher(vec.begin(), vec.end()); } +template +inline internal::ElementsAreArrayMatcher< + typename std::iterator_traits::value_type> +ElementsAreArray(Iter first, Iter last) { + typedef typename std::iterator_traits::value_type T; + return internal::ElementsAreArrayMatcher(first, last); +} + + // 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. diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 7cdb84bf..a8d7612d 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -40,6 +40,7 @@ $$ }} This line fixes auto-indentation of the following code in Emacs. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ +#include #include #include #include @@ -186,7 +187,9 @@ class ArgsMatcher { GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; -// Implements ElementsAre() of 1-$n arguments. +// Implements ElementsAre() of 1-$n arguments. The use of DecayArray in +// the implementation allows ElementsAre() to accept string literals, whose +// inferred type is const char[N] while we want to treat them as const char*. $range i 1..n @@ -214,7 +217,8 @@ $if i==1 [[ // a local array. const Matcher matcher = MatcherCast(e1_); - return MakeMatcher(new ElementsAreMatcherImpl(&matcher, 1)); + return MakeMatcher(new ElementsAreMatcherImpl(&matcher, + &matcher + 1)); ]] $else [[ const Matcher matchers[] = { @@ -225,7 +229,8 @@ $for j [[ ]] }; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, $i)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers + $i)); ]] } @@ -233,7 +238,7 @@ $for j [[ private: $for j [[ - const T$j& e$j[[]]_; + const typename DecayArray::type e$j[[]]_; ]] @@ -344,24 +349,55 @@ inline internal::ElementsAreMatcher$i<$for j, [[T$j]]> ElementsAre($for j, [[con ]] -// ElementsAreArray(array) and ElementAreArray(array, count) are like -// ElementsAre(), except that they take an array of values or -// matchers. The former form infers the size of 'array', which must -// be a static C-style array. In the latter form, 'array' can either -// be a static array or a pointer to a dynamically created array. - +// ElementsAreArray(array) +// ElementsAreArray(pointer, count) +// ElementsAreArray(vector) +// ElementsAreArray(first, last) +// +// The ElementsAreArray() functions are like ElementsAre(...), except that +// they are given a sequence of matchers or values rather than taking each +// element as a function argument. The sequence can be specified as a +// C-style array, a pointer and count, a vector, or an STL iterator range. +// +// * The array form infers the size of 'array', which must be of a +// statically-sized C-style array type. +// +// * The (pointer, count) form can take either a statically-sized C-style +// array or a pointer to a dynamically created array. It does not take +// ownership of the pointer. +// +// * The vector form can take a std::vector either of values or of matchers. +// +// * The (first, last) form can take any STL iterator range. +// +// All forms of ElementsAreArray() make a copy of the input sequence. template inline internal::ElementsAreArrayMatcher ElementsAreArray( const T* first, size_t count) { - return internal::ElementsAreArrayMatcher(first, count); + return internal::ElementsAreArrayMatcher(first, first + count); } template -inline internal::ElementsAreArrayMatcher -ElementsAreArray(const T (&array)[N]) { - return internal::ElementsAreArrayMatcher(array, N); +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const T (&array)[N]) { + return internal::ElementsAreArrayMatcher(array, array + N); +} + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const std::vector& vec) { + return internal::ElementsAreArrayMatcher(vec.begin(), vec.end()); } +template +inline internal::ElementsAreArrayMatcher< + typename std::iterator_traits::value_type> +ElementsAreArray(Iter first, Iter last) { + typedef typename std::iterator_traits::value_type T; + return internal::ElementsAreArrayMatcher(first, last); +} + + // 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. diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 4f1c433c..751574ca 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -935,26 +935,33 @@ bool CaseInsensitiveStringEquals(const StringType& s1, template class StrEqualityMatcher { public: - typedef typename StringType::const_pointer ConstCharPointer; - StrEqualityMatcher(const StringType& str, bool expect_eq, bool case_sensitive) : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {} - // When expect_eq_ is true, returns true iff s is equal to string_; - // otherwise returns true iff s is not equal to string_. - bool MatchAndExplain(ConstCharPointer s, - MatchResultListener* listener) const { + // 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); } - bool MatchAndExplain(const StringType& s, + // 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 bool eq = case_sensitive_ ? s == string_ : - CaseInsensitiveStringEquals(s, string_); + const StringType& s2(s); + const bool eq = case_sensitive_ ? s2 == string_ : + CaseInsensitiveStringEquals(s2, string_); return expect_eq_ == eq; } @@ -989,22 +996,28 @@ class StrEqualityMatcher { template class HasSubstrMatcher { public: - typedef typename StringType::const_pointer ConstCharPointer; - explicit HasSubstrMatcher(const StringType& substring) : substring_(substring) {} - // These overloaded methods allow HasSubstr(substring) to be used as a - // Matcher as long as T can be converted to string. Returns true - // iff s contains substring_ as a substring. - bool MatchAndExplain(ConstCharPointer s, - MatchResultListener* listener) const { + // 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); } - bool MatchAndExplain(const StringType& s, + // 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 { - return s.find(substring_) != StringType::npos; + const StringType& s2(s); + return s2.find(substring_) != StringType::npos; } // Describes what this matcher matches. @@ -1030,23 +1043,29 @@ class HasSubstrMatcher { template class StartsWithMatcher { public: - typedef typename StringType::const_pointer ConstCharPointer; - explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) { } - // These overloaded methods allow StartsWith(prefix) to be used as a - // Matcher as long as T can be converted to string. Returns true - // iff s starts with prefix_. - bool MatchAndExplain(ConstCharPointer s, - MatchResultListener* listener) const { + // 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); } - bool MatchAndExplain(const StringType& s, + // 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 { - return s.length() >= prefix_.length() && - s.substr(0, prefix_.length()) == prefix_; + const StringType& s2(s); + return s2.length() >= prefix_.length() && + s2.substr(0, prefix_.length()) == prefix_; } void DescribeTo(::std::ostream* os) const { @@ -1071,22 +1090,28 @@ class StartsWithMatcher { template class EndsWithMatcher { public: - typedef typename StringType::const_pointer ConstCharPointer; - explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {} - // These overloaded methods allow EndsWith(suffix) to be used as a - // Matcher as long as T can be converted to string. Returns true - // iff s ends with suffix_. - bool MatchAndExplain(ConstCharPointer s, - MatchResultListener* listener) const { + // 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); } - bool MatchAndExplain(const StringType& s, + // 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 { - return s.length() >= suffix_.length() && - s.substr(s.length() - suffix_.length()) == suffix_; + const StringType& s2(s); + return s2.length() >= suffix_.length() && + s2.substr(s2.length() - suffix_.length()) == suffix_; } void DescribeTo(::std::ostream* os) const { @@ -1113,19 +1138,26 @@ class MatchesRegexMatcher { MatchesRegexMatcher(const RE* regex, bool full_match) : regex_(regex), full_match_(full_match) {} - // These overloaded methods allow MatchesRegex(regex) to be used as - // a Matcher as long as T can be converted to string. Returns - // true iff s matches regular expression regex. When full_match_ is - // true, a full match is done; otherwise a partial match is done. - bool MatchAndExplain(const char* s, - MatchResultListener* listener) const { + // 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); } - bool MatchAndExplain(const internal::string& s, + // 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 { - return full_match_ ? RE::FullMatch(s, *regex_) : - RE::PartialMatch(s, *regex_); + const internal::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) : + RE::PartialMatch(s2, *regex_); } void DescribeTo(::std::ostream* os) const { @@ -2527,11 +2559,9 @@ class ElementsAreMatcherImpl : public MatcherInterface { // Constructs the matcher from a sequence of element values or // element matchers. template - ElementsAreMatcherImpl(InputIter first, size_t a_count) { - matchers_.reserve(a_count); - InputIter it = first; - for (size_t i = 0; i != a_count; ++i, ++it) { - matchers_.push_back(MatcherCast(*it)); + ElementsAreMatcherImpl(InputIter first, InputIter last) { + while (first != last) { + matchers_.push_back(MatcherCast(*first++)); } } @@ -2642,7 +2672,8 @@ class ElementsAreMatcher0 { Element; const Matcher* const matchers = NULL; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 0)); + return MakeMatcher(new ElementsAreMatcherImpl(matchers, + matchers)); } }; @@ -2650,21 +2681,17 @@ class ElementsAreMatcher0 { template class ElementsAreArrayMatcher { public: - ElementsAreArrayMatcher(const T* first, size_t count) : - first_(first), count_(count) {} + template + ElementsAreArrayMatcher(Iter first, Iter last) : matchers_(first, last) {} template operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - return MakeMatcher(new ElementsAreMatcherImpl(first_, count_)); + return MakeMatcher(new ElementsAreMatcherImpl( + matchers_.begin(), matchers_.end())); } private: - const T* const first_; - const size_t count_; + const std::vector matchers_; GTEST_DISALLOW_ASSIGN_(ElementsAreArrayMatcher); }; diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index d63fb223..f9b6b809 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -348,6 +348,19 @@ template struct type_equals : public true_type {}; template struct remove_reference { typedef T type; }; // NOLINT template struct remove_reference { typedef T type; }; // NOLINT +// DecayArray::type turns an array type U[N] to const U* and preserves +// other types. Useful for saving a copy of a function argument. +template struct DecayArray { typedef T type; }; // NOLINT +template struct DecayArray { + typedef const T* type; +}; +// Sometimes people use arrays whose size is not available at the use site +// (e.g. extern const char kNamePrefix[]). This specialization covers that +// case. +template struct DecayArray { + typedef const T* type; +}; + // Invalid() returns an invalid value of type T. This is useful // when a value of type T is needed for compilation, but the statement // will not really be executed (or we don't care if the statement diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 6a515d87..b6c5c7f1 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -65,7 +65,7 @@ #define GMOCK_DECLARE_int32_(name) \ extern GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) #define GMOCK_DECLARE_string_(name) \ - extern GTEST_API_ ::testing::internal::String GMOCK_FLAG(name) + extern GTEST_API_ ::std::string GMOCK_FLAG(name) // Macros for defining flags. #define GMOCK_DEFINE_bool_(name, default_val, doc) \ @@ -73,6 +73,6 @@ #define GMOCK_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val) #define GMOCK_DEFINE_string_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::String GMOCK_FLAG(name) = (default_val) + GTEST_API_ ::std::string GMOCK_FLAG(name) = (default_val) #endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ diff --git a/src/gmock.cc b/src/gmock.cc index e06acc5c..1c06985d 100644 --- a/src/gmock.cc +++ b/src/gmock.cc @@ -62,7 +62,7 @@ static const char* ParseGoogleMockFlagValue(const char* str, if (str == NULL || flag == NULL) return NULL; // The flag must start with "--gmock_". - const String flag_str = String::Format("--gmock_%s", flag); + const std::string flag_str = std::string("--gmock_") + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; @@ -107,7 +107,7 @@ static bool ParseGoogleMockBoolFlag(const char* str, const char* flag, // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. static bool ParseGoogleMockStringFlag(const char* str, const char* flag, - String* value) { + std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseGoogleMockFlagValue(str, flag, false); @@ -131,7 +131,7 @@ void InitGoogleMockImpl(int* argc, CharType** argv) { if (*argc <= 0) return; for (int i = 1; i != *argc; i++) { - const String arg_string = StreamableToString(argv[i]); + const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); // Do we see a Google Mock flag? diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index b35c4505..4b7e6e05 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -77,6 +77,7 @@ using testing::Ref; using testing::StaticAssertTypeEq; using testing::StrEq; using testing::Value; +using testing::internal::ElementsAreArrayMatcher; using testing::internal::string; // Returns the description of the given matcher. @@ -527,6 +528,51 @@ TEST(ElementsAreTest, WorksWithTwoDimensionalNativeArray) { ElementsAre('l', 'o', '\0'))); } +TEST(ElementsAreTest, AcceptsStringLiteral) { + string array[] = { "hi", "one", "two" }; + EXPECT_THAT(array, ElementsAre("hi", "one", "two")); + EXPECT_THAT(array, Not(ElementsAre("hi", "one", "too"))); +} + +#ifndef _MSC_VER + +// The following test passes a value of type const char[] to a +// function template that expects const T&. Some versions of MSVC +// generates a compiler error C2665 for that. We believe it's a bug +// in MSVC. Therefore this test is #if-ed out for MSVC. + +// Declared here with the size unknown. Defined AFTER the following test. +extern const char kHi[]; + +TEST(ElementsAreTest, AcceptsArrayWithUnknownSize) { + // The size of kHi is not known in this test, but ElementsAre() should + // still accept it. + + string array1[] = { "hi" }; + EXPECT_THAT(array1, ElementsAre(kHi)); + + string array2[] = { "ho" }; + EXPECT_THAT(array2, Not(ElementsAre(kHi))); +} + +const char kHi[] = "hi"; + +#endif // _MSC_VER + +TEST(ElementsAreTest, MakesCopyOfArguments) { + int x = 1; + int y = 2; + // This should make a copy of x and y. + ::testing::internal::ElementsAreMatcher2 polymorphic_matcher = + ElementsAre(x, y); + // Changing x and y now shouldn't affect the meaning of the above matcher. + x = y = 0; + const int array1[] = { 1, 2 }; + EXPECT_THAT(array1, polymorphic_matcher); + const int array2[] = { 0, 0 }; + EXPECT_THAT(array2, Not(polymorphic_matcher)); +} + // Tests for ElementsAreArray(). Since ElementsAreArray() shares most // of the implementation with ElementsAre(), we don't test it as // thoroughly here. @@ -576,6 +622,39 @@ TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); } +TEST(ElementsAreArrayTest, CanBeCreatedWithVector) { + const int a[] = { 1, 2, 3 }; + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + const vector expected(a, a + GMOCK_ARRAY_SIZE_(a)); + EXPECT_THAT(test_vector, ElementsAreArray(expected)); + test_vector.push_back(4); + EXPECT_THAT(test_vector, Not(ElementsAreArray(expected))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherVector) { + const int a[] = { 1, 2, 3 }; + const Matcher kMatchers[] = { Eq(1), Eq(2), Eq(3) }; + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + const vector > expected( + kMatchers, kMatchers + GMOCK_ARRAY_SIZE_(kMatchers)); + EXPECT_THAT(test_vector, ElementsAreArray(expected)); + test_vector.push_back(4); + EXPECT_THAT(test_vector, Not(ElementsAreArray(expected))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithIteratorRange) { + const int a[] = { 1, 2, 3 }; + const vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + const vector expected(a, a + GMOCK_ARRAY_SIZE_(a)); + EXPECT_THAT(test_vector, ElementsAreArray(expected.begin(), expected.end())); + // Pointers are iterators, too. + EXPECT_THAT(test_vector, ElementsAreArray(a, a + GMOCK_ARRAY_SIZE_(a))); + // The empty range of NULL pointers should also be okay. + int* const null_int = NULL; + EXPECT_THAT(test_vector, Not(ElementsAreArray(null_int, null_int))); + EXPECT_THAT((vector()), ElementsAreArray(null_int, null_int)); +} + // Since ElementsAre() and ElementsAreArray() share much of the // implementation, we only do a sanity test for native arrays here. TEST(ElementsAreArrayTest, WorksWithNativeArray) { @@ -587,6 +666,22 @@ TEST(ElementsAreArrayTest, WorksWithNativeArray) { EXPECT_THAT(a, Not(ElementsAreArray(b, 1))); } +TEST(ElementsAreArrayTest, SourceLifeSpan) { + const int a[] = { 1, 2, 3 }; + vector test_vector(a, a + GMOCK_ARRAY_SIZE_(a)); + vector expect(a, a + GMOCK_ARRAY_SIZE_(a)); + ElementsAreArrayMatcher matcher_maker = + ElementsAreArray(expect.begin(), expect.end()); + EXPECT_THAT(test_vector, matcher_maker); + // Changing in place the values that initialized matcher_maker should not + // affect matcher_maker anymore. It should have made its own copy of them. + typedef vector::iterator Iter; + for (Iter it = expect.begin(); it != expect.end(); ++it) { *it += 10; } + EXPECT_THAT(test_vector, matcher_maker); + test_vector.push_back(3); + EXPECT_THAT(test_vector, Not(matcher_maker)); +} + // Tests for the MATCHER*() macro family. // Tests that a simple MATCHER() definition works. @@ -1017,7 +1112,7 @@ TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { TEST(ContainsTest, ExplainsMatchResultCorrectly) { const int a[2] = { 1, 2 }; - Matcher m = Contains(2); + Matcher m = Contains(2); EXPECT_EQ("whose element #1 matches", Explain(m, a)); m = Contains(3); diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index d53282eb..3c78f647 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -343,13 +343,7 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) { class LogIsVisibleTest : public ::testing::Test { protected: virtual void SetUp() { - // The code needs to work when both ::string and ::std::string are - // defined and the flag is implemented as a - // testing::internal::String. In this case, without the call to - // c_str(), the compiler will complain that it cannot figure out - // whether the String flag should be converted to a ::string or an - // ::std::string before being assigned to original_verbose_. - original_verbose_ = GMOCK_FLAG(verbose).c_str(); + original_verbose_ = GMOCK_FLAG(verbose); } virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; } @@ -415,7 +409,7 @@ TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { TEST(LogTest, NoSkippingStackFrameInOptMode) { CaptureStdout(); Log(kWarning, "Test log.\n", 100); - const String log = GetCapturedStdout(); + const string log = GetCapturedStdout(); # if defined(NDEBUG) && GTEST_GOOGLE3_MODE_ @@ -502,7 +496,7 @@ TEST(TypeTraitsTest, remove_reference) { // Verifies that Log() behaves correctly for the given verbosity level // and log severity. -String GrabOutput(void(*logger)(), const char* verbosity) { +std::string GrabOutput(void(*logger)(), const char* verbosity) { const string saved_flag = GMOCK_FLAG(verbose); GMOCK_FLAG(verbose) = verbosity; CaptureStdout(); @@ -525,7 +519,7 @@ void ExpectCallLogger() { // Verifies that EXPECT_CALL logs if the --gmock_verbose flag is set to "info". TEST(ExpectCallTest, LogsWhenVerbosityIsInfo) { - EXPECT_THAT(GrabOutput(ExpectCallLogger, kInfoVerbosity), + EXPECT_THAT(std::string(GrabOutput(ExpectCallLogger, kInfoVerbosity)), HasSubstr("EXPECT_CALL(mock, TestMethod())")); } @@ -548,7 +542,7 @@ void OnCallLogger() { // Verifies that ON_CALL logs if the --gmock_verbose flag is set to "info". TEST(OnCallTest, LogsWhenVerbosityIsInfo) { - EXPECT_THAT(GrabOutput(OnCallLogger, kInfoVerbosity), + EXPECT_THAT(std::string(GrabOutput(OnCallLogger, kInfoVerbosity)), HasSubstr("ON_CALL(mock, TestMethod())")); } @@ -571,7 +565,7 @@ void OnCallAnyArgumentLogger() { // Verifies that ON_CALL prints provided _ argument. TEST(OnCallTest, LogsAnythingArgument) { - EXPECT_THAT(GrabOutput(OnCallAnyArgumentLogger, kInfoVerbosity), + EXPECT_THAT(std::string(GrabOutput(OnCallAnyArgumentLogger, kInfoVerbosity)), HasSubstr("ON_CALL(mock, TestMethodArg(_)")); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 6e5d5c31..de3f8d73 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -131,7 +131,6 @@ using testing::internal::IsReadableTypeName; using testing::internal::JoinAsTuple; using testing::internal::RE; using testing::internal::StreamMatchResultListener; -using testing::internal::String; using testing::internal::StringMatchResultListener; using testing::internal::Strings; using testing::internal::linked_ptr; diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index e3344180..315a8221 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -141,12 +141,12 @@ TEST(NiceMockTest, InfoForUninterestingCall) { GMOCK_FLAG(verbose) = "info"; CaptureStdout(); nice_foo.DoThis(); - EXPECT_THAT(GetCapturedStdout(), + EXPECT_THAT(std::string(GetCapturedStdout()), HasSubstr("Uninteresting mock function call")); CaptureStdout(); nice_foo.DoThat(true); - EXPECT_THAT(GetCapturedStdout(), + EXPECT_THAT(std::string(GetCapturedStdout()), HasSubstr("Uninteresting mock function call")); GMOCK_FLAG(verbose) = saved_flag; } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 9177b322..0e2e0090 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -94,7 +94,6 @@ using testing::internal::FormatFileLocation; using testing::internal::kErrorVerbosity; using testing::internal::kInfoVerbosity; using testing::internal::kWarningVerbosity; -using testing::internal::String; using testing::internal::linked_ptr; using testing::internal::string; @@ -632,7 +631,7 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooManyActions) { b.DoB(1); b.DoB(2); } - const String output = GetCapturedStdout(); + const std::string output = GetCapturedStdout(); EXPECT_PRED_FORMAT2( IsSubstring, "Too many actions specified in EXPECT_CALL(b, DoB())...\n" @@ -674,7 +673,7 @@ TEST(ExpectCallSyntaxTest, WarnsOnTooFewActions) { CaptureStdout(); b.DoB(); - const String output = GetCapturedStdout(); + const std::string output = GetCapturedStdout(); EXPECT_PRED_FORMAT2( IsSubstring, "Too few actions specified in EXPECT_CALL(b, DoB())...\n" @@ -869,13 +868,13 @@ TEST(ExpectCallTest, TakesDefaultActionWhenWillListIsExhausted) { // expectation has no action clause at all. EXPECT_EQ(1, b.DoB()); EXPECT_EQ(2, b.DoB()); - const String output1 = GetCapturedStdout(); + const std::string output1 = GetCapturedStdout(); EXPECT_STREQ("", output1.c_str()); CaptureStdout(); EXPECT_EQ(0, b.DoB()); EXPECT_EQ(0, b.DoB()); - const String output2 = GetCapturedStdout(); + const std::string output2 = GetCapturedStdout(); EXPECT_THAT(output2.c_str(), HasSubstr("Actions ran out in EXPECT_CALL(b, DoB())...\n" "Called 3 times, but only 2 WillOnce()s are specified" @@ -895,7 +894,7 @@ TEST(FunctionMockerTest, ReportsExpectCallLocationForExhausedActions) { CaptureStdout(); EXPECT_EQ(0, b.DoB()); - const String output = GetCapturedStdout(); + const std::string output = GetCapturedStdout(); // The warning message should contain the call location. EXPECT_PRED_FORMAT2(IsSubstring, expect_call_location, output); } @@ -1873,14 +1872,8 @@ class MockC { class VerboseFlagPreservingFixture : public testing::Test { protected: - // The code needs to work when both ::string and ::std::string are defined - // and the flag is implemented as a testing::internal::String. In this - // case, without the call to c_str(), the compiler will complain that it - // cannot figure out what overload of string constructor to use. - // TODO(vladl@google.com): Use internal::string instead of String for - // string flags in Google Test. VerboseFlagPreservingFixture() - : saved_verbose_flag_(GMOCK_FLAG(verbose).c_str()) {} + : saved_verbose_flag_(GMOCK_FLAG(verbose)) {} ~VerboseFlagPreservingFixture() { GMOCK_FLAG(verbose) = saved_verbose_flag_; } @@ -1898,7 +1891,7 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { MockC c; CaptureStdout(); c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); - const String output = GetCapturedStdout(); + const std::string output = GetCapturedStdout(); EXPECT_PRED_FORMAT2(IsSubstring, "GMOCK WARNING", output); EXPECT_PRED_FORMAT2(IsSubstring, "Stack trace:", output); @@ -1915,7 +1908,7 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { // stack trace. CaptureStdout(); c.NonVoidMethod(); - const String output2 = GetCapturedStdout(); + const std::string output2 = GetCapturedStdout(); EXPECT_PRED_FORMAT2(IsSubstring, "NonVoidMethod(", output2); # endif // NDEBUG @@ -1928,7 +1921,7 @@ TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { MockB b; CaptureStdout(); b.DoB(); - const String output1 = GetCapturedStdout(); + const std::string output1 = GetCapturedStdout(); EXPECT_PRED_FORMAT2( IsSubstring, "Uninteresting mock function call - returning default value.\n" @@ -1940,7 +1933,7 @@ TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { MockC c; CaptureStdout(); c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); - const String output2 = GetCapturedStdout(); + const std::string output2 = GetCapturedStdout(); EXPECT_THAT(output2.c_str(), ContainsRegex( "Uninteresting mock function call - returning directly\\.\n" @@ -1958,7 +1951,7 @@ class GMockVerboseFlagTest : public VerboseFlagPreservingFixture { // should_print is true, the output should match the given regex and // contain the given function name in the stack trace. When it's // false, the output should be empty.) - void VerifyOutput(const String& output, bool should_print, + void VerifyOutput(const std::string& output, bool should_print, const string& expected_substring, const string& function_name) { if (should_print) { -- cgit v1.2.3 From 40fa8ffc9e46cc779fc252ce2bb5aab76faf59a0 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 31 Jan 2013 19:53:54 +0000 Subject: Adds the LICENSE file to the distribution. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 0afce2f8..4509beba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Automake file # Nonstandard package files for distribution. -EXTRA_DIST = +EXTRA_DIST = LICENSE # We may need to build our internally packaged gtest. If so, it will be # included in the 'subdirs' variable. -- cgit v1.2.3 From cf40604cf087eb2a616f104fac587bd889b24e5d Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 27 Feb 2013 17:53:45 +0000 Subject: Adds -pthread and switches -I to -isystem in build instructions; also pulls in the latest gtest revision (r638). --- README | 24 ++++++++++++++++-------- make/Makefile | 7 +++++-- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/README b/README index e414f3a6..ed2e69ba 100644 --- a/README +++ b/README @@ -170,23 +170,31 @@ called by Visual Studio and Xcode) to compile with - ${GTEST_DIR}/include, ${GTEST_DIR}, ${GMOCK_DIR}/include, and ${GMOCK_DIR} + ${GTEST_DIR}/include and ${GMOCK_DIR}/include -in the header search path. Assuming a Linux-like system and gcc, +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++ -I${GTEST_DIR}/include -I${GTEST_DIR} -I${GMOCK_DIR}/include \ - -I${GMOCK_DIR} -c ${GTEST_DIR}/src/gtest-all.cc - g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -I${GMOCK_DIR}/include \ - -I${GMOCK_DIR} -c ${GMOCK_DIR}/src/gmock-all.cc + 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++ -I${GTEST_DIR}/include -I${GMOCK_DIR}/include \ - path/to/your_test.cc libgmock.a -o your_test + 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 diff --git a/make/Makefile b/make/Makefile index 6386e5b2..c1cc0e90 100644 --- a/make/Makefile +++ b/make/Makefile @@ -27,10 +27,13 @@ GMOCK_DIR = .. USER_DIR = ../test # Flags passed to the preprocessor. -CPPFLAGS += -I$(GTEST_DIR)/include -I$(GMOCK_DIR)/include +# Set Google Test and Google Mock's header directories as system +# directories, such that the compiler doesn't generate warnings in +# these headers. +CPPFLAGS += -isystem $(GTEST_DIR)/include -isystem $(GMOCK_DIR)/include # Flags passed to the C++ compiler. -CXXFLAGS += -g -Wall -Wextra +CXXFLAGS += -g -Wall -Wextra -pthread # All tests produced by this Makefile. Remember to add new tests you # created to the list. -- cgit v1.2.3 From edd4ab4945aeacdf9bd5ec3ac1654b940ca72532 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 28 Feb 2013 22:58:51 +0000 Subject: Makes googlemock throw a runtime_error instead of abort when a mock method with no default value is invoked (if exceptions are enabled). --- include/gmock/gmock-spec-builders.h | 27 +++- test/gmock-actions_test.cc | 8 +- test/gmock-spec-builders_test.cc | 265 +++++++++++++++++++++++------------- test/gmock_ex_test.cc | 78 +++++++++++ 4 files changed, 277 insertions(+), 101 deletions(-) create mode 100644 test/gmock_ex_test.cc diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index c677333c..59f1d71e 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -66,6 +66,10 @@ #include #include +#if GTEST_HAS_EXCEPTIONS +# include // NOLINT +#endif + #include "gmock/gmock-actions.h" #include "gmock/gmock-cardinalities.h" #include "gmock/gmock-matchers.h" @@ -1425,10 +1429,12 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { return NULL; } - // Performs the default action of this mock function on the given arguments - // and returns the result. Asserts with a helpful call descrption if there is - // no valid return value. This method doesn't depend on the mutable state of - // this object, and thus can be called concurrently without locking. + // Performs the default action of this mock function on the given + // arguments and returns the result. Asserts (or throws if + // exceptions are enabled) with a helpful call descrption if there + // is no valid return value. This method doesn't depend on the + // mutable state of this object, and thus can be called concurrently + // without locking. // L = * Result PerformDefaultAction(const ArgumentTuple& args, const string& call_description) const { @@ -1437,9 +1443,16 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { if (spec != NULL) { return spec->GetAction().Perform(args); } - Assert(DefaultValue::Exists(), "", -1, - call_description + "\n The mock function has no default action " - "set, and its return type has no default value set."); + const string message = call_description + + "\n The mock function has no default action " + "set, and its return type has no default value set."; +#if GTEST_HAS_EXCEPTIONS + if (!DefaultValue::Exists()) { + throw std::runtime_error(message); + } +#else + Assert(DefaultValue::Exists(), "", -1, message); +#endif return DefaultValue::Get(); } diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index fd87c74c..1210d464 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -634,15 +634,19 @@ TEST(DoDefaultTest, ReturnsBuiltInDefaultValueByDefault) { EXPECT_EQ(0, mock.IntFunc(true)); } -// Tests that DoDefault() aborts the process when there is no built-in -// default value for the return type. +// Tests that DoDefault() throws (when exceptions are enabled) or aborts +// the process when there is no built-in default value for the return type. TEST(DoDefaultDeathTest, DiesForUnknowType) { MockClass mock; EXPECT_CALL(mock, Foo()) .WillRepeatedly(DoDefault()); +#if GTEST_HAS_EXCEPTIONS + EXPECT_ANY_THROW(mock.Foo()); +#else EXPECT_DEATH_IF_SUPPORTED({ mock.Foo(); }, ""); +#endif } // Tests that using DoDefault() inside a composite action leads to a diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 0e2e0090..8a8632dc 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1111,7 +1111,11 @@ TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) { // TODO(wan@google.com): We should really verify the output message, // but we cannot yet due to that EXPECT_DEATH only captures stderr // while Google Mock logs to stdout. +#if GTEST_HAS_EXCEPTIONS + EXPECT_ANY_THROW(a.ReturnResult(1)); +#else EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(1), ""); +#endif } // Tests that an excessive call (one whose arguments match the @@ -1260,87 +1264,116 @@ TEST(SequenceTest, AnyOrderIsOkByDefault) { // Tests that the calls must be in strict order when a complete order // is specified. -TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo) { +TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo1) { MockA a; - Sequence s; + ON_CALL(a, ReturnResult(_)) + .WillByDefault(Return(Result())); + Sequence s; EXPECT_CALL(a, ReturnResult(1)) - .InSequence(s) - .WillOnce(Return(Result())); - + .InSequence(s); EXPECT_CALL(a, ReturnResult(2)) - .InSequence(s) - .WillOnce(Return(Result())); - + .InSequence(s); EXPECT_CALL(a, ReturnResult(3)) - .InSequence(s) - .WillOnce(Return(Result())); + .InSequence(s); - EXPECT_DEATH_IF_SUPPORTED({ - a.ReturnResult(1); - a.ReturnResult(3); - a.ReturnResult(2); - }, ""); + a.ReturnResult(1); - EXPECT_DEATH_IF_SUPPORTED({ - a.ReturnResult(2); - a.ReturnResult(1); - a.ReturnResult(3); - }, ""); + // May only be called after a.ReturnResult(2). + EXPECT_NONFATAL_FAILURE(a.ReturnResult(3), "Unexpected mock function call"); - a.ReturnResult(1); a.ReturnResult(2); a.ReturnResult(3); } -// Tests specifying a DAG using multiple sequences. -TEST(SequenceTest, CallsMustConformToSpecifiedDag) { +// Tests that the calls must be in strict order when a complete order +// is specified. +TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo2) { MockA a; - MockB b; - Sequence x, y; + ON_CALL(a, ReturnResult(_)) + .WillByDefault(Return(Result())); + Sequence s; EXPECT_CALL(a, ReturnResult(1)) - .InSequence(x) - .WillOnce(Return(Result())); + .InSequence(s); + EXPECT_CALL(a, ReturnResult(2)) + .InSequence(s); - EXPECT_CALL(b, DoB()) - .Times(2) - .InSequence(y); + // May only be called after a.ReturnResult(1). + EXPECT_NONFATAL_FAILURE(a.ReturnResult(2), "Unexpected mock function call"); - EXPECT_CALL(a, ReturnResult(2)) - .InSequence(x, y) - .WillRepeatedly(Return(Result())); + a.ReturnResult(1); + a.ReturnResult(2); +} - EXPECT_CALL(a, ReturnResult(3)) - .InSequence(x) - .WillOnce(Return(Result())); +// Tests specifying a DAG using multiple sequences. +class PartialOrderTest : public testing::Test { + protected: + PartialOrderTest() { + ON_CALL(a_, ReturnResult(_)) + .WillByDefault(Return(Result())); - EXPECT_DEATH_IF_SUPPORTED({ - a.ReturnResult(1); - b.DoB(); - a.ReturnResult(2); - }, ""); + // Specifies this partial ordering: + // + // a.ReturnResult(1) ==> + // a.ReturnResult(2) * n ==> a.ReturnResult(3) + // b.DoB() * 2 ==> + Sequence x, y; + EXPECT_CALL(a_, ReturnResult(1)) + .InSequence(x); + EXPECT_CALL(b_, DoB()) + .Times(2) + .InSequence(y); + EXPECT_CALL(a_, ReturnResult(2)) + .Times(AnyNumber()) + .InSequence(x, y); + EXPECT_CALL(a_, ReturnResult(3)) + .InSequence(x); + } - EXPECT_DEATH_IF_SUPPORTED({ - a.ReturnResult(2); - }, ""); + MockA a_; + MockB b_; +}; - EXPECT_DEATH_IF_SUPPORTED({ - a.ReturnResult(3); - }, ""); +TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag1) { + a_.ReturnResult(1); + b_.DoB(); - EXPECT_DEATH_IF_SUPPORTED({ - a.ReturnResult(1); - b.DoB(); - b.DoB(); - a.ReturnResult(3); - a.ReturnResult(2); - }, ""); + // May only be called after the second DoB(). + EXPECT_NONFATAL_FAILURE(a_.ReturnResult(2), "Unexpected mock function call"); - b.DoB(); - a.ReturnResult(1); - b.DoB(); - a.ReturnResult(3); + b_.DoB(); + a_.ReturnResult(3); +} + +TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag2) { + // May only be called after ReturnResult(1). + EXPECT_NONFATAL_FAILURE(a_.ReturnResult(2), "Unexpected mock function call"); + + a_.ReturnResult(1); + b_.DoB(); + b_.DoB(); + a_.ReturnResult(3); +} + +TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag3) { + // May only be called last. + EXPECT_NONFATAL_FAILURE(a_.ReturnResult(3), "Unexpected mock function call"); + + a_.ReturnResult(1); + b_.DoB(); + b_.DoB(); + a_.ReturnResult(3); +} + +TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag4) { + a_.ReturnResult(1); + b_.DoB(); + b_.DoB(); + a_.ReturnResult(3); + + // May only be called before ReturnResult(3). + EXPECT_NONFATAL_FAILURE(a_.ReturnResult(2), "Unexpected mock function call"); } TEST(SequenceTest, Retirement) { @@ -1530,71 +1563,112 @@ TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) { a.DoA(2); } -// Calls must be in strict order when specified so. -TEST(AfterDeathTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { +// Calls must be in strict order when specified so using .After(). +TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo1) { MockA a; MockB b; + + // Define ordering: + // a.DoA(1) ==> b.DoB() ==> a.DoA(2) Expectation e1 = EXPECT_CALL(a, DoA(1)); Expectation e2 = EXPECT_CALL(b, DoB()) - .Times(2) .After(e1); - EXPECT_CALL(a, ReturnResult(2)) - .After(e2) - .WillOnce(Return(Result())); + EXPECT_CALL(a, DoA(2)) + .After(e2); a.DoA(1); - // If a call to ReturnResult() violates the specified order, no - // matching expectation will be found, and thus the default action - // will be done. Since the return type of ReturnResult() is not a - // built-in type, gmock won't know what to return and will thus - // abort the program. Therefore a death test can tell us whether - // gmock catches the order violation correctly. - // - // gtest and gmock print messages to stdout, which isn't captured by - // death tests. Therefore we have to match with an empty regular - // expression in all the EXPECT_DEATH()s. - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(2), ""); + + // May only be called after DoB(). + EXPECT_NONFATAL_FAILURE(a.DoA(2), "Unexpected mock function call"); b.DoB(); - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(2), ""); + a.DoA(2); +} + +// Calls must be in strict order when specified so using .After(). +TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo2) { + MockA a; + MockB b; + + // Define ordering: + // a.DoA(1) ==> b.DoB() * 2 ==> a.DoA(2) + Expectation e1 = EXPECT_CALL(a, DoA(1)); + Expectation e2 = EXPECT_CALL(b, DoB()) + .Times(2) + .After(e1); + EXPECT_CALL(a, DoA(2)) + .After(e2); + a.DoA(1); b.DoB(); - a.ReturnResult(2); + + // May only be called after the second DoB(). + EXPECT_NONFATAL_FAILURE(a.DoA(2), "Unexpected mock function call"); + + b.DoB(); + a.DoA(2); } // Calls must satisfy the partial order when specified so. -TEST(AfterDeathTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { +TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { MockA a; + ON_CALL(a, ReturnResult(_)) + .WillByDefault(Return(Result())); + + // Define ordering: + // a.DoA(1) ==> + // a.DoA(2) ==> a.ReturnResult(3) Expectation e = EXPECT_CALL(a, DoA(1)); const ExpectationSet es = EXPECT_CALL(a, DoA(2)); EXPECT_CALL(a, ReturnResult(3)) - .After(e, es) - .WillOnce(Return(Result())); + .After(e, es); - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); + // May only be called last. + EXPECT_NONFATAL_FAILURE(a.ReturnResult(3), "Unexpected mock function call"); a.DoA(2); - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); - a.DoA(1); a.ReturnResult(3); } +// Calls must satisfy the partial order when specified so. +TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo2) { + MockA a; + + // Define ordering: + // a.DoA(1) ==> + // a.DoA(2) ==> a.DoA(3) + Expectation e = EXPECT_CALL(a, DoA(1)); + const ExpectationSet es = EXPECT_CALL(a, DoA(2)); + EXPECT_CALL(a, DoA(3)) + .After(e, es); + + a.DoA(2); + + // May only be called last. + EXPECT_NONFATAL_FAILURE(a.DoA(3), "Unexpected mock function call"); + + a.DoA(1); + a.DoA(3); +} + // .After() can be combined with .InSequence(). -TEST(AfterDeathTest, CanBeUsedWithInSequence) { +TEST(AfterTest, CanBeUsedWithInSequence) { MockA a; Sequence s; Expectation e = EXPECT_CALL(a, DoA(1)); EXPECT_CALL(a, DoA(2)).InSequence(s); - EXPECT_CALL(a, ReturnResult(3)) - .InSequence(s).After(e) - .WillOnce(Return(Result())); + EXPECT_CALL(a, DoA(3)) + .InSequence(s) + .After(e); a.DoA(1); - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); + + // May only be after DoA(2). + EXPECT_NONFATAL_FAILURE(a.DoA(3), "Unexpected mock function call"); a.DoA(2); - a.ReturnResult(3); + a.DoA(3); } // .After() can be called multiple times. @@ -1636,17 +1710,24 @@ TEST(AfterTest, AcceptsUpToFiveArguments) { // .After() allows input to contain duplicated Expectations. TEST(AfterTest, AcceptsDuplicatedInput) { MockA a; + ON_CALL(a, ReturnResult(_)) + .WillByDefault(Return(Result())); + + // Define ordering: + // DoA(1) ==> + // DoA(2) ==> ReturnResult(3) Expectation e1 = EXPECT_CALL(a, DoA(1)); Expectation e2 = EXPECT_CALL(a, DoA(2)); ExpectationSet es; es += e1; es += e2; EXPECT_CALL(a, ReturnResult(3)) - .After(e1, e2, es, e1) - .WillOnce(Return(Result())); + .After(e1, e2, es, e1); a.DoA(1); - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); + + // May only be after DoA(2). + EXPECT_NONFATAL_FAILURE(a.ReturnResult(3), "Unexpected mock function call"); a.DoA(2); a.ReturnResult(3); diff --git a/test/gmock_ex_test.cc b/test/gmock_ex_test.cc new file mode 100644 index 00000000..a5a8a421 --- /dev/null +++ b/test/gmock_ex_test.cc @@ -0,0 +1,78 @@ +// Copyright 2013, 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) + +// Tests Google Mock's functionality that depends on exceptions. + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { + +using testing::HasSubstr; +using testing::internal::GoogleTestFailureException; + +// A user-defined class. +class Something {}; + +class MockFoo { + public: + // A mock method that returns a user-defined type. Google Mock + // doesn't know what the default value for this type is. + MOCK_METHOD0(GetSomething, Something()); +}; + +#if GTEST_HAS_EXCEPTIONS + +TEST(DefaultValueTest, ThrowsRuntimeErrorWhenNoDefaultValue) { + MockFoo mock; + try { + // No expectation is set on this method, so Google Mock must + // return the default value. However, since Google Mock knows + // nothing about the return type, it doesn't know what to return, + // and has to throw (when exceptions are enabled) or abort + // (otherwise). + mock.GetSomething(); + FAIL() << "GetSomething()'s return type has no default value, " + << "so Google Mock should have thrown."; + } catch (const GoogleTestFailureException& /* unused */) { + FAIL() << "Google Test does not try to catch an exception of type " + << "GoogleTestFailureException, which is used for reporting " + << "a failure to other testing frameworks. Google Mock should " + << "not throw a GoogleTestFailureException as it will kill the " + << "entire test program instead of just the current TEST."; + } catch (const std::exception& ex) { + EXPECT_THAT(ex.what(), HasSubstr("has no default value")); + } +} + +#endif + +} // unnamed namespace -- cgit v1.2.3 From 320814aca02dfb6b5f116bc5de1785a478cc6d42 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 00:20:30 +0000 Subject: Implements matcher IsEmpty(); also pulls in gtest r643. --- include/gmock/gmock-more-matchers.h | 58 +++++++++++++++++++++++++++++++++++++ include/gmock/gmock.h | 5 ++-- test/gmock-matchers_test.cc | 34 ++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 include/gmock/gmock-more-matchers.h diff --git a/include/gmock/gmock-more-matchers.h b/include/gmock/gmock-more-matchers.h new file mode 100644 index 00000000..3db899f4 --- /dev/null +++ b/include/gmock/gmock-more-matchers.h @@ -0,0 +1,58 @@ +// Copyright 2013, 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: marcus.boerger@google.com (Marcus Boerger) + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some matchers that depend on gmock-generated-matchers.h. +// +// Note that tests are implemented in gmock-matchers_test.cc rather than +// gmock-more-matchers-test.cc. + +#ifndef GMOCK_GMOCK_MORE_MATCHERS_H_ +#define GMOCK_GMOCK_MORE_MATCHERS_H_ + +#include "gmock/gmock-generated-matchers.h" + +namespace testing { + +// Defines a matcher that matches an empty container. The container must +// support both size() and empty(), which all STL-like containers provide. +MATCHER(IsEmpty, negation ? "isn't empty" : "is empty") { + if (arg.empty()) { + return true; + } + *result_listener << "whose size is " << arg.size(); + return false; +} + +} // namespace testing + +#endif // GMOCK_GMOCK_MORE_MATCHERS_H_ diff --git a/include/gmock/gmock.h b/include/gmock/gmock.h index 481e5706..6735c71b 100644 --- a/include/gmock/gmock.h +++ b/include/gmock/gmock.h @@ -59,10 +59,11 @@ #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-more-actions.h" #include "gmock/gmock-generated-nice-strict.h" +#include "gmock/gmock-generated-matchers.h" #include "gmock/gmock-matchers.h" +#include "gmock/gmock-more-actions.h" +#include "gmock/gmock-more-matchers.h" #include "gmock/internal/gmock-internal-utils.h" namespace testing { diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index de3f8d73..e75b06e0 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -34,6 +34,7 @@ // This file tests some commonly used argument matchers. #include "gmock/gmock-matchers.h" +#include "gmock/gmock-more-matchers.h" #include #include @@ -88,6 +89,7 @@ using testing::FloatEq; using testing::Ge; using testing::Gt; using testing::HasSubstr; +using testing::IsEmpty; using testing::IsNull; using testing::Key; using testing::Le; @@ -3603,6 +3605,38 @@ TEST(ByRefTest, AllowsNotCopyableValueInMatchers) { EXPECT_TRUE(m.Matches(n2)); } +TEST(IsEmptyTest, ImplementsIsEmpty) { + vector container; + EXPECT_THAT(container, IsEmpty()); + container.push_back(0); + EXPECT_THAT(container, Not(IsEmpty())); + container.push_back(1); + EXPECT_THAT(container, Not(IsEmpty())); +} + +TEST(IsEmptyTest, WorksWithString) { + string text; + EXPECT_THAT(text, IsEmpty()); + text = "foo"; + EXPECT_THAT(text, Not(IsEmpty())); + text = string("\0", 1); + EXPECT_THAT(text, Not(IsEmpty())); +} + +TEST(IsEmptyTest, CanDescribeSelf) { + Matcher > m = IsEmpty(); + EXPECT_EQ("is empty", Describe(m)); + EXPECT_EQ("isn't empty", DescribeNegation(m)); +} + +TEST(IsEmptyTest, ExplainsResult) { + Matcher > m = IsEmpty(); + vector container; + EXPECT_EQ("", Explain(m, container)); + container.push_back(0); + EXPECT_EQ("whose size is 1", Explain(m, container)); +} + #if GTEST_HAS_TYPED_TEST // Tests ContainerEq with different container types, and // different element types. -- cgit v1.2.3 From 83f6b08b5f730c2bfaa288a17d5f12ca98901a00 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 01:47:35 +0000 Subject: Clarifies how to implement MatcherInterface. --- include/gmock/gmock-matchers.h | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 751574ca..19bd551a 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -112,10 +112,27 @@ class MatcherInterface { virtual ~MatcherInterface() {} // Returns true iff the matcher matches x; also explains the match - // result to 'listener', 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 ...". + // 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. // -- cgit v1.2.3 From a31d9ce2900275c5b9aff2459664a50381c7cbb0 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 01:50:17 +0000 Subject: Implements matcher SizeIs(). --- include/gmock/gmock-matchers.h | 64 ++++++++++++++++++++++++++++++++++++++++++ test/gmock-matchers_test.cc | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 19bd551a..dc93468c 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1972,6 +1972,58 @@ class ResultOfMatcher { GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); }; +// Implements a matcher that checks the size of an STL-style container. +template +class SizeIsMatcher { + public: + explicit SizeIsMatcher(const SizeMatcher& size_matcher) + : size_matcher_(size_matcher) { + } + + template + operator Matcher() const { + return MakeMatcher(new Impl(size_matcher_)); + } + + template + class Impl : public MatcherInterface { + public: + typedef internal::StlContainerView< + GTEST_REMOVE_REFERENCE_AND_CONST_(Container)> ContainerView; + typedef typename ContainerView::type::size_type SizeType; + explicit Impl(const SizeMatcher& size_matcher) + : size_matcher_(MatcherCast(size_matcher)) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "size "; + size_matcher_.DescribeTo(os); + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "size "; + size_matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { + SizeType size = container.size(); + StringMatchResultListener size_listener; + const bool result = size_matcher_.MatchAndExplain(size, &size_listener); + *listener + << "whose size " << size << (result ? " matches" : " doesn't match"); + PrintIfNotEmpty(size_listener.str(), listener->stream()); + return result; + } + + private: + const Matcher size_matcher_; + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + private: + const SizeMatcher size_matcher_; + GTEST_DISALLOW_ASSIGN_(SizeIsMatcher); +}; + // Implements an equality matcher for any STL-style container whose elements // support ==. This matcher is like Eq(), but its failure explanations provide // more detailed information that is useful when the container is used as a set. @@ -3079,6 +3131,18 @@ Truly(Predicate pred) { return MakePolymorphicMatcher(internal::TrulyMatcher(pred)); } +// Returns a matcher that matches the container size. The container must +// support both size() and size_type which all STL-like containers provide. +// Note that the parameter 'size' can be a value of type size_type as well as +// matcher. For instance: +// EXPECT_THAT(container, SizeIs(2)); // Checks container has 2 elements. +// EXPECT_THAT(container, SizeIs(Le(2)); // Checks container has at most 2. +template +inline internal::SizeIsMatcher +SizeIs(const SizeMatcher& size_matcher) { + return internal::SizeIsMatcher(size_matcher); +} + // Returns a matcher that matches an equal container. // This matcher behaves like Eq(), but in the event of mismatch lists the // values that are included in one container but not the other. (Duplicate diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index e75b06e0..81460925 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -114,6 +114,7 @@ using testing::PolymorphicMatcher; using testing::Property; using testing::Ref; using testing::ResultOf; +using testing::SizeIs; using testing::StartsWith; using testing::StrCaseEq; using testing::StrCaseNe; @@ -3637,6 +3638,64 @@ TEST(IsEmptyTest, ExplainsResult) { EXPECT_EQ("whose size is 1", Explain(m, container)); } +TEST(SizeIsTest, ImplementsSizeIs) { + vector container; + EXPECT_THAT(container, SizeIs(0)); + EXPECT_THAT(container, Not(SizeIs(1))); + container.push_back(0); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(1)); + container.push_back(0); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(2)); +} + +TEST(SizeIsTest, WorksWithMap) { + map container; + EXPECT_THAT(container, SizeIs(0)); + EXPECT_THAT(container, Not(SizeIs(1))); + container.insert(make_pair("foo", 1)); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(1)); + container.insert(make_pair("bar", 2)); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(2)); +} + +TEST(SizeIsTest, WorksWithReferences) { + vector container; + Matcher&> m = SizeIs(1); + EXPECT_THAT(container, Not(m)); + container.push_back(0); + EXPECT_THAT(container, m); +} + +TEST(SizeIsTest, CanDescribeSelf) { + Matcher > m = SizeIs(2); + EXPECT_EQ("size is equal to 2", Describe(m)); + EXPECT_EQ("size isn't equal to 2", DescribeNegation(m)); +} + +TEST(SizeIsTest, ExplainsResult) { + Matcher > m1 = SizeIs(2); + Matcher > m2 = SizeIs(Lt(2u)); + Matcher > m3 = SizeIs(AnyOf(0, 3)); + Matcher > m4 = SizeIs(GreaterThan(1)); + vector container; + EXPECT_EQ("whose size 0 doesn't match", Explain(m1, container)); + EXPECT_EQ("whose size 0 matches", Explain(m2, container)); + EXPECT_EQ("whose size 0 matches", Explain(m3, container)); + EXPECT_EQ("whose size 0 doesn't match, which is 1 less than 1", + Explain(m4, container)); + container.push_back(0); + container.push_back(0); + EXPECT_EQ("whose size 2 matches", Explain(m1, container)); + EXPECT_EQ("whose size 2 doesn't match", Explain(m2, container)); + EXPECT_EQ("whose size 2 doesn't match", Explain(m3, container)); + EXPECT_EQ("whose size 2 matches, which is 1 more than 1", + Explain(m4, container)); +} + #if GTEST_HAS_TYPED_TEST // Tests ContainerEq with different container types, and // different element types. -- cgit v1.2.3 From 844fa94976acbcd01dc2de0a0cc7efc4f97274df Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 01:54:22 +0000 Subject: Implements NaggyMock. --- include/gmock/gmock-generated-nice-strict.h | 157 ++++++++++++++++++++--- include/gmock/gmock-generated-nice-strict.h.pump | 117 ++++++++--------- include/gmock/gmock-spec-builders.h | 3 + test/gmock-nice-strict_test.cc | 106 ++++++++++++++- 4 files changed, 302 insertions(+), 81 deletions(-) diff --git a/include/gmock/gmock-generated-nice-strict.h b/include/gmock/gmock-generated-nice-strict.h index 6099e81e..4095f4d5 100644 --- a/include/gmock/gmock-generated-nice-strict.h +++ b/include/gmock/gmock-generated-nice-strict.h @@ -1,4 +1,6 @@ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! +// 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. @@ -31,26 +33,36 @@ // // Author: wan@google.com (Zhanyong Wan) -// Implements class templates NiceMock and StrictMock. +// 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), and StrictMock is a subclass of -// MockFoo that treats all uninteresting calls as errors. +// 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. // -// NiceMock and StrictMock "inherits" 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. +// 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. // -// A known limitation is that NiceMock 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 and StrictMock is NOT supported. +// 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 @@ -160,6 +172,102 @@ class NiceMock : public MockClass { 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: @@ -170,6 +278,8 @@ class StrictMock : public MockClass { 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( @@ -258,15 +368,28 @@ class StrictMock : public MockClass { // user errors of nesting nice and strict mocks. They do NOT catch // all possible errors. -// These specializations are declared but not defined, as NiceMock and -// StrictMock cannot be nested. +// 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 diff --git a/include/gmock/gmock-generated-nice-strict.h.pump b/include/gmock/gmock-generated-nice-strict.h.pump index b7964db3..3ee1ce7f 100644 --- a/include/gmock/gmock-generated-nice-strict.h.pump +++ b/include/gmock/gmock-generated-nice-strict.h.pump @@ -34,26 +34,36 @@ $var n = 10 $$ The maximum arity we support. // // Author: wan@google.com (Zhanyong Wan) -// Implements class templates NiceMock and StrictMock. +// 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), and StrictMock is a subclass of -// MockFoo that treats all uninteresting calls as errors. +// 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. // -// NiceMock and StrictMock "inherits" 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. +// 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. // -// A known limitation is that NiceMock 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 and StrictMock is NOT supported. +// 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 @@ -67,21 +77,32 @@ $var n = 10 $$ The maximum arity we support. 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 NiceMock : public MockClass { +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. - NiceMock() { - ::testing::Mock::AllowUninterestingCalls( + $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 NiceMock(const A1& a1) : MockClass(a1) { - ::testing::Mock::AllowUninterestingCalls( + explicit $clazz(const A1& a1) : MockClass(a1) { + ::testing::Mock::$method( internal::ImplicitCast_(this)); } @@ -89,70 +110,50 @@ $range i 2..n $for i [[ $range j 1..i template <$for j, [[typename A$j]]> - NiceMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { - ::testing::Mock::AllowUninterestingCalls( + $clazz($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { + ::testing::Mock::$method( internal::ImplicitCast_(this)); } ]] - virtual ~NiceMock() { + virtual ~$clazz() { ::testing::Mock::UnregisterCallReaction( internal::ImplicitCast_(this)); } private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); + GTEST_DISALLOW_COPY_AND_ASSIGN_($clazz); }; -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)); - } - - template - explicit StrictMock(const A1& a1) : MockClass(a1) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - -$for i [[ -$range j 1..i - template <$for j, [[typename A$j]]> - StrictMock($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { - ::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 and -// StrictMock cannot be nested. +// 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 diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 59f1d71e..4c2dca98 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -399,6 +399,9 @@ class GTEST_API_ Mock { template friend class NiceMock; + template + friend class NaggyMock; + template friend class StrictMock; diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 315a8221..9b83d88e 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -54,6 +54,7 @@ namespace gmock_nice_strict_test { using testing::internal::string; using testing::GMOCK_FLAG(verbose); using testing::HasSubstr; +using testing::NaggyMock; using testing::NiceMock; using testing::StrictMock; @@ -116,7 +117,7 @@ TEST(NiceMockTest, NoWarningForUninterestingCall) { CaptureStdout(); nice_foo.DoThis(); nice_foo.DoThat(true); - EXPECT_STREQ("", GetCapturedStdout().c_str()); + EXPECT_EQ("", GetCapturedStdout()); } // Tests that a nice mock generates no warning for uninteresting calls @@ -129,7 +130,7 @@ TEST(NiceMockTest, NoWarningForUninterestingCallAfterDeath) { CaptureStdout(); nice_foo->DoThis(); - EXPECT_STREQ("", GetCapturedStdout().c_str()); + EXPECT_EQ("", GetCapturedStdout()); } // Tests that a nice mock generates informational logs for @@ -141,12 +142,12 @@ TEST(NiceMockTest, InfoForUninterestingCall) { GMOCK_FLAG(verbose) = "info"; CaptureStdout(); nice_foo.DoThis(); - EXPECT_THAT(std::string(GetCapturedStdout()), + EXPECT_THAT(GetCapturedStdout(), HasSubstr("Uninteresting mock function call")); CaptureStdout(); nice_foo.DoThat(true); - EXPECT_THAT(std::string(GetCapturedStdout()), + EXPECT_THAT(GetCapturedStdout(), HasSubstr("Uninteresting mock function call")); GMOCK_FLAG(verbose) = saved_flag; } @@ -192,7 +193,7 @@ TEST(NiceMockTest, NonDefaultConstructor10) { #if !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE // Tests that NiceMock compiles where Mock is a user-defined -// class (as opposed to ::testing::Mock). We had to workaround an +// class (as opposed to ::testing::Mock). We had to work around an // MSVC 8.0 bug that caused the symbol Mock used in the definition of // NiceMock to be looked up in the wrong context, and this test // ensures that our fix works. @@ -206,6 +207,99 @@ TEST(NiceMockTest, AcceptsClassNamedMock) { } #endif // !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_HAS_STREAM_REDIRECTION + +// Tests that a naggy mock generates warnings for uninteresting calls. +TEST(NaggyMockTest, WarningForUninterestingCall) { + const string saved_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = "warning"; + + NaggyMock naggy_foo; + + CaptureStdout(); + naggy_foo.DoThis(); + naggy_foo.DoThat(true); + EXPECT_THAT(GetCapturedStdout(), + HasSubstr("Uninteresting mock function call")); + + GMOCK_FLAG(verbose) = saved_flag; +} + +// Tests that a naggy mock generates a warning for an uninteresting call +// that deletes the mock object. +TEST(NaggyMockTest, WarningForUninterestingCallAfterDeath) { + const string saved_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = "warning"; + + NaggyMock* const naggy_foo = new NaggyMock; + + ON_CALL(*naggy_foo, DoThis()) + .WillByDefault(Invoke(naggy_foo, &MockFoo::Delete)); + + CaptureStdout(); + naggy_foo->DoThis(); + EXPECT_THAT(GetCapturedStdout(), + HasSubstr("Uninteresting mock function call")); + + GMOCK_FLAG(verbose) = saved_flag; +} + +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Tests that a naggy mock allows expected calls. +TEST(NaggyMockTest, AllowsExpectedCall) { + NaggyMock naggy_foo; + + EXPECT_CALL(naggy_foo, DoThis()); + naggy_foo.DoThis(); +} + +// Tests that an unexpected call on a naggy mock fails. +TEST(NaggyMockTest, UnexpectedCallFails) { + NaggyMock naggy_foo; + + EXPECT_CALL(naggy_foo, DoThis()).Times(0); + EXPECT_NONFATAL_FAILURE(naggy_foo.DoThis(), + "called more times than expected"); +} + +// Tests that NaggyMock works with a mock class that has a non-default +// constructor. +TEST(NaggyMockTest, NonDefaultConstructor) { + NaggyMock naggy_bar("hi"); + EXPECT_EQ("hi", naggy_bar.str()); + + naggy_bar.This(); + naggy_bar.That(5, true); +} + +// Tests that NaggyMock works with a mock class that has a 10-ary +// non-default constructor. +TEST(NaggyMockTest, NonDefaultConstructor10) { + NaggyMock naggy_bar('0', '1', "2", "3", '4', '5', + "6", "7", true, false); + EXPECT_EQ("01234567TF", naggy_bar.str()); + + naggy_bar.This(); + naggy_bar.That(5, true); +} + +#if !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE +// Tests that NaggyMock compiles where Mock is a user-defined +// class (as opposed to ::testing::Mock). We had to work around an +// MSVC 8.0 bug that caused the symbol Mock used in the definition of +// NaggyMock to be looked up in the wrong context, and this test +// ensures that our fix works. +// +// We have to skip this test on Symbian and Windows Mobile, as it +// causes the program to crash there, for reasons unclear to us yet. +TEST(NaggyMockTest, AcceptsClassNamedMock) { + NaggyMock< ::Mock> naggy; + EXPECT_CALL(naggy, DoThis()); + naggy.DoThis(); +} +#endif // !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE + // Tests that a strict mock allows expected calls. TEST(StrictMockTest, AllowsExpectedCall) { StrictMock strict_foo; @@ -266,7 +360,7 @@ TEST(StrictMockTest, NonDefaultConstructor10) { #if !GTEST_OS_SYMBIAN && !GTEST_OS_WINDOWS_MOBILE // Tests that StrictMock compiles where Mock is a user-defined -// class (as opposed to ::testing::Mock). We had to workaround an +// class (as opposed to ::testing::Mock). We had to work around an // MSVC 8.0 bug that caused the symbol Mock used in the definition of // StrictMock to be looked up in the wrong context, and this test // ensures that our fix works. -- cgit v1.2.3 From 29be92385e118de1b2ef45daf38dfd1dabbea63f Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 06:53:35 +0000 Subject: Removes unused variables and functions. --- test/gmock-actions_test.cc | 58 +---------------------------------- test/gmock-generated-actions_test.cc | 13 ++++++++ test/gmock-generated-matchers_test.cc | 13 ++++++++ 3 files changed, 27 insertions(+), 57 deletions(-) diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 1210d464..68bdadee 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -1031,68 +1031,12 @@ class VoidNullaryFunctor { void operator()() { g_done = true; } }; -bool Unary(int x) { return x < 0; } - -const char* Plus1(const char* s) { return s + 1; } - -void VoidUnary(int /* n */) { g_done = true; } - -bool ByConstRef(const std::string& s) { return s == "Hi"; } - -const double g_double = 0; -bool ReferencesGlobalDouble(const double& x) { return &x == &g_double; } - -std::string ByNonConstRef(std::string& s) { return s += "+"; } // NOLINT - -struct UnaryFunctor { - int operator()(bool x) { return x ? 1 : -1; } -}; - -const char* Binary(const char* input, short n) { return input + n; } // NOLINT - -void VoidBinary(int, char) { g_done = true; } - -int Ternary(int x, char y, short z) { return x + y + z; } // NOLINT - -void VoidTernary(int, char, bool) { g_done = true; } - -int SumOf4(int a, int b, int c, int d) { return a + b + c + d; } - -void VoidFunctionWithFourArguments(char, int, float, double) { g_done = true; } - -int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } - -struct SumOf5Functor { - int operator()(int a, int b, int c, int d, int e) { - return a + b + c + d + e; - } -}; - -int SumOf6(int a, int b, int c, int d, int e, int f) { - return a + b + c + d + e + f; -} - -struct SumOf6Functor { - int operator()(int a, int b, int c, int d, int e, int f) { - return a + b + c + d + e + f; - } -}; - class Foo { public: Foo() : value_(123) {} int Nullary() const { return value_; } - short Unary(long x) { return static_cast(value_ + x); } // NOLINT - std::string Binary(const std::string& str, char c) const { return str + c; } - int Ternary(int x, bool y, char z) { return value_ + x + y*z; } - int SumOf4(int a, int b, int c, int d) const { - return a + b + c + d + value_; - } - int SumOf5(int a, int b, int c, int d, int e) { return a + b + c + d + e; } - int SumOf6(int a, int b, int c, int d, int e, int f) { - return a + b + c + d + e + f; - } + private: int value_; }; diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index 436f1a2e..23f8c8b0 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -956,6 +956,19 @@ TEST(ActionPnMacroTest, TypesAreCorrect) { Plus(1, 2, 3, 4, 5, 6, 7, 8, '9'); PlusActionP10 a10 = Plus(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); + + // Avoid "unused variable" warnings. + (void)a0; + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + (void)a6; + (void)a7; + (void)a8; + (void)a9; + (void)a10; } // Tests that an ACTION_P*() action can be explicitly instantiated diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 4b7e6e05..0a750de1 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -1039,6 +1039,19 @@ TEST(MatcherPnMacroTest, TypesAreCorrect) { EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, '9'); EqualsSumOfMatcherP10 a10 = EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); + + // Avoid "unused variable" warnings. + (void)a0; + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + (void)a6; + (void)a7; + (void)a8; + (void)a9; + (void)a10; } // Tests that matcher-typed parameters can be used in Value() inside a -- cgit v1.2.3 From 20d1a235bcfba95d1f436c9335bd46e9d62b64a2 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 06:58:38 +0000 Subject: Allows the return type of a mock method to contain unprotected commas. --- include/gmock/gmock-generated-function-mockers.h | 664 +++++++++++---------- .../gmock/gmock-generated-function-mockers.h.pump | 61 +- test/gmock-generated-function-mockers_test.cc | 50 +- 3 files changed, 446 insertions(+), 329 deletions(-) diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 509d46cb..577fd9e9 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -326,17 +326,23 @@ class FunctionMocker : public // cannot handle it if we define FunctionMocker in ::testing. using internal::FunctionMocker; -// The result type of function type F. +// 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, F) tn ::testing::internal::Function::Result +#define GMOCK_RESULT_(tn, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Result -// The type of argument N of function type F. +// The type of argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_ARG_(tn, F, N) tn ::testing::internal::Function::Argument##N +#define GMOCK_ARG_(tn, N, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Argument##N -// The matcher type for argument N of function type F. +// The matcher type for argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MATCHER_(tn, F, N) const ::testing::Matcher& +#define GMOCK_MATCHER_(tn, N, ...) \ + const ::testing::Matcher& // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! @@ -344,419 +350,475 @@ using internal::FunctionMocker; GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD0_(tn, constness, ct, Method, F) \ - GMOCK_RESULT_(tn, F) ct Method() constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 0, \ +#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + ) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::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& \ + ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method() constness { \ GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(0, constness, Method).With(); \ } \ - mutable ::testing::FunctionMocker GMOCK_MOCKER_(0, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 1, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1) constness { \ + ::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 GMOCK_MOCKER_(1, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 2, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2) constness { \ + ::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 GMOCK_MOCKER_(2, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 3, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3) constness { \ + ::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 GMOCK_MOCKER_(3, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 4, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4) constness { \ + ::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 GMOCK_MOCKER_(4, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4, \ - GMOCK_ARG_(tn, F, 5) gmock_a5) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 5, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER_(tn, F, 5) gmock_a5) constness { \ + ::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 GMOCK_MOCKER_(5, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4, \ - GMOCK_ARG_(tn, F, 5) gmock_a5, \ - GMOCK_ARG_(tn, F, 6) gmock_a6) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 6, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER_(tn, F, 6) gmock_a6) constness { \ + ::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 GMOCK_MOCKER_(6, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4, \ - GMOCK_ARG_(tn, F, 5) gmock_a5, \ - GMOCK_ARG_(tn, F, 6) gmock_a6, \ - GMOCK_ARG_(tn, F, 7) gmock_a7) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 7, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER_(tn, F, 7) gmock_a7) constness { \ + ::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 GMOCK_MOCKER_(7, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4, \ - GMOCK_ARG_(tn, F, 5) gmock_a5, \ - GMOCK_ARG_(tn, F, 6) gmock_a6, \ - GMOCK_ARG_(tn, F, 7) gmock_a7, \ - GMOCK_ARG_(tn, F, 8) gmock_a8) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 8, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ - GMOCK_MATCHER_(tn, F, 8) gmock_a8) constness { \ + ::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 GMOCK_MOCKER_(8, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4, \ - GMOCK_ARG_(tn, F, 5) gmock_a5, \ - GMOCK_ARG_(tn, F, 6) gmock_a6, \ - GMOCK_ARG_(tn, F, 7) gmock_a7, \ - GMOCK_ARG_(tn, F, 8) gmock_a8, \ - GMOCK_ARG_(tn, F, 9) gmock_a9) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 9, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ - GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ - GMOCK_MATCHER_(tn, F, 9) gmock_a9) constness { \ + ::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 GMOCK_MOCKER_(9, constness, Method) + 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, F) \ - GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \ - GMOCK_ARG_(tn, F, 2) gmock_a2, \ - GMOCK_ARG_(tn, F, 3) gmock_a3, \ - GMOCK_ARG_(tn, F, 4) gmock_a4, \ - GMOCK_ARG_(tn, F, 5) gmock_a5, \ - GMOCK_ARG_(tn, F, 6) gmock_a6, \ - GMOCK_ARG_(tn, F, 7) gmock_a7, \ - GMOCK_ARG_(tn, F, 8) gmock_a8, \ - GMOCK_ARG_(tn, F, 9) gmock_a9, \ - GMOCK_ARG_(tn, F, 10) gmock_a10) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == 10, \ +#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_((::std::tr1::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& \ - gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \ - GMOCK_MATCHER_(tn, F, 2) gmock_a2, \ - GMOCK_MATCHER_(tn, F, 3) gmock_a3, \ - GMOCK_MATCHER_(tn, F, 4) gmock_a4, \ - GMOCK_MATCHER_(tn, F, 5) gmock_a5, \ - GMOCK_MATCHER_(tn, F, 6) gmock_a6, \ - GMOCK_MATCHER_(tn, F, 7) gmock_a7, \ - GMOCK_MATCHER_(tn, F, 8) gmock_a8, \ - GMOCK_MATCHER_(tn, F, 9) gmock_a9, \ - GMOCK_MATCHER_(tn, F, 10) gmock_a10) constness { \ + ::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 GMOCK_MOCKER_(10, constness, Method) - -#define MOCK_METHOD0(m, F) GMOCK_METHOD0_(, , , m, F) -#define MOCK_METHOD1(m, F) GMOCK_METHOD1_(, , , m, F) -#define MOCK_METHOD2(m, F) GMOCK_METHOD2_(, , , m, F) -#define MOCK_METHOD3(m, F) GMOCK_METHOD3_(, , , m, F) -#define MOCK_METHOD4(m, F) GMOCK_METHOD4_(, , , m, F) -#define MOCK_METHOD5(m, F) GMOCK_METHOD5_(, , , m, F) -#define MOCK_METHOD6(m, F) GMOCK_METHOD6_(, , , m, F) -#define MOCK_METHOD7(m, F) GMOCK_METHOD7_(, , , m, F) -#define MOCK_METHOD8(m, F) GMOCK_METHOD8_(, , , m, F) -#define MOCK_METHOD9(m, F) GMOCK_METHOD9_(, , , m, F) -#define MOCK_METHOD10(m, F) GMOCK_METHOD10_(, , , m, F) - -#define MOCK_CONST_METHOD0(m, F) GMOCK_METHOD0_(, const, , m, F) -#define MOCK_CONST_METHOD1(m, F) GMOCK_METHOD1_(, const, , m, F) -#define MOCK_CONST_METHOD2(m, F) GMOCK_METHOD2_(, const, , m, F) -#define MOCK_CONST_METHOD3(m, F) GMOCK_METHOD3_(, const, , m, F) -#define MOCK_CONST_METHOD4(m, F) GMOCK_METHOD4_(, const, , m, F) -#define MOCK_CONST_METHOD5(m, F) GMOCK_METHOD5_(, const, , m, F) -#define MOCK_CONST_METHOD6(m, F) GMOCK_METHOD6_(, const, , m, F) -#define MOCK_CONST_METHOD7(m, F) GMOCK_METHOD7_(, const, , m, F) -#define MOCK_CONST_METHOD8(m, F) GMOCK_METHOD8_(, const, , m, F) -#define MOCK_CONST_METHOD9(m, F) GMOCK_METHOD9_(, const, , m, F) -#define MOCK_CONST_METHOD10(m, F) GMOCK_METHOD10_(, const, , m, F) - -#define MOCK_METHOD0_T(m, F) GMOCK_METHOD0_(typename, , , m, F) -#define MOCK_METHOD1_T(m, F) GMOCK_METHOD1_(typename, , , m, F) -#define MOCK_METHOD2_T(m, F) GMOCK_METHOD2_(typename, , , m, F) -#define MOCK_METHOD3_T(m, F) GMOCK_METHOD3_(typename, , , m, F) -#define MOCK_METHOD4_T(m, F) GMOCK_METHOD4_(typename, , , m, F) -#define MOCK_METHOD5_T(m, F) GMOCK_METHOD5_(typename, , , m, F) -#define MOCK_METHOD6_T(m, F) GMOCK_METHOD6_(typename, , , m, F) -#define MOCK_METHOD7_T(m, F) GMOCK_METHOD7_(typename, , , m, F) -#define MOCK_METHOD8_T(m, F) GMOCK_METHOD8_(typename, , , m, F) -#define MOCK_METHOD9_T(m, F) GMOCK_METHOD9_(typename, , , m, F) -#define MOCK_METHOD10_T(m, F) GMOCK_METHOD10_(typename, , , m, F) - -#define MOCK_CONST_METHOD0_T(m, F) GMOCK_METHOD0_(typename, const, , m, F) -#define MOCK_CONST_METHOD1_T(m, F) GMOCK_METHOD1_(typename, const, , m, F) -#define MOCK_CONST_METHOD2_T(m, F) GMOCK_METHOD2_(typename, const, , m, F) -#define MOCK_CONST_METHOD3_T(m, F) GMOCK_METHOD3_(typename, const, , m, F) -#define MOCK_CONST_METHOD4_T(m, F) GMOCK_METHOD4_(typename, const, , m, F) -#define MOCK_CONST_METHOD5_T(m, F) GMOCK_METHOD5_(typename, const, , m, F) -#define MOCK_CONST_METHOD6_T(m, F) GMOCK_METHOD6_(typename, const, , m, F) -#define MOCK_CONST_METHOD7_T(m, F) GMOCK_METHOD7_(typename, const, , m, F) -#define MOCK_CONST_METHOD8_T(m, F) GMOCK_METHOD8_(typename, const, , m, F) -#define MOCK_CONST_METHOD9_T(m, F) GMOCK_METHOD9_(typename, const, , m, F) -#define MOCK_CONST_METHOD10_T(m, F) GMOCK_METHOD10_(typename, const, , m, F) - -#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD0_(, , ct, m, F) -#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD1_(, , ct, m, F) -#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD2_(, , ct, m, F) -#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD3_(, , ct, m, F) -#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD4_(, , ct, m, F) -#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD5_(, , ct, m, F) -#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD6_(, , ct, m, F) -#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD7_(, , ct, m, F) -#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD8_(, , ct, m, F) -#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD9_(, , ct, m, F) -#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, F) GMOCK_METHOD10_(, , ct, m, F) - -#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD0_(, const, ct, m, F) -#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD1_(, const, ct, m, F) -#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD2_(, const, ct, m, F) -#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD3_(, const, ct, m, F) -#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD4_(, const, ct, m, F) -#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD5_(, const, ct, m, F) -#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD6_(, const, ct, m, F) -#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD7_(, const, ct, m, F) -#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD8_(, const, ct, m, F) -#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD9_(, const, ct, m, F) -#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD10_(, const, ct, m, F) - -#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD0_(typename, , ct, m, F) -#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD1_(typename, , ct, m, F) -#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD2_(typename, , ct, m, F) -#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD3_(typename, , ct, m, F) -#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD4_(typename, , ct, m, F) -#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD5_(typename, , ct, m, F) -#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD6_(typename, , ct, m, F) -#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD7_(typename, , ct, m, F) -#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD8_(typename, , ct, m, F) -#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD9_(typename, , ct, m, F) -#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD10_(typename, , ct, m, F) - -#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD0_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD1_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD2_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD3_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD4_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD5_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD6_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD7_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD8_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD9_(typename, const, ct, m, F) -#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, F) \ - GMOCK_METHOD10_(typename, const, ct, m, F) + 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 diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 4f82d622..f050caf1 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -104,17 +104,23 @@ $if i >= 1 [[ // cannot handle it if we define FunctionMocker in ::testing. using internal::FunctionMocker; -// The result type of function type F. +// 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, F) tn ::testing::internal::Function::Result +#define GMOCK_RESULT_(tn, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Result -// The type of argument N of function type F. +// The type of argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_ARG_(tn, F, N) tn ::testing::internal::Function::Argument##N +#define GMOCK_ARG_(tn, N, ...) \ + tn ::testing::internal::Function<__VA_ARGS__>::Argument##N -// The matcher type for argument N of function type F. +// The matcher type for argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MATCHER_(tn, F, N) const ::testing::Matcher& +#define GMOCK_MATCHER_(tn, N, ...) \ + const ::testing::Matcher& // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! @@ -125,77 +131,78 @@ using internal::FunctionMocker; $for i [[ $range j 1..i $var arg_as = [[$for j, \ - [[GMOCK_ARG_(tn, F, $j) gmock_a$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, F, $j) gmock_a$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, F) \ - GMOCK_RESULT_(tn, F) ct Method($arg_as) constness { \ - GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \ - tn ::testing::internal::Function::ArgumentTuple>::value == $i, \ +#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, ...) \ + GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ + $arg_as) constness { \ + GTEST_COMPILE_ASSERT_((::std::tr1::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& \ + ::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 GMOCK_MOCKER_($i, constness, Method) + mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_($i, constness, Method) ]] $for i [[ -#define MOCK_METHOD$i(m, F) GMOCK_METHOD$i[[]]_(, , , m, F) +#define MOCK_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, , , m, __VA_ARGS__) ]] $for i [[ -#define MOCK_CONST_METHOD$i(m, F) GMOCK_METHOD$i[[]]_(, const, , m, F) +#define MOCK_CONST_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, const, , m, __VA_ARGS__) ]] $for i [[ -#define MOCK_METHOD$i[[]]_T(m, F) GMOCK_METHOD$i[[]]_(typename, , , m, F) +#define MOCK_METHOD$i[[]]_T(m, ...) GMOCK_METHOD$i[[]]_(typename, , , m, __VA_ARGS__) ]] $for i [[ -#define MOCK_CONST_METHOD$i[[]]_T(m, F) [[]] -GMOCK_METHOD$i[[]]_(typename, const, , m, F) +#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, F) [[]] -GMOCK_METHOD$i[[]]_(, , ct, m, F) +#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, F) \ - GMOCK_METHOD$i[[]]_(, const, ct, m, F) +#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, F) \ - GMOCK_METHOD$i[[]]_(typename, , ct, m, F) +#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, F) \ - GMOCK_METHOD$i[[]]_(typename, const, ct, m, F) +#define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_METHOD$i[[]]_(typename, const, ct, m, __VA_ARGS__) ]] diff --git a/test/gmock-generated-function-mockers_test.cc b/test/gmock-generated-function-mockers_test.cc index 2087f991..ea49b9c1 100644 --- a/test/gmock-generated-function-mockers_test.cc +++ b/test/gmock-generated-function-mockers_test.cc @@ -129,9 +129,16 @@ class MockFoo : public FooInterface { MOCK_METHOD1(TakesNonConstReference, bool(int&)); // NOLINT MOCK_METHOD1(TakesConstReference, string(const int&)); + #ifdef GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS MOCK_METHOD1(TakesConst, bool(const int)); // NOLINT -#endif // GMOCK_ALLOWS_CONST_PARAM_FUNCTIONS +#endif + + // Tests that the function return type can contain unprotected comma. + MOCK_METHOD0(ReturnTypeWithComma, std::map()); + MOCK_CONST_METHOD1(ReturnTypeWithComma, + std::map(int)); // NOLINT + MOCK_METHOD0(OverloadedOnArgumentNumber, int()); // NOLINT MOCK_METHOD1(OverloadedOnArgumentNumber, int(int)); // NOLINT @@ -143,6 +150,7 @@ class MockFoo : public FooInterface { MOCK_METHOD1(TypeWithHole, int(int (*)())); // NOLINT MOCK_METHOD1(TypeWithComma, int(const std::map&)); // NOLINT + #if GTEST_OS_WINDOWS MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, CTNullary, int()); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, CTUnary, bool(int)); @@ -150,6 +158,10 @@ class MockFoo : public FooInterface { short d, int e, long f, float g, double h, unsigned i, char* j, const string& k)); MOCK_CONST_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, CTConst, char(int)); + + // Tests that the function return type can contain unprotected comma. + MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, CTReturnTypeWithComma, + std::map()); #endif // GTEST_OS_WINDOWS private: @@ -267,6 +279,17 @@ TEST_F(FunctionMockerTest, MocksFunctionsOverloadedOnConstnessOfThis) { EXPECT_EQ('a', Const(*foo_).OverloadedOnConstness()); } +TEST_F(FunctionMockerTest, MocksReturnTypeWithComma) { + const std::map a_map; + EXPECT_CALL(mock_foo_, ReturnTypeWithComma()) + .WillOnce(Return(a_map)); + EXPECT_CALL(mock_foo_, ReturnTypeWithComma(42)) + .WillOnce(Return(a_map)); + + EXPECT_EQ(a_map, mock_foo_.ReturnTypeWithComma()); + EXPECT_EQ(a_map, mock_foo_.ReturnTypeWithComma(42)); +} + #if GTEST_OS_WINDOWS // Tests mocking a nullary function with calltype. TEST_F(FunctionMockerTest, MocksNullaryFunctionWithCallType) { @@ -306,6 +329,14 @@ TEST_F(FunctionMockerTest, MocksFunctionsConstFunctionWithCallType) { EXPECT_EQ('a', Const(*foo_).CTConst(0)); } +TEST_F(FunctionMockerTest, MocksReturnTypeWithCommaAndCallType) { + const std::map a_map; + EXPECT_CALL(mock_foo_, CTReturnTypeWithComma()) + .WillOnce(Return(a_map)); + + EXPECT_EQ(a_map, mock_foo_.CTReturnTypeWithComma()); +} + #endif // GTEST_OS_WINDOWS class MockB { @@ -362,6 +393,10 @@ class MockStack : public StackInterface { MOCK_CONST_METHOD0_T(GetSize, int()); // NOLINT MOCK_CONST_METHOD0_T(GetTop, const T&()); + // Tests that the function return type can contain unprotected comma. + MOCK_METHOD0_T(ReturnTypeWithComma, std::map()); + MOCK_CONST_METHOD1_T(ReturnTypeWithComma, std::map(int)); // NOLINT + private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockStack); }; @@ -389,6 +424,19 @@ TEST(TemplateMockTest, Works) { EXPECT_EQ(0, mock.GetSize()); } +TEST(TemplateMockTest, MethodWithCommaInReturnTypeWorks) { + MockStack mock; + + const std::map a_map; + EXPECT_CALL(mock, ReturnTypeWithComma()) + .WillOnce(Return(a_map)); + EXPECT_CALL(mock, ReturnTypeWithComma(1)) + .WillOnce(Return(a_map)); + + EXPECT_EQ(a_map, mock.ReturnTypeWithComma()); + EXPECT_EQ(a_map, mock.ReturnTypeWithComma(1)); +} + #if GTEST_OS_WINDOWS // Tests mocking template interfaces with calltype. -- cgit v1.2.3 From c896504e4175f08cd229ea151861558ba9380f50 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 07:10:07 +0000 Subject: Improves the tests for nice, naggy, and strict mocks. --- include/gmock/gmock-spec-builders.h | 3 ++- src/gmock-spec-builders.cc | 2 +- test/gmock-nice-strict_test.cc | 54 ++++++++++++++++++++++++++++++++++--- test/gmock-spec-builders_test.cc | 40 ++++++++++++++------------- test/gmock_output_test_.cc | 3 ++- 5 files changed, 77 insertions(+), 25 deletions(-) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 4c2dca98..312fbe87 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -361,7 +361,8 @@ class OnCallSpec : public UntypedOnCallSpecBase { enum CallReaction { kAllow, kWarn, - kFail + kFail, + kDefault = kWarn // By default, warn about uninteresting calls. }; } // namespace internal diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 9fcb61ea..abaae3ad 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -639,7 +639,7 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls( GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { internal::MutexLock l(&internal::g_gmock_mutex); return (g_uninteresting_call_reaction.count(mock_obj) == 0) ? - internal::kWarn : g_uninteresting_call_reaction[mock_obj]; + internal::kDefault : g_uninteresting_call_reaction[mock_obj]; } // Tells Google Mock to ignore mock_obj when checking for leaked mock diff --git a/test/gmock-nice-strict_test.cc b/test/gmock-nice-strict_test.cc index 9b83d88e..d0adcbbe 100644 --- a/test/gmock-nice-strict_test.cc +++ b/test/gmock-nice-strict_test.cc @@ -110,6 +110,56 @@ class MockBar { #if GTEST_HAS_STREAM_REDIRECTION +// Tests that a raw mock generates warnings for uninteresting calls. +TEST(RawMockTest, WarningForUninterestingCall) { + const string saved_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = "warning"; + + MockFoo raw_foo; + + CaptureStdout(); + raw_foo.DoThis(); + raw_foo.DoThat(true); + EXPECT_THAT(GetCapturedStdout(), + HasSubstr("Uninteresting mock function call")); + + GMOCK_FLAG(verbose) = saved_flag; +} + +// Tests that a raw mock generates warnings for uninteresting calls +// that delete the mock object. +TEST(RawMockTest, WarningForUninterestingCallAfterDeath) { + const string saved_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = "warning"; + + MockFoo* const raw_foo = new MockFoo; + + ON_CALL(*raw_foo, DoThis()) + .WillByDefault(Invoke(raw_foo, &MockFoo::Delete)); + + CaptureStdout(); + raw_foo->DoThis(); + EXPECT_THAT(GetCapturedStdout(), + HasSubstr("Uninteresting mock function call")); + + GMOCK_FLAG(verbose) = saved_flag; +} + +// Tests that a raw mock generates informational logs for +// uninteresting calls. +TEST(RawMockTest, InfoForUninterestingCall) { + MockFoo raw_foo; + + const string saved_flag = GMOCK_FLAG(verbose); + GMOCK_FLAG(verbose) = "info"; + CaptureStdout(); + raw_foo.DoThis(); + EXPECT_THAT(GetCapturedStdout(), + HasSubstr("Uninteresting mock function call")); + + GMOCK_FLAG(verbose) = saved_flag; +} + // Tests that a nice mock generates no warning for uninteresting calls. TEST(NiceMockTest, NoWarningForUninterestingCall) { NiceMock nice_foo; @@ -145,10 +195,6 @@ TEST(NiceMockTest, InfoForUninterestingCall) { EXPECT_THAT(GetCapturedStdout(), HasSubstr("Uninteresting mock function call")); - CaptureStdout(); - nice_foo.DoThat(true); - EXPECT_THAT(GetCapturedStdout(), - HasSubstr("Uninteresting mock function call")); GMOCK_FLAG(verbose) = saved_flag; } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 8a8632dc..4a333df7 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -85,6 +85,7 @@ using testing::IsSubstring; using testing::Lt; using testing::Message; using testing::Mock; +using testing::NaggyMock; using testing::Ne; using testing::Return; using testing::Sequence; @@ -899,11 +900,12 @@ TEST(FunctionMockerTest, ReportsExpectCallLocationForExhausedActions) { EXPECT_PRED_FORMAT2(IsSubstring, expect_call_location, output); } -TEST(FunctionMockerTest, ReportsDefaultActionLocationOfUninterestingCalls) { +TEST(FunctionMockerTest, + ReportsDefaultActionLocationOfUninterestingCallsForNaggyMock) { std::string on_call_location; CaptureStdout(); { - MockB b; + NaggyMock b; on_call_location = FormatFileLocation(__FILE__, __LINE__ + 1); ON_CALL(b, DoB(_)).WillByDefault(Return(0)); b.DoB(0); @@ -1966,10 +1968,11 @@ class VerboseFlagPreservingFixture : public testing::Test { #if GTEST_HAS_STREAM_REDIRECTION -// Tests that an uninteresting mock function call generates a warning -// containing the stack trace. -TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { - MockC c; +// Tests that an uninteresting mock function call on a naggy mock +// generates a warning containing the stack trace. +TEST(FunctionCallMessageTest, + UninterestingCallOnNaggyMockGeneratesFyiWithStackTrace) { + NaggyMock c; CaptureStdout(); c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); const std::string output = GetCapturedStdout(); @@ -1995,11 +1998,12 @@ TEST(FunctionCallMessageTest, UninterestingCallGeneratesFyiWithStackTrace) { # endif // NDEBUG } -// Tests that an uninteresting mock function call causes the function -// arguments and return value to be printed. -TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { +// Tests that an uninteresting mock function call on a naggy mock +// causes the function arguments and return value to be printed. +TEST(FunctionCallMessageTest, + UninterestingCallOnNaggyMockPrintsArgumentsAndReturnValue) { // A non-void mock function. - MockB b; + NaggyMock b; CaptureStdout(); b.DoB(); const std::string output1 = GetCapturedStdout(); @@ -2011,7 +2015,7 @@ TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) { // Makes sure the return value is printed. // A void mock function. - MockC c; + NaggyMock c; CaptureStdout(); c.VoidMethod(false, 5, "Hi", NULL, Printable(), Unprintable()); const std::string output2 = GetCapturedStdout(); @@ -2081,9 +2085,9 @@ class GMockVerboseFlagTest : public VerboseFlagPreservingFixture { "Binary"); } - // Tests how the flag affects uninteresting calls. - void TestUninterestingCall(bool should_print) { - MockA a; + // Tests how the flag affects uninteresting calls on a naggy mock. + void TestUninterestingCallOnNaggyMock(bool should_print) { + NaggyMock a; // A void-returning function. CaptureStdout(); @@ -2117,7 +2121,7 @@ class GMockVerboseFlagTest : public VerboseFlagPreservingFixture { TEST_F(GMockVerboseFlagTest, Info) { GMOCK_FLAG(verbose) = kInfoVerbosity; TestExpectedCall(true); - TestUninterestingCall(true); + TestUninterestingCallOnNaggyMock(true); } // Tests that --gmock_verbose=warning causes uninteresting calls to be @@ -2125,7 +2129,7 @@ TEST_F(GMockVerboseFlagTest, Info) { TEST_F(GMockVerboseFlagTest, Warning) { GMOCK_FLAG(verbose) = kWarningVerbosity; TestExpectedCall(false); - TestUninterestingCall(true); + TestUninterestingCallOnNaggyMock(true); } // Tests that --gmock_verbose=warning causes neither expected nor @@ -2133,7 +2137,7 @@ TEST_F(GMockVerboseFlagTest, Warning) { TEST_F(GMockVerboseFlagTest, Error) { GMOCK_FLAG(verbose) = kErrorVerbosity; TestExpectedCall(false); - TestUninterestingCall(false); + TestUninterestingCallOnNaggyMock(false); } // Tests that --gmock_verbose=SOME_INVALID_VALUE has the same effect @@ -2141,7 +2145,7 @@ TEST_F(GMockVerboseFlagTest, Error) { TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { GMOCK_FLAG(verbose) = "invalid"; // Treated as "warning". TestExpectedCall(false); - TestUninterestingCall(true); + TestUninterestingCallOnNaggyMock(true); } #endif // GTEST_HAS_STREAM_REDIRECTION diff --git a/test/gmock_output_test_.cc b/test/gmock_output_test_.cc index c8e6b831..44cba342 100644 --- a/test/gmock_output_test_.cc +++ b/test/gmock_output_test_.cc @@ -43,6 +43,7 @@ using testing::_; using testing::AnyNumber; using testing::Ge; using testing::InSequence; +using testing::NaggyMock; using testing::Ref; using testing::Return; using testing::Sequence; @@ -61,7 +62,7 @@ class MockFoo { class GMockOutputTest : public testing::Test { protected: - MockFoo foo_; + NaggyMock foo_; }; TEST_F(GMockOutputTest, ExpectedCall) { -- cgit v1.2.3 From a1a98f840e25692ddcb0ca872aaf8362a2b4e088 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 1 Mar 2013 21:28:40 +0000 Subject: Adds a cmake target for gmock_ex_test; also fixes name shadowing warnings. --- CMakeLists.txt | 1 + test/gmock-actions_test.cc | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ded9ca9d..572d0444 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ if (gmock_build_tests) 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) diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 68bdadee..8cd77e20 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -323,9 +323,9 @@ TEST(DefaultValueOfReferenceDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { // Tests that ActionInterface can be implemented by defining the // Perform method. -typedef int MyFunction(bool, int); +typedef int MyGlobalFunction(bool, int); -class MyActionImpl : public ActionInterface { +class MyActionImpl : public ActionInterface { public: virtual int Perform(const tuple& args) { return get<0>(args) ? get<1>(args) : 0; @@ -338,7 +338,7 @@ TEST(ActionInterfaceTest, CanBeImplementedByDefiningPerform) { } TEST(ActionInterfaceTest, MakeAction) { - Action action = MakeAction(new MyActionImpl); + Action action = MakeAction(new MyActionImpl); // When exercising the Perform() method of Action, we must pass // it a tuple whose size and type are compatible with F's argument @@ -351,12 +351,12 @@ TEST(ActionInterfaceTest, MakeAction) { // Tests that Action can be contructed from a pointer to // ActionInterface. TEST(ActionTest, CanBeConstructedFromActionInterface) { - Action action(new MyActionImpl); + Action action(new MyActionImpl); } // Tests that Action delegates actual work to ActionInterface. TEST(ActionTest, DelegatesWorkToActionInterface) { - const Action action(new MyActionImpl); + const Action action(new MyActionImpl); EXPECT_EQ(5, action.Perform(make_tuple(true, 5))); EXPECT_EQ(0, action.Perform(make_tuple(false, 1))); @@ -364,8 +364,8 @@ TEST(ActionTest, DelegatesWorkToActionInterface) { // Tests that Action can be copied. TEST(ActionTest, IsCopyable) { - Action a1(new MyActionImpl); - Action a2(a1); // Tests the copy constructor. + Action a1(new MyActionImpl); + Action a2(a1); // Tests the copy constructor. // a1 should continue to work after being copied from. EXPECT_EQ(5, a1.Perform(make_tuple(true, 5))); -- cgit v1.2.3 From 2eab17b76d350dac1b1c85879ec8e1135da615ce Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 8 Mar 2013 17:53:24 +0000 Subject: Removes an unnecessary semi-colon, which causes a warning in GCC's pedantic mode. --- include/gmock/gmock-matchers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index dc93468c..83311280 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -387,7 +387,7 @@ class PolymorphicMatcher { 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 -- cgit v1.2.3 From 1f122a06e6aad4d234123d2d8c1e352029ce0742 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 25 Mar 2013 16:27:03 +0000 Subject: Adds special support for matching StringPiece. Pulls in gtest r646. --- include/gmock/gmock-matchers.h | 45 ++++++++++++++++++++++++++++++++++++++++++ src/gmock-matchers.cc | 35 ++++++++++++++++++++++++++++++++ test/gmock-matchers_test.cc | 38 +++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 83311280..ceb73fdd 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -318,6 +318,51 @@ class GTEST_API_ Matcher 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()). diff --git a/src/gmock-matchers.cc b/src/gmock-matchers.cc index 63f3859b..5f746b95 100644 --- a/src/gmock-matchers.cc +++ b/src/gmock-matchers.cc @@ -63,6 +63,41 @@ Matcher::Matcher(const char* s) { *this = Eq(internal::string(s)); } +#if GTEST_HAS_STRING_PIECE_ +// Constructs a matcher that matches a const StringPiece& whose value is +// equal to s. +Matcher::Matcher(const internal::string& s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a const StringPiece& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(internal::string(s)); +} + +// Constructs a matcher that matches a const StringPiece& whose value is +// equal to s. +Matcher::Matcher(StringPiece s) { + *this = Eq(s.ToString()); +} + +// Constructs a matcher that matches a StringPiece whose value is equal to s. +Matcher::Matcher(const internal::string& s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a StringPiece whose value is equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(internal::string(s)); +} + +// Constructs a matcher that matches a StringPiece whose value is equal to s. +Matcher::Matcher(StringPiece s) { + *this = Eq(s.ToString()); +} +#endif // GTEST_HAS_STRING_PIECE_ + namespace internal { // Joins a vector of strings as if they are fields of a tuple; returns diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 81460925..3a834a18 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -364,6 +364,44 @@ TEST(StringMatcherTest, CanBeImplicitlyConstructedFromString) { EXPECT_FALSE(m2.Matches("hello")); } +#if GTEST_HAS_STRING_PIECE_ +// Tests that a C-string literal can be implicitly converted to a +// Matcher or Matcher. +TEST(StringPieceMatcherTest, CanBeImplicitlyConstructedFromCStringLiteral) { + Matcher m1 = "cats"; + EXPECT_TRUE(m1.Matches("cats")); + EXPECT_FALSE(m1.Matches("dogs")); + + Matcher m2 = "cats"; + EXPECT_TRUE(m2.Matches("cats")); + EXPECT_FALSE(m2.Matches("dogs")); +} + +// Tests that a string object can be implicitly converted to a +// Matcher or Matcher. +TEST(StringPieceMatcherTest, CanBeImplicitlyConstructedFromString) { + Matcher m1 = string("cats"); + EXPECT_TRUE(m1.Matches("cats")); + EXPECT_FALSE(m1.Matches("dogs")); + + Matcher m2 = string("cats"); + EXPECT_TRUE(m2.Matches("cats")); + EXPECT_FALSE(m2.Matches("dogs")); +} + +// Tests that a StringPiece object can be implicitly converted to a +// Matcher or Matcher. +TEST(StringPieceMatcherTest, CanBeImplicitlyConstructedFromStringPiece) { + Matcher m1 = StringPiece("cats"); + EXPECT_TRUE(m1.Matches("cats")); + EXPECT_FALSE(m1.Matches("dogs")); + + Matcher m2 = StringPiece("cats"); + EXPECT_TRUE(m2.Matches("cats")); + EXPECT_FALSE(m2.Matches("dogs")); +} +#endif // GTEST_HAS_STRING_PIECE_ + // Tests that MakeMatcher() constructs a Matcher from a // MatcherInterface* without requiring the user to explicitly // write the type. -- cgit v1.2.3 From a9a59e06dd7cdfe52c988bf065bc156a7ed96a5c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 27 Mar 2013 16:14:55 +0000 Subject: Makes WhenSorted() support associative containers (by billydonahue@google.com). --- include/gmock/gmock-matchers.h | 5 +- include/gmock/internal/gmock-internal-utils.h | 14 +++ test/gmock-matchers_test.cc | 161 ++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index ceb73fdd..962cfde9 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2189,7 +2189,10 @@ class WhenSortedByMatcher { GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView; typedef typename LhsView::type LhsStlContainer; typedef typename LhsView::const_reference LhsStlContainerReference; - typedef typename LhsStlContainer::value_type LhsValue; + // Transforms std::pair into std::pair + // so that we can match associative containers. + typedef typename RemoveConstFromKey< + typename LhsStlContainer::value_type>::type LhsValue; Impl(const Comparator& comparator, const ContainerMatcher& matcher) : comparator_(comparator), matcher_(matcher) {} diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index f9b6b809..e12b7d7d 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -473,6 +473,20 @@ class StlContainerView< ::std::tr1::tuple > { // StlContainer with a reference type. template class StlContainerView; +// A type transform to remove constness from the first part of a pair. +// Pairs like that are used as the value_type of associative containers, +// and this transform produces a similar but assignable pair. +template +struct RemoveConstFromKey { + typedef T type; +}; + +// Partially specialized to remove constness from std::pair. +template +struct RemoveConstFromKey > { + typedef std::pair type; +}; + // Mapping from booleans to types. Similar to boost::bool_ and // std::integral_constant. template diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 3a834a18..66459464 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -37,8 +37,10 @@ #include "gmock/gmock-more-matchers.h" #include +#include #include #include +#include #include #include #include @@ -4012,6 +4014,165 @@ TEST(WhenSortedTest, WorksForNonEmptyContainer) { EXPECT_THAT(words, Not(WhenSorted(ElementsAre("3", "1", "2", "2")))); } +TEST(WhenSortedTest, WorksForMapTypes) { + map word_counts; + word_counts["and"] = 1; + word_counts["the"] = 1; + word_counts["buffalo"] = 2; + EXPECT_THAT(word_counts, WhenSorted(ElementsAre( + Pair("and", 1), Pair("buffalo", 2), Pair("the", 1)))); + EXPECT_THAT(word_counts, Not(WhenSorted(ElementsAre( + Pair("and", 1), Pair("the", 1), Pair("buffalo", 2))))); +} + +TEST(WhenSortedTest, WorksForMultiMapTypes) { + multimap ifib; + ifib.insert(make_pair(8, 6)); + ifib.insert(make_pair(2, 3)); + ifib.insert(make_pair(1, 1)); + ifib.insert(make_pair(3, 4)); + ifib.insert(make_pair(1, 2)); + ifib.insert(make_pair(5, 5)); + EXPECT_THAT(ifib, WhenSorted(ElementsAre(Pair(1, 1), + Pair(1, 2), + Pair(2, 3), + Pair(3, 4), + Pair(5, 5), + Pair(8, 6)))); + EXPECT_THAT(ifib, Not(WhenSorted(ElementsAre(Pair(8, 6), + Pair(2, 3), + Pair(1, 1), + Pair(3, 4), + Pair(1, 2), + Pair(5, 5))))); +} + +TEST(WhenSortedTest, WorksForPolymorphicMatcher) { + std::deque d; + d.push_back(2); + d.push_back(1); + EXPECT_THAT(d, WhenSorted(ElementsAre(1, 2))); + EXPECT_THAT(d, Not(WhenSorted(ElementsAre(2, 1)))); +} + +TEST(WhenSortedTest, WorksForVectorConstRefMatcher) { + std::deque d; + d.push_back(2); + d.push_back(1); + Matcher&> vector_match = ElementsAre(1, 2); + EXPECT_THAT(d, WhenSorted(vector_match)); + Matcher&> not_vector_match = ElementsAre(2, 1); + EXPECT_THAT(d, Not(WhenSorted(not_vector_match))); +} + +// Deliberately bare pseudo-container. +// Offers only begin() and end() accessors, yielding InputIterator. +template +class Streamlike { + private: + class ConstIter; + public: + typedef ConstIter const_iterator; + typedef T value_type; + + template + Streamlike(InIter first, InIter last) : remainder_(first, last) {} + + const_iterator begin() const { + return const_iterator(this, remainder_.begin()); + } + const_iterator end() const { + return const_iterator(this, remainder_.end()); + } + + private: + class ConstIter : public std::iterator { + public: + ConstIter(const Streamlike* s, + typename std::list::iterator pos) + : s_(s), pos_(pos) {} + + const value_type& operator*() const { return *pos_; } + const value_type* operator->() const { return &*pos_; } + ConstIter& operator++() { + s_->remainder_.erase(pos_++); + return *this; + } + + // *iter++ is required to work (see std::istreambuf_iterator). + // (void)iter++ is also required to work. + class PostIncrProxy { + public: + explicit PostIncrProxy(const value_type& value) : value_(value) {} + value_type operator*() const { return value_; } + private: + value_type value_; + }; + PostIncrProxy operator++(int) { + PostIncrProxy proxy(**this); + ++(*this); + return proxy; + } + + friend bool operator==(const ConstIter& a, const ConstIter& b) { + return a.s_ == b.s_ && a.pos_ == b.pos_; + } + friend bool operator!=(const ConstIter& a, const ConstIter& b) { + return !(a == b); + } + + private: + const Streamlike* s_; + typename std::list::iterator pos_; + }; + + friend std::ostream& operator<<(std::ostream& os, const Streamlike& s) { + os << "["; + typedef typename std::list::const_iterator Iter; + const char* sep = ""; + for (Iter it = s.remainder_.begin(); it != s.remainder_.end(); ++it) { + os << sep << *it; + sep = ","; + } + os << "]"; + return os; + } + + mutable std::list remainder_; // modified by iteration +}; + +TEST(StreamlikeTest, Iteration) { + const int a[5] = { 2, 1, 4, 5, 3 }; + Streamlike s(a, a + 5); + Streamlike::const_iterator it = s.begin(); + const int* ip = a; + while (it != s.end()) { + SCOPED_TRACE(ip - a); + EXPECT_EQ(*ip++, *it++); + } +} + +TEST(WhenSortedTest, WorksForStreamlike) { + // Streamlike 'container' provides only minimal iterator support. + // Its iterators are tagged with input_iterator_tag. + const int a[5] = { 2, 1, 4, 5, 3 }; + Streamlike s(a, a + 5); + EXPECT_THAT(s, WhenSorted(ElementsAre(1, 2, 3, 4, 5))); + EXPECT_THAT(s, Not(WhenSorted(ElementsAre(2, 1, 4, 5, 3)))); +} + +TEST(WhenSortedTest, WorksForVectorConstRefMatcherOnStreamlike) { + const int a[5] = { 2, 1, 4, 5, 3 }; + Streamlike s(a, a + 5); + Matcher&> vector_match = ElementsAre(1, 2, 3, 4, 5); + EXPECT_THAT(s, WhenSorted(vector_match)); + EXPECT_THAT(s, Not(WhenSorted(ElementsAre(2, 1, 4, 5, 3)))); +} + // Tests IsReadableTypeName(). TEST(IsReadableTypeNameTest, ReturnsTrueForShortNames) { -- cgit v1.2.3 From c10a35a26af06908f9b6e84848dbf96cac66eb61 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 4 Apr 2013 22:45:59 +0000 Subject: Fixes some compatibility issues with STLport. --- test/gmock-spec-builders_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 4a333df7..92e7d343 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -1523,14 +1523,14 @@ TEST(ExpectationSetTest, SizeWorks) { TEST(ExpectationSetTest, IsEnumerable) { ExpectationSet es; - EXPECT_THAT(es.begin(), Eq(es.end())); + EXPECT_TRUE(es.begin() == es.end()); es += Expectation(); ExpectationSet::const_iterator it = es.begin(); - EXPECT_THAT(it, Ne(es.end())); + EXPECT_TRUE(it != es.end()); EXPECT_THAT(*it, Eq(Expectation())); ++it; - EXPECT_THAT(it, Eq(es.end())); + EXPECT_TRUE(it== es.end()); } // Tests the .After() clause. -- cgit v1.2.3 From 061f1d4d167a0c118ae653516770e9d78bab320e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sun, 7 Apr 2013 03:16:38 +0000 Subject: Updates version number to 1.7.0 --- CHANGES | 4 ++++ configure.ac | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 90f88a59..4ccabf6d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +Changes for 1.7.0: + +TO BE WRITTEN. + Changes for 1.6.0: * Compilation is much faster and uses much less memory, especially diff --git a/configure.ac b/configure.ac index 05b90c4b..d268d5d7 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ m4_include(gtest/m4/acx_pthread.m4) AC_INIT([Google C++ Mocking Framework], - [1.6.0], + [1.7.0], [googlemock@googlegroups.com], [gmock]) @@ -101,7 +101,7 @@ AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" -GTEST_MIN_VERSION="1.6.0" +GTEST_MIN_VERSION="1.7.0" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. -- cgit v1.2.3 From f4274520da256a3e8dd4fe2aa2e714f44ad89d18 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Apr 2013 02:49:43 +0000 Subject: Makes EXPECT_THAT typesafe; updates CHANGES for 1.7.0; pulls in gtest r653 --- CHANGES | 22 +++++++++++++++++++++- include/gmock/gmock-matchers.h | 6 ++++-- test/gmock-matchers_test.cc | 9 +++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 4ccabf6d..d20b50b7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,26 @@ Changes for 1.7.0: -TO BE WRITTEN. +* All new improvements in Google Test 1.7.0. +* New feature: matchers WhenSorted(), WhenSortedBy(), IsEmpty(), and + SizeIs(). +* Improvement: Google Mock can now be built as a DLL. +* Improvement: when exceptions are enabled, a mock method with no + default action now throws instead crashing the test. +* 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. +* 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: diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 962cfde9..d4977273 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1613,10 +1613,12 @@ class PredicateFormatterFromMatcher { // know which type to instantiate it to until we actually see the // type of x here. // - // We write MatcherCast(matcher_) instead of + // We write SafeMatcherCast(matcher_) instead of // Matcher(matcher_), as the latter won't compile when // matcher_ has type Matcher (e.g. An()). - const Matcher matcher = MatcherCast(matcher_); + // We don't write MatcherCast either, as that allows + // potentially unsafe downcasting of the matcher argument. + const Matcher matcher = SafeMatcherCast(matcher_); StringMatchResultListener listener; if (MatchPrintAndExplain(x, matcher, &listener)) return AssertionSuccess(); diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 66459464..3ec2989e 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -721,6 +721,15 @@ TEST(ATest, MatchesAnyValue) { EXPECT_TRUE(m2.Matches(b)); } +TEST(ATest, WorksForDerivedClass) { + Base base; + Derived derived; + EXPECT_THAT(&base, A()); + // This shouldn't compile: EXPECT_THAT(&base, A()); + EXPECT_THAT(&derived, A()); + EXPECT_THAT(&derived, A()); +} + // Tests that A() describes itself properly. TEST(ATest, CanDescribeSelf) { EXPECT_EQ("is anything", Describe(A())); -- cgit v1.2.3 From 616180e6847dd3cc6517a59ff2d24e9fd5c8052c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 18 Jun 2013 18:49:51 +0000 Subject: New floating-point matchers: DoubleNear() and friends; AllOf() and AnyOf() can accept any number of arguments now in C++11 mode. --- CHANGES | 7 +- include/gmock/gmock-matchers.h | 210 ++++++++++++++++++++++++++--- test/gmock-generated-actions_test.cc | 2 +- test/gmock-matchers_test.cc | 254 +++++++++++++++++++++++++++++++++++ test/gmock-more-actions_test.cc | 2 +- 5 files changed, 455 insertions(+), 20 deletions(-) diff --git a/CHANGES b/CHANGES index d20b50b7..fc5c7954 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,12 @@ Changes for 1.7.0: * All new improvements in Google Test 1.7.0. -* New feature: matchers WhenSorted(), WhenSortedBy(), IsEmpty(), and - SizeIs(). +* New feature: matchers DoubleNear(), FloatNear(), + NanSensitiveDoubleNear(), NanSensitiveFloatNear(), 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 exceptions are enabled, a mock method with no default action now throws instead crashing the test. * Improvement: function return types used in MOCK_METHOD*() macros can diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index d4977273..0512ef44 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -38,6 +38,7 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#include #include #include #include // NOLINT @@ -1406,6 +1407,91 @@ class BothOfMatcherImpl : public MatcherInterface { 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 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 pair ListType; + + static ListType BuildList(const Matcher1& matcher1, + const Matcher2& matcher2) { + return 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