diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-22 18:32:21 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-22 18:32:21 +0000 |
commit | 22015c33fe44a1cc36596e0b6de37a48dc13b131 (patch) | |
tree | 643966e3ad01ab48b4f1d0ab48793261c68cee02 /testing | |
parent | ad764d54ec391e95e4ea239aa8eed548ce45cb61 (diff) | |
download | chromium_src-22015c33fe44a1cc36596e0b6de37a48dc13b131.zip chromium_src-22015c33fe44a1cc36596e0b6de37a48dc13b131.tar.gz chromium_src-22015c33fe44a1cc36596e0b6de37a48dc13b131.tar.bz2 |
Upgrade gtest to r267 and gmock to r173.
This is step1 into removing the boost + tr1 dependency in windows. It also includes a hack to avoid brining in tr1/functional on gcc, which will move us closer to enabling -fno-rtti.
This CL has passed the try servers. I've also tried compiling gmock, gmock_main, base, base_unittests, and webcore modules in vs2008 express editions.
Review URL: http://codereview.chromium.org/140003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18923 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'testing')
35 files changed, 2457 insertions, 1056 deletions
diff --git a/testing/README.chromium b/testing/README.chromium index 67e6451..ed305ee 100644 --- a/testing/README.chromium +++ b/testing/README.chromium @@ -1,7 +1,7 @@ We include a snapshot of gmock from http://googlemock.googlecode.com/svn/trunk with chromium.patch applied. -Current revision: 157 +Current revision: 173 -- HOW TO USE -- @@ -21,38 +21,19 @@ In particular, the "For Dummies" guide is a good place to start. The -- RECREATING PACKAGE -- -Gmock requires tr1 tuple. However, Visual Studio 2005 does not include -tr1 tuple, so a version of boost tuple was added into the third_party -tree for chromium. Our version of gmock has been patched to search for -this version of tuple inside our source tree. +Starting with r173, gmock began distributing a pared down version of tr1 tuple +that can be used on compilers without TR1. This means that we will no longer +need TR1 or boost on windows. -chromium.patch modifies gmock/include/gmock/internal/gmock-port.h so that -for _MSC_VER < 1500 (anything newer than Visual Studio 2008), boost tuple -is loaded from boost/tr1/tr1/tuple. +Recreating this package is now just exporting the wanted revision. +Example: -To recreate this install, do the following: + svn export --ignore-externals \ + http://googlemock.googlecode.com/svn/trunk/ gmock - *1) Checkout a copy from svn trunk using --ignore-externals to avoid - getting an extra copy of gtest. Use the following command: - svn export --ignore-externals \ - http://googlemock.googlecode.com/svn/trunk/ gmock - 2) Patch it with chromium.patch. +When checking out a copy from svn, --ignore-externals should be used to avoid +getting an extra copy of gtest. -* Pass -r [revision number] to svn export if you want a specific revision. -The current revision of the source is listed at the top of the README. - - --- ALTERNATIVES TO PATCHING -- - -The patching of gmock to use boost in VS2005 was settled upon as the lowest -impact solution for getting gmock working in VS2005. Patching gmock trades -making some assumptions regarding the internal implementations of gmock -and boost for a simple, easy to underatnd, implementation that provides -relatively good insulation for the rest of the build from the boost dependency. - -Alternate soltuions are: - 1) Drop support for VS2005 -- too heavy-handed. - 2) Add a "tuple" file parallel to gmock-port.h -- still makes assumptions - about boost's structure. - 3) Add boost/tr1/tr1 into the include path -- dirties the include path for - all dependencies. +This command will grab the head of trunk. Optionally, -r [revision number] to +can be passed to svn export if you want a specific revision. The current +revision of the source is listed at the top of the README. diff --git a/testing/chromium.patch b/testing/chromium.patch deleted file mode 100644 index 26b5662..0000000 --- a/testing/chromium.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -ru gmock.orig/include/gmock/internal/gmock-port.h gmock/include/gmock/internal/gmock-port.h ---- gmock.orig/include/gmock/internal/gmock-port.h 2009-05-22 23:58:41.000000000 -0700 -+++ gmock/include/gmock/internal/gmock-port.h 2009-05-23 00:49:01.000000000 -0700 -@@ -54,9 +54,14 @@ - // GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does - // not conform to the TR1 spec, which requires the header to be <tuple>. - #include <tr1/tuple> -+#elif defined(_MSC_VER) && _MSC_VER < 1500 -+// For Visual Studio older than 2008, we redirect directly to boost tuple -+// searching from boost's root. This is to avoid extra dirtying of the -+// compiler include paths. -+#include "boost/tr1/tr1/tuple" - #else --// If the compiler is not GCC 4.0+, we assume the user is using a --// spec-conforming TR1 implementation. -+// If the compiler is neither GCC 4.0+, nor Visual Studio 2008, we assume the -+// user is using a spec-conforming TR1 implementation. - #include <tuple> - #endif // __GNUC__ - diff --git a/testing/gmock.gyp b/testing/gmock.gyp index 4e56089..dd446f2 100644 --- a/testing/gmock.gyp +++ b/testing/gmock.gyp @@ -15,6 +15,7 @@ 'gtest.gyp:gtest', ], 'sources': [ + # Sources based on files in r173 of gmock. 'gmock/include/gmock/gmock-actions.h', 'gmock/include/gmock/gmock-cardinalities.h', 'gmock/include/gmock/gmock-generated-actions.h', diff --git a/testing/gmock/Makefile.am b/testing/gmock/Makefile.am index 7a821a0..196b927 100644 --- a/testing/gmock/Makefile.am +++ b/testing/gmock/Makefile.am @@ -135,6 +135,28 @@ 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 diff --git a/testing/gmock/README b/testing/gmock/README index f14279c..9cbda5d 100644 --- a/testing/gmock/README +++ b/testing/gmock/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 <type_info> 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/testing/gmock/configure.ac b/testing/gmock/configure.ac index c317979..78ff30d 100644 --- a/testing/gmock/configure.ac +++ b/testing/gmock/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/testing/gmock/include/gmock/gmock-generated-matchers.h b/testing/gmock/include/gmock/gmock-generated-matchers.h index afe1bd4..1a3e60b 100644 --- a/testing/gmock/include/gmock/gmock-generated-matchers.h +++ b/testing/gmock/include/gmock/gmock-generated-matchers.h @@ -45,12 +45,260 @@ 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<i, Tuple>::type + +// TupleFields<Tuple, k0, ..., kn> 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<tuple<bool, char, int>, 2, 0>, we have: +// +// type is tuple<int, bool>, and +// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). + +template <class Tuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1, + int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1, + int k9 = -1> +class TupleFields; + +// This generic version is used when there are 10 selectors. +template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6, + int k7, int k8, int k9> +class TupleFields { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4), + GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6), + GMOCK_FIELD_TYPE_(Tuple, k7), GMOCK_FIELD_TYPE_(Tuple, k8), + GMOCK_FIELD_TYPE_(Tuple, k9)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t), + get<k5>(t), get<k6>(t), get<k7>(t), get<k8>(t), get<k9>(t)); + } +}; + +// The following specialization is used for 0 ~ 9 selectors. + +template <class Tuple> +class TupleFields<Tuple, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(); + } +}; + +template <class Tuple, int k0> +class TupleFields<Tuple, k0, -1, -1, -1, -1, -1, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t)); + } +}; + +template <class Tuple, int k0, int k1> +class TupleFields<Tuple, k0, k1, -1, -1, -1, -1, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2> +class TupleFields<Tuple, k0, k1, k2, -1, -1, -1, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2, int k3> +class TupleFields<Tuple, k0, k1, k2, k3, -1, -1, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2, int k3, int k4> +class TupleFields<Tuple, k0, k1, k2, k3, k4, -1, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5> +class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, -1, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4), + GMOCK_FIELD_TYPE_(Tuple, k5)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t), + get<k5>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6> +class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, -1, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4), + GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t), + get<k5>(t), get<k6>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6, + int k7> +class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, k7, -1, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4), + GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6), + GMOCK_FIELD_TYPE_(Tuple, k7)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t), + get<k5>(t), get<k6>(t), get<k7>(t)); + } +}; + +template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6, + int k7, int k8> +class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, k7, k8, -1> { + public: + typedef ::std::tr1::tuple<GMOCK_FIELD_TYPE_(Tuple, k0), + GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2), + GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4), + GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6), + GMOCK_FIELD_TYPE_(Tuple, k7), GMOCK_FIELD_TYPE_(Tuple, k8)> type; + static type GetSelectedFields(const Tuple& t) { + using ::std::tr1::get; + return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t), + get<k5>(t), get<k6>(t), get<k7>(t), get<k8>(t)); + } +}; + +#undef GMOCK_FIELD_TYPE_ + +// Implements the Args() matcher. +template <class ArgsTuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1, + int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1, + int k9 = -1> +class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> { + public: + // ArgsTuple may have top-level const or reference modifiers. + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef typename internal::TupleFields<RawArgsTuple, k0, k1, k2, k3, k4, k5, + k6, k7, k8, k9>::type SelectedArgs; + typedef Matcher<const SelectedArgs&> MonomorphicInnerMatcher; + + template <typename InnerMatcher> + explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) + : inner_matcher_(SafeMatcherCast<const SelectedArgs&>(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<RawArgsTuple, k0, k1, k2, k3, k4, k5, k6, k7, k8, + k9>::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 InnerMatcher, int k0 = -1, int k1 = -1, int k2 = -1, + int k3 = -1, int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, + int k8 = -1, int k9 = -1> +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template <typename ArgsTuple> + operator Matcher<ArgsTuple>() const { + return MakeMatcher(new ArgsMatcherImpl<ArgsTuple, k0, k1, k2, k3, k4, k5, + k6, k7, k8, k9>(inner_matcher_)); + } + + const InnerMatcher inner_matcher_; +}; + // Implements ElementsAre() and ElementsAreArray(). template <typename Container> class ElementsAreMatcherImpl : public MatcherInterface<Container> { public: typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef internal::StlContainerView<RawContainer> 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 +313,13 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { // 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 +365,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { // 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 +387,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { } } 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 +402,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { // 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 +440,8 @@ class ElementsAreMatcher0 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&>* const matchers = NULL; return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0)); @@ -206,7 +457,8 @@ class ElementsAreMatcher1 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -228,7 +480,8 @@ class ElementsAreMatcher2 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -253,7 +506,8 @@ class ElementsAreMatcher3 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -280,7 +534,8 @@ class ElementsAreMatcher4 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -309,7 +564,8 @@ class ElementsAreMatcher5 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -342,7 +598,8 @@ class ElementsAreMatcher6 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -377,7 +634,8 @@ class ElementsAreMatcher7 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -414,7 +672,8 @@ class ElementsAreMatcher8 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -454,7 +713,8 @@ class ElementsAreMatcher9 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -496,7 +756,8 @@ class ElementsAreMatcher10 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { MatcherCast<const Element&>(e1_), @@ -538,7 +799,8 @@ class ElementsAreArrayMatcher { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_)); } @@ -550,6 +812,84 @@ class ElementsAreArrayMatcher { } // namespace internal +// Args<N1, N2, ..., Nk>(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 <typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher>(matcher); +} + +template <int k1, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1>(matcher); +} + +template <int k1, int k2, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2>(matcher); +} + +template <int k1, int k2, int k3, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3>(matcher); +} + +template <int k1, int k2, int k3, int k4, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4>(matcher); +} + +template <int k1, int k2, int k3, int k4, int k5, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5>(matcher); +} + +template <int k1, int k2, int k3, int k4, int k5, int k6, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6>(matcher); +} + +template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, + typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, + k7>(matcher); +} + +template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8, + typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, + k8>(matcher); +} + +template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8, + int k9, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, k9> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, + k9>(matcher); +} + +template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8, + int k9, int k10, typename InnerMatcher> +inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, k9, + k10> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, + k9, k10>(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 @@ -1573,45 +1913,4 @@ string FormatMatcherDescription( p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>::\ gmock_Impl<arg_type>::Matches(arg_type arg) const -namespace testing { -namespace internal { - -// Returns true iff element is in the STL-style container. -template <typename Container, typename Element> -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 <typename ArrayElement, size_t N, typename Element> -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<int> 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<int, size_t> page_lengths; -// page_lengths[1] = 100; -// EXPECT_THAT(map_int, Contains(::std::pair<const int, size_t>(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/testing/gmock/include/gmock/gmock-generated-matchers.h.pump b/testing/gmock/include/gmock/gmock-generated-matchers.h.pump index 09dfedf..653a2e8 100644 --- a/testing/gmock/include/gmock/gmock-generated-matchers.h.pump +++ b/testing/gmock/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,12 +49,139 @@ $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<i, Tuple>::type + +// TupleFields<Tuple, k0, ..., kn> 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<tuple<bool, char, int>, 2, 0>, we have: +// +// type is tuple<int, bool>, and +// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). + +template <class Tuple$for i [[, int k$i = -1]]> +class TupleFields; + +// This generic version is used when there are $n selectors. +template <class Tuple$for i [[, int k$i]]> +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<k$i>(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 Tuple$for j [[, int k$j]]> +class TupleFields<Tuple, $for k, [[$if k < i [[k$k]] $else [[-1]]]]> { + 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<k$j>(t)]]); + } +}; + +]] + +#undef GMOCK_FIELD_TYPE_ + +// Implements the Args() matcher. + +$var ks = [[$for i, [[k$i]]]] +template <class ArgsTuple$for i [[, int k$i = -1]]> +class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> { + public: + // ArgsTuple may have top-level const or reference modifiers. + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef typename internal::TupleFields<RawArgsTuple, $ks>::type SelectedArgs; + typedef Matcher<const SelectedArgs&> MonomorphicInnerMatcher; + + template <typename InnerMatcher> + explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) + : inner_matcher_(SafeMatcherCast<const SelectedArgs&>(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<RawArgsTuple, $ks>::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 InnerMatcher$for i [[, int k$i = -1]]> +class ArgsMatcher { + public: + explicit ArgsMatcher(const InnerMatcher& inner_matcher) + : inner_matcher_(inner_matcher) {} + + template <typename ArgsTuple> + operator Matcher<ArgsTuple>() const { + return MakeMatcher(new ArgsMatcherImpl<ArgsTuple, $ks>(inner_matcher_)); + } + + const InnerMatcher inner_matcher_; +}; + // Implements ElementsAre() and ElementsAreArray(). template <typename Container> class ElementsAreMatcherImpl : public MatcherInterface<Container> { public: typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef internal::StlContainerView<RawContainer> 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 +196,13 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { // 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 +248,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { // 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 +270,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { } } 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 +285,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { // 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 +323,8 @@ class ElementsAreMatcher0 { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&>* const matchers = NULL; return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0)); @@ -214,7 +345,8 @@ class ElementsAreMatcher$i { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; const Matcher<const Element&> matchers[] = { @@ -248,7 +380,8 @@ class ElementsAreArrayMatcher { operator Matcher<Container>() const { typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; - typedef typename RawContainer::value_type Element; + typedef typename internal::StlContainerView<RawContainer>::type::value_type + Element; return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_)); } @@ -260,6 +393,21 @@ class ElementsAreArrayMatcher { } // namespace internal +// Args<N1, N2, ..., Nk>(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<InnerMatcher$for j [[, k$j]]> +Args(const InnerMatcher& matcher) { + return internal::ArgsMatcher<InnerMatcher$for j [[, k$j]]>(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 @@ -274,6 +422,7 @@ inline internal::ElementsAreMatcher0 ElementsAre() { return internal::ElementsAreMatcher0(); } +$range i 1..n $for i [[ $range j 1..i @@ -590,45 +739,4 @@ $var param_field_decls2 = [[$for j ]] -namespace testing { -namespace internal { - -// Returns true iff element is in the STL-style container. -template <typename Container, typename Element> -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 <typename ArrayElement, size_t N, typename Element> -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<int> 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<int, size_t> page_lengths; -// page_lengths[1] = 100; -// EXPECT_THAT(map_int, Contains(::std::pair<const int, size_t>(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/testing/gmock/include/gmock/gmock-matchers.h b/testing/gmock/include/gmock/gmock-matchers.h index 0497be2..dc252e3 100644 --- a/testing/gmock/include/gmock/gmock-matchers.h +++ b/testing/gmock/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 <typename T1, typename T2> \ @@ -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_ @@ -1709,60 +1709,164 @@ void ExplainMatchResultTo(const ResultOfMatcher<Callable>& matcher, template <typename Container> class ContainerEqMatcher { public: - explicit ContainerEqMatcher(const Container& rhs) : rhs_(rhs) {} - bool Matches(const Container& lhs) const { return lhs == rhs_; } + typedef internal::StlContainerView<Container> 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<Container, + GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))>(); + } + + template <typename LhsContainer> + 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<GMOCK_REMOVE_CONST_(LhsContainer)> + LhsView; + StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + return lhs_stl_container == rhs_; + } void DescribeTo(::std::ostream* os) const { *os << "equals "; - UniversalPrinter<Container>::Print(rhs_, os); + UniversalPrinter<StlContainer>::Print(rhs_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "does not equal "; - UniversalPrinter<Container>::Print(rhs_, os); + UniversalPrinter<StlContainer>::Print(rhs_, os); } - void ExplainMatchResultTo(const Container& lhs, + template <typename LhsContainer> + 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<GMOCK_REMOVE_CONST_(LhsContainer)> + 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<typename Container::value_type>::Print(*it, os); + UniversalPrinter<typename LhsStlContainer::value_type>::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<typename Container::value_type>::Print(*it, os); + UniversalPrinter<typename StlContainer::value_type>::Print(*it, os); } } } private: - const Container rhs_; + const StlContainer rhs_; }; -template <typename Container> +template <typename LhsContainer, typename Container> void ExplainMatchResultTo(const ContainerEqMatcher<Container>& 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 <typename Container> +class ContainsMatcherImpl : public MatcherInterface<Container> { + public: + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; + typedef StlContainerView<RawContainer> View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + typedef typename StlContainer::value_type Element; + + template <typename InnerMatcher> + explicit ContainsMatcherImpl(InnerMatcher inner_matcher) + : inner_matcher_( + testing::SafeMatcherCast<const Element&>(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<const Element&> inner_matcher_; +}; + +// Implements polymorphic Contains(element_matcher). +template <typename M> +class ContainsMatcher { + public: + explicit ContainsMatcher(M m) : inner_matcher_(m) {} + + template <typename Container> + operator Matcher<Container>() const { + return MakeMatcher(new ContainsMatcherImpl<Container>(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 <typename Container> -inline PolymorphicMatcher<internal::ContainerEqMatcher<Container> > +inline PolymorphicMatcher<internal::ContainerEqMatcher< + GMOCK_REMOVE_CONST_(Container)> > ContainerEq(const Container& rhs) { - return MakePolymorphicMatcher(internal::ContainerEqMatcher<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<RawContainer>(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<int> 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<int, size_t> page_lengths; +// page_lengths[1] = 100; +// EXPECT_THAT(map_int, Contains(::std::pair<const int, size_t>(1, 100))); +// +// const char* user_ids[] = { "joe", "mike", "tom" }; +// EXPECT_THAT(user_ids, Contains(Eq(::std::string("tom")))); +template <typename M> +inline internal::ContainsMatcher<M> Contains(M matcher) { + return internal::ContainsMatcher<M>(matcher); } // Returns a predicate that is satisfied by anything that matches the @@ -2218,6 +2348,22 @@ inline internal::MatcherAsPredicate<M> Matches(M matcher) { return internal::MatcherAsPredicate<M>(matcher); } +// Returns true iff the value matches the matcher. +template <typename T, typename M> +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 <typename InnerMatcher> +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/testing/gmock/include/gmock/gmock-printers.h b/testing/gmock/include/gmock/gmock-printers.h index 9900243..561de3d 100644 --- a/testing/gmock/include/gmock/gmock-printers.h +++ b/testing/gmock/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<string> 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 <typename T> class UniversalPrinter; +template <typename T> +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 <typename C> @@ -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) { @@ -580,6 +603,41 @@ class UniversalPrinter { #endif // _MSC_VER }; +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template <typename T> +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 <typename T> +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 <typename T, size_t N> class UniversalPrinter<T[N]> { @@ -587,41 +645,13 @@ class UniversalPrinter<T[N]> { // 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<const T, const char>::value) { - UniversalPrinter<const T*>::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); } }; @@ -676,6 +706,15 @@ inline void UniversalTersePrint(char* str, ::std::ostream* os) { UniversalTersePrint(static_cast<const char*>(str), os); } +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template <typename T> +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter<T>::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/testing/gmock/include/gmock/gmock-spec-builders.h b/testing/gmock/include/gmock/gmock-spec-builders.h index cc48bc0..a22bcd1 100644 --- a/testing/gmock/include/gmock/gmock-spec-builders.h +++ b/testing/gmock/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) @@ -93,10 +93,6 @@ class ExpectationTester; template <typename F> class FunctionMockerBase; -// Helper class for implementing FunctionMockerBase<F>::InvokeWith(). -template <typename Result, typename F> -class InvokeWithHelper; - // Protects the mock object registry (in class Mock), all function // mockers, and all expectations. // @@ -148,20 +144,20 @@ class DefaultActionSpec { // bug in Symbian's C++ compiler (cannot decide between two // overloaded constructors of Matcher<const ArgumentTuple&>). extra_matcher_(A<const ArgumentTuple&>()), - 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<const ArgumentTuple&>& m) { + // Implements the .With() clause. + DefaultActionSpec& With(const Matcher<const ArgumentTuple&>& 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; @@ -169,10 +165,10 @@ class DefaultActionSpec { // Implements the .WillByDefault() clause. DefaultActionSpec& WillByDefault(const Action<F>& 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()."); @@ -187,7 +183,7 @@ class DefaultActionSpec { // Returns the action specified by the user. const Action<F>& GetAction() const { - AssertSpecProperty(last_clause_ == WILL_BY_DEFAULT, + AssertSpecProperty(last_clause_ == kWillByDefault, ".WillByDefault() must appear exactly " "once in an ON_CALL()."); return action_; @@ -197,9 +193,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. @@ -215,7 +211,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: @@ -232,7 +228,7 @@ class DefaultActionSpec { Action<F> 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 @@ -269,9 +265,6 @@ class Mock { template <typename F> friend class internal::FunctionMockerBase; - template <typename R, typename Args> - friend class internal::InvokeWithHelper; - template <typename M> friend class NiceMock; @@ -444,13 +437,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. @@ -588,7 +581,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() { @@ -597,18 +590,18 @@ class Expectation : public ExpectationBase { CheckActionCountIfNotDone(); } - // Implements the .WithArguments() clause. - Expectation& WithArguments(const Matcher<const ArgumentTuple&>& m) { - if (last_clause_ == WITH_ARGUMENTS) { + // Implements the .With() clause. + Expectation& With(const Matcher<const ArgumentTuple&>& 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; @@ -616,17 +609,17 @@ class Expectation : public ExpectationBase { // 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; @@ -639,11 +632,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; @@ -667,10 +660,10 @@ class Expectation : public ExpectationBase { // Implements the .WillOnce() clause. Expectation& WillOnce(const Action<F>& 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()) { @@ -681,16 +674,16 @@ class Expectation : public ExpectationBase { // Implements the .WillRepeatedly() clause. Expectation& WillRepeatedly(const Action<F>& 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; @@ -706,10 +699,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 @@ -724,7 +717,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<const ArgumentTuple&>& extra_matcher() const { return extra_matcher_; } @@ -763,9 +756,6 @@ class Expectation : public ExpectationBase { template <typename Function> friend class FunctionMockerBase; - template <typename R, typename Function> - 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. @@ -805,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<const ArgumentTuple&>( extra_matcher_, args, os); @@ -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<T> 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 <typename T> +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<T>::Print(value_, os); + } + + // Performs the given mock function's default action and returns the + // result in a ActionResultHolder. + template <typename Function, typename Arguments> + static ActionResultHolder PerformDefaultAction( + const FunctionMockerBase<Function>* 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 <typename Function, typename Arguments> + static ActionResultHolder PerformAction(const Action<Function>& action, + const Arguments& args) { + return ActionResultHolder(action.Perform(args)); + } + + private: + T value_; +}; + +// Specialization for T = void. +template <> +class ActionResultHolder<void> { + public: + ActionResultHolder() {} + void value() const {} + void PrintAsActionResult(::std::ostream* /* os */) const {} + + template <typename Function, typename Arguments> + static ActionResultHolder PerformDefaultAction( + const FunctionMockerBase<Function>* func_mocker, + const Arguments& args, + const string& call_description) { + func_mocker->PerformDefaultAction(args, call_description); + return ActionResultHolder(); + } + + template <typename Function, typename Arguments> + static ActionResultHolder PerformAction(const Action<Function>& 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 <typename Function> friend class MockSpec; - template <typename R, typename Function> - 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<Result, F>::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<F>::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<F>::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 <typename Result, typename F> -class InvokeWithHelper { - public: - typedef typename Function<F>::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<F>* 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<Result>::Print(result, &ss); - ReportUninterestingCall(reaction, ss.str()); - - return result; - } - - bool is_excessive = false; - ::std::stringstream ss; - ::std::stringstream why; - ::std::stringstream loc; - Action<F> action; - Expectation<F>* 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<ArgumentTuple>::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<Result>::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<F>::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 <typename F> -class InvokeWithHelper<void, F> { - public: - typedef typename Function<F>::ArgumentTuple ArgumentTuple; - - // Invokes the function mocked by mocker with the given arguments. - // L < g_gmock_mutex - static void InvokeAndPrintResult(FunctionMockerBase<F>* mocker, - const ArgumentTuple& args) { - const int count = static_cast<int>(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<F>::Result FunctionMockerBase<F>::InvokeWith( + const typename Function<F>::ArgumentTuple& args) { + typedef ActionResultHolder<Result> 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<F> action; - Expectation<F>* 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<ArgumentTuple>::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<void, F> + 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<F> action; + Expectation<F>* 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<ArgumentTuple>::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/testing/gmock/include/gmock/gmock.h b/testing/gmock/include/gmock/gmock.h index 22e7028..29d9727 100644 --- a/testing/gmock/include/gmock/gmock.h +++ b/testing/gmock/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/testing/gmock/include/gmock/internal/gmock-internal-utils.h b/testing/gmock/include/gmock/internal/gmock-internal-utils.h index b02682f..ee6aa1e 100644 --- a/testing/gmock/include/gmock/internal/gmock-internal-utils.h +++ b/testing/gmock/include/gmock/internal/gmock-internal-utils.h @@ -99,6 +99,17 @@ struct RemoveConst { typedef T type; }; // NOLINT template <typename T> struct RemoveConst<const T> { 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 <typename T, size_t N> +struct RemoveConst<T[N]> { + typedef typename RemoveConst<T>::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) \ @@ -438,6 +449,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 @@ -447,10 +462,6 @@ const char kErrorVerbosity[] = "error"; // 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. @@ -478,6 +489,238 @@ inline T Invalid() { template <> inline void Invalid<void>() {} +// 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 <typename T, typename U> +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template <typename T, typename U> +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template <typename T, typename U, size_t N> +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 <typename T, typename U> +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 <typename Iter, typename Element> +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 <typename T, typename U> +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template <typename T, typename U> +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template <typename T, typename U, size_t N> +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 <typename T, typename U> +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 <typename Element> +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 <size_t N> + 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 <typename Pointer, typename Size> + NativeArray(const ::std::tr1::tuple<Pointer, Size>& 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<Element, + GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Element))>(); + 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<RawContainer> 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 RawContainer> +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<RawContainer, + GMOCK_REMOVE_CONST_(RawContainer)>(); + return container; + } + static type Copy(const RawContainer& container) { return container; } +}; + +// This specialization is used when RawContainer is a native array type. +template <typename Element, size_t N> +class StlContainerView<Element[N]> { + public: + typedef GMOCK_REMOVE_CONST_(Element) RawElement; + typedef internal::NativeArray<RawElement> type; + // NativeArray<T> 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<Element, RawElement>(); + 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 <typename ElementPointer, typename Size> +class StlContainerView< ::std::tr1::tuple<ElementPointer, Size> > { + public: + typedef GMOCK_REMOVE_CONST_( + typename internal::PointeeOf<ElementPointer>::type) RawElement; + typedef internal::NativeArray<RawElement> type; + typedef const type const_reference; + + static const_reference ConstReference( + const ::std::tr1::tuple<ElementPointer, Size>& array) { + return type(array, kReference); + } + static type Copy(const ::std::tr1::tuple<ElementPointer, Size>& array) { + return type(array, kCopy); + } +}; + +// The following specialization prevents the user from instantiating +// StlContainer with a reference type. +template <typename T> class StlContainerView<T&>; + } // namespace internal } // namespace testing diff --git a/testing/gmock/include/gmock/internal/gmock-port.h b/testing/gmock/include/gmock/internal/gmock-port.h index 5aa0fd8..9ee8f72 100644 --- a/testing/gmock/include/gmock/internal/gmock-port.h +++ b/testing/gmock/include/gmock/internal/gmock-port.h @@ -47,23 +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 <tr1/tuple> header. This does -// not conform to the TR1 spec, which requires the header to be <tuple>. -#include <tr1/tuple> -#elif defined(_MSC_VER) && _MSC_VER < 1500 -// For Visual Studio older than 2008, we redirect directly to boost tuple -// searching from boost's root. This is to avoid extra dirtying of the -// compiler include paths. -#include "boost/tr1/tr1/tuple" -#else -// If the compiler is neither GCC 4.0+, nor Visual Studio 2008, we assume the -// user is using a spec-conforming TR1 implementation. -#include <tuple> -#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/testing/gmock/include/gmock/internal/gmock-port.h.orig b/testing/gmock/include/gmock/internal/gmock-port.h.orig deleted file mode 100644 index e4f4e23..0000000 --- a/testing/gmock/include/gmock/internal/gmock-port.h.orig +++ /dev/null @@ -1,326 +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. -// -// 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 <assert.h> -#include <stdlib.h> -#include <iostream> - -// Most of the types needed for porting Google Mock are also required -// for Google Test and are defined in gtest-port.h. -#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 -// 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 <tr1/tuple> header. This does -// not conform to the TR1 spec, which requires the header to be <tuple>. -#include <tr1/tuple> -#elif defined(_MSC_VER) && _MSC_VER < 1500 -// For Visual Studio older than 2008, we redirect directly to boost tuple -// searching from boost's root. This is to avoid extra dirtying of the -// compiler include paths. -#include "boost/tr1/tr1/tuple" -#else -// If the compiler is not GCC 4.0+, or Visual Studio 2008, we assume the -// user is using a spec-conforming TR1 implementation. -#include <tuple> -#endif // __GNUC__ - -#if GTEST_OS_LINUX - -// On some platforms, <regex.h> needs someone to define size_t, and -// won't compile otherwise. We can #include it here as we already -// included <stdlib.h>, which is guaranteed to define size_t through -// <stddef.h>. -#include <regex.h> // 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. -#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 - -// 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<ToType>(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<typename To, typename From> -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<Subclass1>(foo)) HandleASubclass1Object(foo); -// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo); -// You should design the code some other way not to need this. -template<typename To, typename From> // use like this: down_cast<T*>(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<From*, To>(0); - } - -#if GTEST_HAS_RTTI - assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only! -#endif - return static_cast<To>(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 <bool> -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<bool(expr)> -// -// 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 - -// 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; - 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 - -// 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) \ - 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/testing/gmock/msvc/gmock_config.vsprops b/testing/gmock/msvc/gmock_config.vsprops index fa596ef..a68c32e 100644 --- a/testing/gmock/msvc/gmock_config.vsprops +++ b/testing/gmock/msvc/gmock_config.vsprops @@ -6,15 +6,10 @@ >
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(BoostDir)/boost/tr1/tr1";"$(BoostDir)";"$(GTestDir)/include""
- PreprocessorDefinitions="GTEST_HAS_TR1_TUPLE=1"
+ AdditionalIncludeDirectories=""$(GTestDir)/include""
/>
<UserMacro
Name="GTestDir"
Value="../gtest"
/>
- <UserMacro
- Name="BoostDir"
- Value="../boost"
- />
</VisualStudioPropertySheet>
diff --git a/testing/gmock/scripts/generator/README b/testing/gmock/scripts/generator/README index 071bf0f..d6f9597 100644 --- a/testing/gmock/scripts/generator/README +++ b/testing/gmock/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/testing/gmock/scripts/generator/cpp/ast.py b/testing/gmock/scripts/generator/cpp/ast.py index 6d1c8d3..47dc9a0 100755 --- a/testing/gmock/scripts/generator/cpp/ast.py +++ b/testing/gmock/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/testing/gmock/scripts/generator/cpp/gmock_class.py b/testing/gmock/scripts/generator/cpp/gmock_class.py index 2920424..3ad0bcd 100755 --- a/testing/gmock/scripts/generator/cpp/gmock_class.py +++ b/testing/gmock/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/testing/gmock/scripts/generator/cpp/gmock_class_test.py b/testing/gmock/scripts/generator/cpp/gmock_class_test.py new file mode 100755 index 0000000..ae00800 --- /dev/null +++ b/testing/gmock/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.join(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 = [] + # <test> is a pseudo-filename, it is not read or written. + builder = ast.BuilderFromSource(cpp_source, '<test>') + 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.""" + # <test> is a pseudo-filename, it is not read or written. + filename = '<test>' + 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() diff --git a/testing/gmock/scripts/gmock-config.in b/testing/gmock/scripts/gmock-config.in index 016ad61..9ce17a2 100755 --- a/testing/gmock/scripts/gmock-config.in +++ b/testing/gmock/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. diff --git a/testing/gmock/scripts/gmock_doctor.py b/testing/gmock/scripts/gmock_doctor.py index 907089e..05e4258 100755 --- a/testing/gmock/scripts/gmock_doctor.py +++ b/testing/gmock/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.3' _COMMON_GMOCK_SYMBOLS = [ # Matchers @@ -46,8 +46,12 @@ _COMMON_GMOCK_SYMBOLS = [ 'AllOf', 'An', 'AnyOf', + 'ContainerEq', + 'Contains', 'ContainsRegex', 'DoubleEq', + 'ElementsAre', + 'ElementsAreArray', 'EndsWith', 'Eq', 'Field', @@ -59,7 +63,10 @@ _COMMON_GMOCK_SYMBOLS = [ 'Le', 'Lt', 'MatcherCast', + 'Matches', 'MatchesRegex', + 'NanSensitiveDoubleEq', + 'NanSensitiveFloatEq', 'Ne', 'Not', 'NotNull', @@ -67,6 +74,8 @@ _COMMON_GMOCK_SYMBOLS = [ 'PointeeIsInitializedProto', 'Property', 'Ref', + 'ResultOf', + 'SafeMatcherCast', 'StartsWith', 'StrCaseEq', 'StrCaseNe', @@ -74,9 +83,12 @@ _COMMON_GMOCK_SYMBOLS = [ 'StrNe', 'Truly', 'TypedEq', + 'Value', # Actions + 'Assign', 'ByRef', + 'DeleteArg', 'DoAll', 'DoDefault', 'IgnoreResult', @@ -84,11 +96,18 @@ _COMMON_GMOCK_SYMBOLS = [ 'InvokeArgument', 'InvokeWithoutArgs', 'Return', + 'ReturnNew', 'ReturnNull', 'ReturnRef', + 'SaveArg', + 'SetArgReferee', 'SetArgumentPointee', 'SetArrayArgument', + 'SetErrnoAndReturn', + 'Throw', + 'WithArg', 'WithArgs', + 'WithoutArgs', # Cardinalities 'AnyNumber', @@ -106,6 +125,9 @@ _COMMON_GMOCK_SYMBOLS = [ 'Mock', ] +# Regex for matching source file path and line number in gcc's errors. +_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):\s+' + def _FindAllMatches(regex, s): """Generates all matches of regex in string s.""" @@ -128,6 +150,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 +159,9 @@ def _NeedToReturnReferenceDiagnoser(msg): """Diagnoses the NRR disease, given the error messages by gcc.""" regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n' - r'(?P<file>.*):(?P<line>\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 +171,11 @@ Please use ReturnRef() instead.""" def _NeedToReturnSomethingDiagnoser(msg): """Diagnoses the NRS disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\d+):\s+' + 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 = """%(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 +186,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<file>.*):(?P<line>\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 +202,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<file>.*):(?P<line>\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<type>.*)\'') - 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 +217,9 @@ by pointer.""" def _OverloadedFunctionMatcherDiagnoser(msg): """Diagnoses the OFM disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for ' + regex = (_FILE_LINE_RE + r'error: no matching function for ' r'call to \'Truly\(<unresolved overloaded function type>\)') - 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 +234,9 @@ you should write def _OverloadedFunctionActionDiagnoser(msg): """Diagnoses the OFA disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\d+): error: ' - r'no matching function for call to \'Invoke\(' + regex = (_FILE_LINE_RE + r'error: no matching function for call to \'Invoke\(' r'<unresolved overloaded function type>') - 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 +251,10 @@ you should write something like def _OverloadedMethodActionDiagnoser1(msg): """Diagnoses the OMA disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\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 +272,10 @@ you should write something like def _MockObjectPointerDiagnoser(msg): """Diagnoses the MOP disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\d+): error: request for member ' + regex = (_FILE_LINE_RE + r'error: request for member ' r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', ' r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'') - 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 +301,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<file>.*):(?P<line>\d+): error: no matching function for ' + regex = (_FILE_LINE_RE + r'error: no matching function for ' r'call to \'Invoke\(.+, <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. @@ -299,9 +321,9 @@ you should write something like def _NeedToUseSymbolDiagnoser(msg): """Diagnoses the NUS disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\d+): error: \'(?P<symbol>.+)\' ' + regex = (_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' ' 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 +337,10 @@ Did you forget to write def _NeedToUseReturnNullDiagnoser(msg): """Diagnoses the NRNULL disease, given the error messages by gcc.""" - regex = (r'(?P<file>.*):(?P<line>\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<type>.+\*)') - - 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).""" @@ -327,23 +348,90 @@ 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<T>, you +need to make it visible. One way to do it is: + + typedef typename Base<T>::%(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<type>.+)\' 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<type>.+)\' 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.""" - regex = (r'(?P<file>.*):(?P<line>\d+):\s+' + regex = (_FILE_LINE_RE + r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n' r'.*\n' - r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>' - ) - - diagnosis = """%(file)s:%(line)s: + r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\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', + return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro', 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<method>\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, @@ -357,7 +445,11 @@ _DIAGNOSERS = [ _OverloadedFunctionMatcherDiagnoser, _OverloadedMethodActionDiagnoser1, _OverloadedMethodActionDiagnoser2, + _TypeInTemplatedBaseDiagnoser1, + _TypeInTemplatedBaseDiagnoser2, + _TypeInTemplatedBaseDiagnoser3, _WrongMockMethodMacroDiagnoser, + _WrongParenPositionDiagnoser, ] diff --git a/testing/gmock/src/gmock-internal-utils.cc b/testing/gmock/src/gmock-internal-utils.cc index 735abce..0e693c7 100644 --- a/testing/gmock/src/gmock-internal-utils.cc +++ b/testing/gmock/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,30 +126,24 @@ 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); - 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. @@ -146,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/testing/gmock/src/gmock-printers.cc b/testing/gmock/src/gmock-printers.cc index e6d4001..922a7b2 100644 --- a/testing/gmock/src/gmock-printers.cc +++ b/testing/gmock/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/testing/gmock/src/gmock-spec-builders.cc b/testing/gmock/src/gmock-spec-builders.cc index 65a74b8..465e4d6 100644 --- a/testing/gmock/src/gmock-spec-builders.cc +++ b/testing/gmock/src/gmock-spec-builders.cc @@ -139,10 +139,10 @@ ThreadLocal<Sequence*> 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/testing/gmock/test/gmock-generated-actions_test.cc b/testing/gmock/test/gmock-generated-actions_test.cc index 84e5a41..d0b2ddc 100644 --- a/testing/gmock/test/gmock-generated-actions_test.cc +++ b/testing/gmock/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<string(const char*, const char*, const char*, const char*, const char*, const char*, const char*)> 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<string(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*)> 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<int(int, int, double, const string&)> 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<int(int, int, bool, int*)> a2 = Invoke(SumOfFirst2); @@ -321,7 +334,7 @@ TEST(InvokeTest, MethodWithUnusedParameters) { Foo foo; Action<int(string, bool, int, int)> 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<int(char, double, int, int)> 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<string(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*)> 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<const char*(const char* s, double x, int n)> 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<string(const char*, const char*, double, const char*, const char*)> 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<string(const char*, const char*, const char*, const char*, const char*)> 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<string(const char*, const char*, const char*)> 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<string(const char*, const char*, const char*, const char*)> 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<string(const char*, const char*, const char*, const char*)> 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<string(const char*, const char*, const char*, const char*)> 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<string(const char*, const char*, const char*, const char*)> 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<int(int, int)> { // NOLINT TEST(WithArgsTest, NonInvokeAction) { Action<int(const string&, int, int)> 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<const char*(short n, const char* input)> 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<const char*(bool, const char*)> 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<std::string(const char*)> promo = PadArgument("foo", static_cast<int>('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<void(bool, int, int, const char*, bool, int, int, int, int, DeletionTester*)> 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/testing/gmock/test/gmock-generated-matchers_test.cc b/testing/gmock/test/gmock-generated-matchers_test.cc index 669652b..19024d0 100644 --- a/testing/gmock/test/gmock-generated-matchers_test.cc +++ b/testing/gmock/test/gmock-generated-matchers_test.cc @@ -53,13 +53,18 @@ 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; using testing::Eq; using testing::Ge; using testing::Gt; +using testing::Lt; using testing::MakeMatcher; using testing::Matcher; using testing::MatcherInterface; @@ -69,6 +74,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. @@ -95,6 +101,107 @@ string Explain(const MatcherType& m, const Value& x) { return ss.str(); } +// Tests Args<k0, ..., kn>(m). + +TEST(ArgsTest, AcceptsZeroTemplateArg) { + const tuple<int, bool> t(5, true); + EXPECT_THAT(t, Args<>(Eq(tuple<>()))); + EXPECT_THAT(t, Not(Args<>(Ne(tuple<>())))); +} + +TEST(ArgsTest, AcceptsOneTemplateArg) { + const tuple<int, bool> 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<short, int, long> 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<short, int, long> 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<short, int, long> 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<short, int, long, int> 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<char, int, int> Tuple3; + const Matcher<Tuple3> 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<char, char, int> Tuple3; + const Matcher<const Tuple3&> 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<RawTuple>::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<tuple<int, bool, char> > 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<const tuple<int, bool, char, int>&> 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<tuple<int, char> > 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<int> { public: @@ -330,6 +437,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<int*, size_t> 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(_, _)) + .With(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 +519,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 +594,23 @@ namespace matcher_test { MATCHER(IsOdd, "") { return (arg % 2) != 0; } } // namespace matcher_test -TEST(MatcherTest, WorksInNamespace) { +TEST(MatcherMacroTest, WorksInNamespace) { Matcher<int> 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 +904,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<int>(Value(arg, m1)) + + static_cast<int>(Value(arg, m2)) + static_cast<int>(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<int> 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<string> another_list; another_list.push_back("fee"); @@ -771,8 +950,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<const char*> another_set; @@ -780,7 +959,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 +974,20 @@ TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { } TEST(ContainsTest, DescribesItselfCorrectly) { + const int a[2] = { 1, 2 }; + Matcher<const int(&)[2]> m = Contains(2); + EXPECT_EQ("element 1 matches", Explain(m, a)); + + m = Contains(3); + EXPECT_EQ("", Explain(m, a)); +} + +TEST(ContainsTest, ExplainsMatchResultCorrectly) { Matcher<vector<int> > m = Contains(1); - EXPECT_EQ("contains 1", Describe(m)); + EXPECT_EQ("contains at least one element that is equal to 1", Describe(m)); + + Matcher<vector<int> > m2 = Not(m); + EXPECT_EQ("doesn't contain any element that is equal to 1", Describe(m2)); } TEST(ContainsTest, MapMatchesWhenElementIsInContainer) { @@ -823,7 +1014,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 +1022,25 @@ 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 }; + 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) { + 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/testing/gmock/test/gmock-internal-utils_test.cc b/testing/gmock/test/gmock-internal-utils_test.cc index 5e4dc03..9ab15af 100644 --- a/testing/gmock/test/gmock-internal-utils_test.cc +++ b/testing/gmock/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<int, RemoveConst<const int>::type>(); + CompileAssertTypesEqual<char[2], RemoveConst<const char[2]>::type>(); + CompileAssertTypesEqual<char[2][3], RemoveConst<const char[2][3]>::type>(); } // Tests GMOCK_REMOVE_CONST_. @@ -494,6 +497,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 @@ -693,6 +724,236 @@ 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<int> na(a, 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<int> na(make_tuple(p, 3U), kReference); + EXPECT_EQ(a, na.begin()); + + const linked_ptr<char> b(new char); + *b = 'a'; + // Tests with a smart pointer. + NativeArray<char> 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<int> 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<char, NativeArray<char>::value_type>(); + StaticAssertTypeEq<int[2], NativeArray<int[2]>::value_type>(); + + StaticAssertTypeEq<const char*, NativeArray<char>::const_iterator>(); + StaticAssertTypeEq<const bool(*)[2], NativeArray<bool[2]>::const_iterator>(); +} + +TEST(NativeArrayTest, MethodsWork) { + const int a[] = { 0, 1, 2 }; + NativeArray<int> na(a, kCopy); + ASSERT_EQ(3, na.size()); + EXPECT_EQ(3, na.end() - na.begin()); + + NativeArray<int>::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<int> 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<int>(b1, kReference)))); + EXPECT_THAT(na, Not(Eq(NativeArray<int>(b2, kCopy)))); +} + +TEST(NativeArrayTest, WorksForTwoDimensionalArray) { + const char a[2][3] = { "hi", "lo" }; + NativeArray<char[3]> na(a, kReference); + ASSERT_EQ(2, na.size()); + EXPECT_EQ(a, na.begin()); +} + +// Tests StlContainerView. + +TEST(StlContainerViewTest, WorksForStlContainer) { + StaticAssertTypeEq<std::vector<int>, + StlContainerView<std::vector<int> >::type>(); + StaticAssertTypeEq<const std::vector<double>&, + StlContainerView<std::vector<double> >::const_reference>(); + + typedef std::vector<char> Chars; + Chars v1; + const Chars& v2(StlContainerView<Chars>::ConstReference(v1)); + EXPECT_EQ(&v1, &v2); + + v1.push_back('a'); + Chars v3 = StlContainerView<Chars>::Copy(v1); + EXPECT_THAT(v3, Eq(v3)); +} + +TEST(StlContainerViewTest, WorksForStaticNativeArray) { + StaticAssertTypeEq<NativeArray<int>, + StlContainerView<int[3]>::type>(); + StaticAssertTypeEq<NativeArray<double>, + StlContainerView<const double[4]>::type>(); + StaticAssertTypeEq<NativeArray<char[3]>, + StlContainerView<const char[2][3]>::type>(); + + StaticAssertTypeEq<const NativeArray<int>, + StlContainerView<int[2]>::const_reference>(); + + int a1[3] = { 0, 1, 2 }; + NativeArray<int> a2 = StlContainerView<int[3]>::ConstReference(a1); + EXPECT_EQ(3, a2.size()); + EXPECT_EQ(a1, a2.begin()); + + const NativeArray<int> a3 = StlContainerView<int[3]>::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<NativeArray<int>, + StlContainerView<tuple<const int*, size_t> >::type>(); + StaticAssertTypeEq<NativeArray<double>, + StlContainerView<tuple<linked_ptr<double>, int> >::type>(); + + StaticAssertTypeEq<const NativeArray<int>, + StlContainerView<tuple<const int*, int> >::const_reference>(); + + int a1[3] = { 0, 1, 2 }; + const int* const p1 = a1; + NativeArray<int> a2 = StlContainerView<tuple<const int*, int> >:: + ConstReference(make_tuple(p1, 3)); + EXPECT_EQ(3, a2.size()); + EXPECT_EQ(a1, a2.begin()); + + const NativeArray<int> a3 = StlContainerView<tuple<int*, size_t> >:: + Copy(make_tuple(static_cast<int*>(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/testing/gmock/test/gmock-matchers_test.cc b/testing/gmock/test/gmock-matchers_test.cc index e770901..3541eef 100644 --- a/testing/gmock/test/gmock-matchers_test.cc +++ b/testing/gmock/test/gmock-matchers_test.cc @@ -60,7 +60,9 @@ 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::AllArgs; using testing::AllOf; using testing::An; using testing::AnyOf; @@ -98,6 +100,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; @@ -1333,7 +1336,7 @@ TEST(Eq2Test, MatchesEqualArguments) { // Tests that Eq() describes itself properly. TEST(Eq2Test, CanDescribeSelf) { Matcher<const Tuple2&> 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 @@ -1348,8 +1351,7 @@ TEST(Ge2Test, MatchesGreaterThanOrEqualArguments) { // Tests that Ge() describes itself properly. TEST(Ge2Test, CanDescribeSelf) { Matcher<const Tuple2&> 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 @@ -1364,7 +1366,7 @@ TEST(Gt2Test, MatchesGreaterThanArguments) { // Tests that Gt() describes itself properly. TEST(Gt2Test, CanDescribeSelf) { Matcher<const Tuple2&> 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 @@ -1379,8 +1381,7 @@ TEST(Le2Test, MatchesLessThanOrEqualArguments) { // Tests that Le() describes itself properly. TEST(Le2Test, CanDescribeSelf) { Matcher<const Tuple2&> 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 @@ -1395,7 +1396,7 @@ TEST(Lt2Test, MatchesLessThanArguments) { // Tests that Lt() describes itself properly. TEST(Lt2Test, CanDescribeSelf) { Matcher<const Tuple2&> 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 @@ -1410,7 +1411,7 @@ TEST(Ne2Test, MatchesUnequalArguments) { // Tests that Ne() describes itself properly. TEST(Ne2Test, CanDescribeSelf) { Matcher<const Tuple2&> 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. @@ -1670,6 +1671,54 @@ 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<int> is_zero = Eq(0); + EXPECT_TRUE(Value(0, is_zero)); + EXPECT_FALSE(Value('a', is_zero)); + + int n = 0; + const Matcher<const int&> ref_n = Ref(n); + EXPECT_TRUE(Value(n, ref_n)); + 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) { @@ -2765,9 +2814,7 @@ TEST(ByRefTest, AllowsNotCopyableValueInMatchers) { // different element types. template <typename T> -class ContainerEqTest : public testing::Test { - public: -}; +class ContainerEqTest : public testing::Test {}; typedef testing::Types< std::set<int>, @@ -2901,6 +2948,60 @@ 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 }; + + 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(p1, 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<const std::string(&)[2][3]> m = ContainerEq(a2); + EXPECT_THAT(a1, m); + + a2[0][0] = "ha"; + EXPECT_THAT(a1, m); +} + // Tests GetParamIndex(). TEST(GetParamIndexTest, WorksForEmptyParamList) { diff --git a/testing/gmock/test/gmock-printers_test.cc b/testing/gmock/test/gmock-printers_test.cc index 29a0db8..8c03ec4 100644 --- a/testing/gmock/test/gmock-printers_test.cc +++ b/testing/gmock/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 @@ -485,75 +488,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 <typename T, size_t N> +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. @@ -803,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<int> b(a, kReference); + EXPECT_EQ("{ 1, 2, 3 }", Print(b)); +} + +TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { + const int a[][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + NativeArray<int[3]> b(a, kReference); + EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); +} // Tests printing tuples. @@ -995,6 +992,11 @@ TEST(PrintToStringTest, WorksForReference) { UniversalPrinter<const int&>::PrintToString(n)); } +TEST(PrintToStringTest, WorksForArray) { + int n[3] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3 }", UniversalPrinter<int[3]>::PrintToString(n)); +} + TEST(UniversalTersePrintTest, WorksForNonReference) { ::std::stringstream ss; UniversalTersePrint(123, &ss); @@ -1025,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<char*>(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()); diff --git a/testing/gmock/test/gmock-spec-builders_test.cc b/testing/gmock/test/gmock-spec-builders_test.cc index e8c3902..058d343c 100644 --- a/testing/gmock/test/gmock-spec-builders_test.cc +++ b/testing/gmock/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,25 @@ 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()"); } #if GTEST_HAS_DEATH_TEST @@ -237,47 +239,44 @@ 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); } @@ -1612,6 +1611,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); diff --git a/testing/gmock/test/gmock_link_test.h b/testing/gmock/test/gmock_link_test.h index 4e0adb7..b903f3c 100644 --- a/testing/gmock/test/gmock_link_test.h +++ b/testing/gmock/test/gmock_link_test.h @@ -120,6 +120,7 @@ #include <errno.h> #endif +#include <gmock/internal/gmock-port.h> #include <gtest/gtest.h> #include <iostream> #include <vector> diff --git a/testing/gmock/test/gmock_output_test_.cc b/testing/gmock/test/gmock_output_test_.cc index 97619af..8244f10 100644 --- a/testing/gmock/test/gmock_output_test_.cc +++ b/testing/gmock/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/testing/gmock/test/gmock_output_test_golden.txt b/testing/gmock/test/gmock_output_test_golden.txt index 887b7be..aeec660 100644 --- a/testing/gmock/test/gmock_output_test_golden.txt +++ b/testing/gmock/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. @@ -183,12 +183,12 @@ 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 -[ RUN ] GMockOutputTest.MismatchArgumentsAndWithArguments +[ FAILED ] GMockOutputTest.MismatchWith +[ RUN ] GMockOutputTest.MismatchArgumentsAndWith unknown file: Failure Unexpected mock function call - returning default value. @@ -199,11 +199,11 @@ 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 +[ 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 diff --git a/testing/gtest.gyp b/testing/gtest.gyp index 061667e..e9d15f5 100644 --- a/testing/gtest.gyp +++ b/testing/gtest.gyp @@ -12,15 +12,7 @@ 'type': '<(library)', 'msvs_guid': 'BFE8E2A7-3B3B-43B0-A994-3058B852DB8B', 'sources': [ - 'gtest/include/gtest/internal/gtest-death-test-internal.h', - 'gtest/include/gtest/internal/gtest-filepath.h', - 'gtest/include/gtest/internal/gtest-internal.h', - 'gtest/include/gtest/internal/gtest-linked_ptr.h', - 'gtest/include/gtest/internal/gtest-param-util-generated.h', - 'gtest/include/gtest/internal/gtest-param-util.h', - 'gtest/include/gtest/internal/gtest-port.h', - 'gtest/include/gtest/internal/gtest-string.h', - 'gtest/include/gtest/internal/gtest-type-util.h', + # Sources based on files in r267 of gmock. 'gtest/include/gtest/gtest-death-test.h', 'gtest/include/gtest/gtest-message.h', 'gtest/include/gtest/gtest-param-test.h', @@ -30,17 +22,31 @@ 'gtest/include/gtest/gtest.h', 'gtest/include/gtest/gtest_pred_impl.h', 'gtest/include/gtest/gtest_prod.h', - 'gtest/src/gtest-test-part.cc', - 'gtest/src/gtest-typed-test.cc', + 'gtest/include/gtest/internal/gtest-death-test-internal.h', + 'gtest/include/gtest/internal/gtest-filepath.h', + 'gtest/include/gtest/internal/gtest-internal.h', + 'gtest/include/gtest/internal/gtest-linked_ptr.h', + 'gtest/include/gtest/internal/gtest-param-util-generated.h', + 'gtest/include/gtest/internal/gtest-param-util.h', + 'gtest/include/gtest/internal/gtest-port.h', + 'gtest/include/gtest/internal/gtest-string.h', + 'gtest/include/gtest/internal/gtest-tuple.h', + 'gtest/include/gtest/internal/gtest-type-util.h', + 'gtest/src/gtest-all.cc', 'gtest/src/gtest-death-test.cc', 'gtest/src/gtest-filepath.cc', 'gtest/src/gtest-internal-inl.h', 'gtest/src/gtest-port.cc', + 'gtest/src/gtest-test-part.cc', + 'gtest/src/gtest-typed-test.cc', 'gtest/src/gtest.cc', 'multiprocess_func_list.cc', 'multiprocess_func_list.h', 'platform_test.h', ], + 'sources!': [ + 'gtest/src/gtest-all.cc', # Not needed by our build. + ], 'include_dirs': [ 'gtest', 'gtest/include', |