From ce198ff8997775d63b802615ee0cea5886ab82ab Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 12 Feb 2009 01:34:27 +0000 Subject: [PATCH] Implements the MATCHER* macros. --- include/gmock/gmock-generated-matchers.h | 829 ++++++++++++++++++ include/gmock/gmock-generated-matchers.h.pump | 210 +++++ include/gmock/gmock-printers.h | 15 +- include/gmock/internal/gmock-internal-utils.h | 6 + src/gmock-internal-utils.cc | 24 + test/gmock-generated-matchers_test.cc | 338 +++++++ test/gmock-internal-utils_test.cc | 34 + test/gmock-printers_test.cc | 24 + 8 files changed, 1479 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 09ccc9c3..f8cbf49e 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -44,6 +44,14 @@ namespace testing { namespace internal { +// Generates a non-fatal failure iff 'description' is not a valid +// matcher description. +inline void ValidateMatcherDescription(const char* description) { + EXPECT_STREQ("", description) + << "The description string in a MATCHER*() macro must be \"\" " + "at this moment. We will implement custom description string soon."; +} + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -647,4 +655,825 @@ ElementsAreArray(const T (&array)[N]) { } // namespace testing +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. The syntax: +// +// MATCHER(name, description_string) { statements; } +// +// will define a matcher with the given name that executes the +// statements, which must return a bool to indicate if the match +// succeeds. For now, the description_string must be "", but we'll +// allow other values soon. Inside the statements, you can refer to +// the value being matched by 'arg', and refer to its type by +// 'arg_type'. For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to +// support multi-parameter matchers. +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// While it's tempting to always use the MATCHER* macros when defining +// a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher() instead, +// especially if you need to use the matcher a lot. While these +// approaches require more work, they give you more control on the +// types of the value being matched and the matcher parameters, which +// in general leads to better compiler error messages that pay off in +// the long run. They also allow overloading matchers based on +// parameter types (as opposed to just based on the number of +// parameters). +// +// CAVEAT: +// +// MATCHER*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using MATCHER*() inside +// a function. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'MATCHER' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +#define MATCHER(name, description)\ + class name##Matcher {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl() {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + }\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl());\ + }\ + name##Matcher() {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + };\ + inline name##Matcher name() {\ + return name##Matcher();\ + }\ + template \ + bool name##Matcher::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P(name, p0, description)\ + template \ + class name##MatcherP {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " ";\ + ::testing::internal::UniversalPrint(p0, os);\ + }\ + p0##_type p0;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0));\ + }\ + name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + };\ + template \ + inline name##MatcherP name(p0##_type p0) {\ + return name##MatcherP(p0);\ + }\ + template \ + template \ + bool name##MatcherP::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P2(name, p0, p1, description)\ + template \ + class name##MatcherP2 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1));\ + }\ + name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ + p1(gmock_p1) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + };\ + template \ + inline name##MatcherP2 name(p0##_type p0, \ + p1##_type p1) {\ + return name##MatcherP2(p0, p1);\ + }\ + template \ + template \ + bool name##MatcherP2::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P3(name, p0, p1, p2, description)\ + template \ + class name##MatcherP3 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2));\ + }\ + name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + };\ + template \ + inline name##MatcherP3 name(p0##_type p0, \ + p1##_type p1, p2##_type p2) {\ + return name##MatcherP3(p0, p1, p2);\ + }\ + template \ + template \ + bool name##MatcherP3::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P4(name, p0, p1, p2, p3, description)\ + template \ + class name##MatcherP4 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3));\ + }\ + name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + };\ + template \ + inline name##MatcherP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3) {\ + return name##MatcherP4(p0, \ + p1, p2, p3);\ + }\ + template \ + template \ + bool name##MatcherP4::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\ + template \ + class name##MatcherP5 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \ + p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3, p4));\ + }\ + name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, \ + p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + };\ + template \ + inline name##MatcherP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4) {\ + return name##MatcherP5(p0, p1, p2, p3, p4);\ + }\ + template \ + template \ + bool name##MatcherP5::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\ + template \ + class name##MatcherP6 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3, p4, p5));\ + }\ + name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + };\ + template \ + inline name##MatcherP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ + p3##_type p3, p4##_type p4, p5##_type p5) {\ + return name##MatcherP6(p0, p1, p2, p3, p4, p5);\ + }\ + template \ + template \ + bool name##MatcherP6::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\ + template \ + class name##MatcherP7 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3, p4, p5, p6));\ + }\ + name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ + p6(gmock_p6) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + };\ + template \ + inline name##MatcherP7 name(p0##_type p0, p1##_type p1, \ + p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6) {\ + return name##MatcherP7(p0, p1, p2, p3, p4, p5, p6);\ + }\ + template \ + template \ + bool name##MatcherP7::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\ + template \ + class name##MatcherP8 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \ + p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \ + p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p7, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3, p4, p5, p6, p7));\ + }\ + name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, \ + p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + };\ + template \ + inline name##MatcherP8 name(p0##_type p0, \ + p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ + p6##_type p6, p7##_type p7) {\ + return name##MatcherP8(p0, p1, p2, p3, p4, p5, \ + p6, p7);\ + }\ + template \ + template \ + bool name##MatcherP8::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\ + template \ + class name##MatcherP9 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p7, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p8, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3, p4, p5, p6, p7, p8));\ + }\ + name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ + p8(gmock_p8) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + };\ + template \ + inline name##MatcherP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ + p8##_type p8) {\ + return name##MatcherP9(p0, p1, p2, \ + p3, p4, p5, p6, p7, p8);\ + }\ + template \ + template \ + bool name##MatcherP9::\ + gmock_Impl::Matches(arg_type arg) const + +#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\ + template \ + class name##MatcherP10 {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ + p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ + p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ + p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ + p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ + *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p1, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p2, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p3, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p4, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p5, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p6, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p7, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p8, os);\ + *os << ", ";\ + ::testing::internal::UniversalPrint(p9, os);\ + *os << ")";\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl(p0, p1, \ + p2, p3, p4, p5, p6, p7, p8, p9));\ + }\ + name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \ + p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ + p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ + p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ + p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ + p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\ + p0##_type p0;\ + p1##_type p1;\ + p2##_type p2;\ + p3##_type p3;\ + p4##_type p4;\ + p5##_type p5;\ + p6##_type p6;\ + p7##_type p7;\ + p8##_type p8;\ + p9##_type p9;\ + };\ + template \ + inline name##MatcherP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ + p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ + p9##_type p9) {\ + return name##MatcherP10(p0, \ + p1, p2, p3, p4, p5, p6, p7, p8, p9);\ + }\ + template \ + template \ + bool name##MatcherP10::\ + gmock_Impl::Matches(arg_type arg) const + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index b45028ae..2a457aad 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -47,6 +47,14 @@ $var n = 10 $$ The maximum arity we support. namespace testing { namespace internal { +// Generates a non-fatal failure iff 'description' is not a valid +// matcher description. +inline void ValidateMatcherDescription(const char* description) { + EXPECT_STREQ("", description) + << "The description string in a MATCHER*() macro must be \"\" " + "at this moment. We will implement custom description string soon."; +} + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -300,4 +308,206 @@ ElementsAreArray(const T (&array)[N]) { } // namespace testing +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. The syntax: +// +// MATCHER(name, description_string) { statements; } +// +// will define a matcher with the given name that executes the +// statements, which must return a bool to indicate if the match +// succeeds. For now, the description_string must be "", but we'll +// allow other values soon. Inside the statements, you can refer to +// the value being matched by 'arg', and refer to its type by +// 'arg_type'. For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to +// support multi-parameter matchers. +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// While it's tempting to always use the MATCHER* macros when defining +// a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher() instead, +// especially if you need to use the matcher a lot. While these +// approaches require more work, they give you more control on the +// types of the value being matched and the matcher parameters, which +// in general leads to better compiler error messages that pay off in +// the long run. They also allow overloading matchers based on +// parameter types (as opposed to just based on the number of +// parameters). +// +// CAVEAT: +// +// MATCHER*() can only be used in a namespace scope. The reason is +// that C++ doesn't yet allow function-local types to be used to +// instantiate templates. The up-coming C++0x standard will fix this. +// Once that's done, we'll consider supporting using MATCHER*() inside +// a function. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'MATCHER' +// on http://code.google.com/p/googlemock/wiki/CookBook. + +$range i 0..n +$for i + +[[ +$var macro_name = [[$if i==0 [[MATCHER]] $elif i==1 [[MATCHER_P]] + $else [[MATCHER_P$i]]]] +$var class_name = [[name##Matcher[[$if i==0 [[]] $elif i==1 [[P]] + $else [[P$i]]]]]] +$range j 0..i-1 +$var template = [[$if i==0 [[]] $else [[ + + template <$for j, [[typename p$j##_type]]>\ +]]]] +$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] +$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] +$var params = [[$for j, [[p$j]]]] +$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] +$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] +$var param_field_decls = [[$for j +[[ + + p$j##_type p$j;\ +]]]] +$var param_field_decls2 = [[$for j +[[ + + p$j##_type p$j;\ +]]]] + +#define $macro_name(name$for j [[, p$j]], description)\$template + class $class_name {\ + public:\ + template \ + class gmock_Impl : public ::testing::MatcherInterface {\ + public:\ + [[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\ + virtual bool Matches(arg_type arg) const;\ + virtual void DescribeTo(::std::ostream* os) const {\ + *os << ::testing::internal::ConvertIdentifierNameToWords(#name);\ +[[$if i==1 [[ *os << " ";\ + ::testing::internal::UniversalPrint(p0, os);\ + +]] $elif i>=2 [[ *os << " (";\ + ::testing::internal::UniversalPrint(p0, os);\ +$range k 1..i-1 +$for k [[ + + *os << ", ";\ + ::testing::internal::UniversalPrint(p$k, os);\ +]] + + *os << ")";\ + +]]]] + }\$param_field_decls + };\ + template \ + operator ::testing::Matcher() const {\ + return ::testing::Matcher(new gmock_Impl($params));\ + }\ + $class_name($ctor_param_list)$inits {\ + ::testing::internal::ValidateMatcherDescription(description);\ + }\$param_field_decls2 + };\$template + inline $class_name$param_types name($param_types_and_names) {\ + return $class_name$param_types($params);\ + }\$template + template \ + bool $class_name$param_types::\ + gmock_Impl::Matches(arg_type arg) const +]] + + #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index 759aa347..5cd5f12e 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -44,9 +44,12 @@ // When T is a reference type, the address of the value is also // printed. // -// We also provide a convenient wrapper +// We also provide some convenient wrappers: // +// // Prints to a string. // string ::testing::internal::UniversalPrinter::PrintAsString(value); +// // Prints a value using its inferred type. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ @@ -585,6 +588,16 @@ class UniversalPrinter { #endif // _MSC_VER }; +// Prints a value using its inferred type. In particular, if the +// original type of the value is a reference, the *referenced* type +// (as opposed to the reference type) will be used, as C++ doesn't +// infer reference types. This is useful when you just want to know +// what the value is and don't care if it's a reference or not. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter::Print(value, os); +} + } // namespace internal } // namespace testing diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index bdc82882..9a74d546 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -63,6 +63,12 @@ namespace proto2 { class Message; } namespace testing { namespace internal { +// Converts an identifier name to a space-separated list of lower-case +// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is +// treated as one word. For example, both "FooBar123" and +// "foo_bar_123" are converted to "foo bar 123". +string ConvertIdentifierNameToWords(const char* id_name); + // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc index 58bc64e4..735abce5 100644 --- a/src/gmock-internal-utils.cc +++ b/src/gmock-internal-utils.cc @@ -37,6 +37,7 @@ #include +#include #include // NOLINT #include #include @@ -46,6 +47,29 @@ namespace testing { namespace internal { +// Converts an identifier name to a space-separated list of lower-case +// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is +// treated as one word. For example, both "FooBar123" and +// "foo_bar_123" are converted to "foo bar 123". +string ConvertIdentifierNameToWords(const char* id_name) { + string result; + char prev_char = '\0'; + for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) { + // We don't care about the current locale as the input is + // guaranteed to be a valid C++ identifier name. + const bool starts_new_word = isupper(*p) || + (!isalpha(prev_char) && islower(*p)) || + (!isdigit(prev_char) && isdigit(*p)); + + if (isalnum(*p)) { + if (starts_new_word && result != "") + result += ' '; + result += tolower(*p); + } + } + return result; +} + // This class reports Google Mock failures as Google Test failures. A // user can define another class in a similar fashion if he intends to // use Google Mock with a testing framework other than Google Test. diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 89b26caa..136ef5ce 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -40,6 +40,7 @@ #include #include +#include namespace { @@ -59,6 +60,7 @@ using testing::Ne; using testing::Not; using testing::Pointee; using testing::Ref; +using testing::StaticAssertTypeEq; using testing::StrEq; using testing::internal::string; @@ -370,4 +372,340 @@ TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); } +// Tests for the MATCHER*() macro family. + +// Tests that a simple MATCHER() definition works. + +MATCHER(IsEven, "") { return (arg % 2) == 0; } + +TEST(MatcherMacroTest, Works) { + const Matcher m = IsEven(); + EXPECT_TRUE(m.Matches(6)); + EXPECT_FALSE(m.Matches(7)); + + EXPECT_EQ("is even", Describe(m)); + EXPECT_EQ("not (is even)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 6)); + EXPECT_EQ("", Explain(m, 7)); +} + +// Tests that the description string supplied to MATCHER() must be +// empty. + +MATCHER(HasBadDescription, "not empty?") { + return true; +} + +TEST(MatcherMacroTest, + CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(HasBadDescription(), + "The description string in a MATCHER*() macro " + "must be \"\" at this moment"); +} + +// Tests that the body of MATCHER() can reference the type of the +// value being matched. + +MATCHER(IsEmptyString, "") { + StaticAssertTypeEq< ::std::string, arg_type>(); + return arg == ""; +} + +MATCHER(IsEmptyStringByRef, "") { + StaticAssertTypeEq(); + return arg == ""; +} + +TEST(MatcherMacroTest, CanReferenceArgType) { + const Matcher< ::std::string> m1 = IsEmptyString(); + EXPECT_TRUE(m1.Matches("")); + + const Matcher m2 = IsEmptyStringByRef(); + EXPECT_TRUE(m2.Matches("")); +} + +// Tests that MATCHER() can be used in a namespace. + +namespace matcher_test { +MATCHER(IsOdd, "") { return (arg % 2) != 0; } +} // namespace matcher_test + +TEST(MatcherTest, WorksInNamespace) { + Matcher m = matcher_test::IsOdd(); + EXPECT_FALSE(m.Matches(4)); + EXPECT_TRUE(m.Matches(5)); +} + +// Tests that a simple MATCHER_P() definition works. + +MATCHER_P(IsGreaterThan32And, n, "") { return arg > 32 && arg > n; } + +TEST(MatcherPMacroTest, Works) { + const Matcher m = IsGreaterThan32And(5); + EXPECT_TRUE(m.Matches(36)); + EXPECT_FALSE(m.Matches(5)); + + EXPECT_EQ("is greater than 32 and 5", Describe(m)); + EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36)); + EXPECT_EQ("", Explain(m, 5)); +} + +// Tests that the description string supplied to MATCHER_P() must be +// empty. + +MATCHER_P(HasBadDescription1, n, "not empty?") { + return arg > n; +} + +TEST(MatcherPMacroTest, + CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(HasBadDescription1(2), + "The description string in a MATCHER*() macro " + "must be \"\" at this moment"); +} + +// Tests that the description is calculated correctly from the matcher name. +MATCHER_P(_is_Greater_Than32and_, n, "") { return arg > 32 && arg > n; } + +TEST(MatcherPMacroTest, GeneratesCorrectDescription) { + const Matcher m = _is_Greater_Than32and_(5); + + EXPECT_EQ("is greater than 32 and 5", Describe(m)); + EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36)); + EXPECT_EQ("", Explain(m, 5)); +} + +// Tests that a MATCHER_P matcher can be explicitly instantiated with +// a reference parameter type. + +class UncopyableFoo { + public: + explicit UncopyableFoo(char value) : value_(value) {} + private: + UncopyableFoo(const UncopyableFoo&); + void operator=(const UncopyableFoo&); + + char value_; +}; + +MATCHER_P(ReferencesUncopyable, variable, "") { return &arg == &variable; } + +TEST(MatcherPMacroTest, WorksWhenExplicitlyInstantiatedWithReference) { + UncopyableFoo foo1('1'), foo2('2'); + const Matcher m = + ReferencesUncopyable(foo1); + + EXPECT_TRUE(m.Matches(foo1)); + EXPECT_FALSE(m.Matches(foo2)); + + // We don't want the address of the parameter printed, as most + // likely it will just annoy the user. If the address is + // interesting, the user should consider passing the parameter by + // pointer instead. + EXPECT_EQ("references uncopyable 1-byte object <31>", Describe(m)); +} + + +// Tests that the description string supplied to MATCHER_Pn() must be +// empty. + +MATCHER_P2(HasBadDescription2, m, n, "not empty?") { + return arg > m + n; +} + +TEST(MatcherPnMacroTest, + CreatingMatcherWithBadDescriptionGeneratesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(HasBadDescription2(3, 4), + "The description string in a MATCHER*() macro " + "must be \"\" at this moment"); +} + +// Tests that the body of MATCHER_Pn() can reference the parameter +// types. + +MATCHER_P3(ParamTypesAreIntLongAndChar, foo, bar, baz, "") { + StaticAssertTypeEq(); + StaticAssertTypeEq(); // NOLINT + StaticAssertTypeEq(); + return arg == 0; +} + +TEST(MatcherPnMacroTest, CanReferenceParamTypes) { + EXPECT_THAT(0, ParamTypesAreIntLongAndChar(10, 20L, 'a')); +} + +// Tests that a MATCHER_Pn matcher can be explicitly instantiated with +// reference parameter types. + +MATCHER_P2(ReferencesAnyOf, variable1, variable2, "") { + return &arg == &variable1 || &arg == &variable2; +} + +TEST(MatcherPnMacroTest, WorksWhenExplicitlyInstantiatedWithReferences) { + UncopyableFoo foo1('1'), foo2('2'), foo3('3'); + const Matcher m = + ReferencesAnyOf(foo1, foo2); + + EXPECT_TRUE(m.Matches(foo1)); + EXPECT_TRUE(m.Matches(foo2)); + EXPECT_FALSE(m.Matches(foo3)); +} + +TEST(MatcherPnMacroTest, + GeneratesCorretDescriptionWhenExplicitlyInstantiatedWithReferences) { + UncopyableFoo foo1('1'), foo2('2'); + const Matcher m = + ReferencesAnyOf(foo1, foo2); + + // We don't want the addresses of the parameters printed, as most + // likely they will just annoy the user. If the addresses are + // interesting, the user should consider passing the parameters by + // pointers instead. + EXPECT_EQ("references any of (1-byte object <31>, 1-byte object <32>)", + Describe(m)); +} + +// Tests that a simple MATCHER_P2() definition works. + +MATCHER_P2(IsNotInClosedRange, low, hi, "") { return arg < low || arg > hi; } + +TEST(MatcherPnMacroTest, Works) { + const Matcher m = IsNotInClosedRange(10, 20); // NOLINT + EXPECT_TRUE(m.Matches(36L)); + EXPECT_FALSE(m.Matches(15L)); + + EXPECT_EQ("is not in closed range (10, 20)", Describe(m)); + EXPECT_EQ("not (is not in closed range (10, 20))", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36L)); + EXPECT_EQ("", Explain(m, 15L)); +} + +// Tests that MATCHER*() definitions can be overloaded on the number +// of parameters; also tests MATCHER_Pn() where n >= 3. + +MATCHER(EqualsSumOf, "") { return arg == 0; } +MATCHER_P(EqualsSumOf, a, "") { return arg == a; } +MATCHER_P2(EqualsSumOf, a, b, "") { return arg == a + b; } +MATCHER_P3(EqualsSumOf, a, b, c, "") { return arg == a + b + c; } +MATCHER_P4(EqualsSumOf, a, b, c, d, "") { return arg == a + b + c + d; } +MATCHER_P5(EqualsSumOf, a, b, c, d, e, "") { return arg == a + b + c + d + e; } +MATCHER_P6(EqualsSumOf, a, b, c, d, e, f, "") { + return arg == a + b + c + d + e + f; +} +MATCHER_P7(EqualsSumOf, a, b, c, d, e, f, g, "") { + return arg == a + b + c + d + e + f + g; +} +MATCHER_P8(EqualsSumOf, a, b, c, d, e, f, g, h, "") { + return arg == a + b + c + d + e + f + g + h; +} +MATCHER_P9(EqualsSumOf, a, b, c, d, e, f, g, h, i, "") { + return arg == a + b + c + d + e + f + g + h + i; +} +MATCHER_P10(EqualsSumOf, a, b, c, d, e, f, g, h, i, j, "") { + return arg == a + b + c + d + e + f + g + h + i + j; +} + +TEST(MatcherPnMacroTest, CanBeOverloadedOnNumberOfParameters) { + EXPECT_THAT(0, EqualsSumOf()); + EXPECT_THAT(1, EqualsSumOf(1)); + EXPECT_THAT(12, EqualsSumOf(10, 2)); + EXPECT_THAT(123, EqualsSumOf(100, 20, 3)); + EXPECT_THAT(1234, EqualsSumOf(1000, 200, 30, 4)); + EXPECT_THAT(12345, EqualsSumOf(10000, 2000, 300, 40, 5)); + EXPECT_THAT("abcdef", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f')); + EXPECT_THAT("abcdefg", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g')); + EXPECT_THAT("abcdefgh", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h")); + EXPECT_THAT("abcdefghi", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i')); + EXPECT_THAT("abcdefghij", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i', ::std::string("j"))); + + EXPECT_THAT(1, Not(EqualsSumOf())); + EXPECT_THAT(-1, Not(EqualsSumOf(1))); + EXPECT_THAT(-12, Not(EqualsSumOf(10, 2))); + EXPECT_THAT(-123, Not(EqualsSumOf(100, 20, 3))); + EXPECT_THAT(-1234, Not(EqualsSumOf(1000, 200, 30, 4))); + EXPECT_THAT(-12345, Not(EqualsSumOf(10000, 2000, 300, 40, 5))); + EXPECT_THAT("abcdef ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f'))); + EXPECT_THAT("abcdefg ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', + 'g'))); + EXPECT_THAT("abcdefgh ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h"))); + EXPECT_THAT("abcdefghi ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i'))); + EXPECT_THAT("abcdefghij ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i', ::std::string("j")))); +} + +// Tests that a MATCHER_Pn() definition can be instantiated with any +// compatible parameter types. +TEST(MatcherPnMacroTest, WorksForDifferentParameterTypes) { + EXPECT_THAT(123, EqualsSumOf(100L, 20, static_cast(3))); + EXPECT_THAT("abcd", EqualsSumOf(::std::string("a"), "b", 'c', "d")); + + EXPECT_THAT(124, Not(EqualsSumOf(100L, 20, static_cast(3)))); + EXPECT_THAT("abcde", Not(EqualsSumOf(::std::string("a"), "b", 'c', "d"))); +} + +// Tests that the matcher body can promote the parameter types. + +MATCHER_P2(EqConcat, prefix, suffix, "") { + // The following lines promote the two parameters to desired types. + std::string prefix_str(prefix); + char suffix_char(suffix); + return arg == prefix_str + suffix_char; +} + +TEST(MatcherPnMacroTest, SimpleTypePromotion) { + Matcher no_promo = + EqConcat(std::string("foo"), 't'); + Matcher promo = + EqConcat("foo", static_cast('t')); + EXPECT_FALSE(no_promo.Matches("fool")); + EXPECT_FALSE(promo.Matches("fool")); + EXPECT_TRUE(no_promo.Matches("foot")); + EXPECT_TRUE(promo.Matches("foot")); +} + +// Verifies the type of a MATCHER*. + +TEST(MatcherPnMacroTest, TypesAreCorrect) { + // EqualsSumOf() must be assignable to a EqualsSumOfMatcher variable. + EqualsSumOfMatcher a0 = EqualsSumOf(); + + // EqualsSumOf(1) must be assignable to a EqualsSumOfMatcherP variable. + EqualsSumOfMatcherP a1 = EqualsSumOf(1); + + // EqualsSumOf(p1, ..., pk) must be assignable to a EqualsSumOfMatcherPk + // variable, and so on. + EqualsSumOfMatcherP2 a2 = EqualsSumOf(1, '2'); + EqualsSumOfMatcherP3 a3 = EqualsSumOf(1, 2, '3'); + EqualsSumOfMatcherP4 a4 = EqualsSumOf(1, 2, 3, '4'); + EqualsSumOfMatcherP5 a5 = + EqualsSumOf(1, 2, 3, 4, '5'); + EqualsSumOfMatcherP6 a6 = + EqualsSumOf(1, 2, 3, 4, 5, '6'); + EqualsSumOfMatcherP7 a7 = + EqualsSumOf(1, 2, 3, 4, 5, 6, '7'); + EqualsSumOfMatcherP8 a8 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, '8'); + EqualsSumOfMatcherP9 a9 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, '9'); + EqualsSumOfMatcherP10 a10 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); +} + } // namespace diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index 2a43caa9..2ea76b0e 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -50,6 +50,40 @@ namespace { using ::std::tr1::tuple; +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsNoWord) { + EXPECT_EQ("", ConvertIdentifierNameToWords("")); + EXPECT_EQ("", ConvertIdentifierNameToWords("_")); + EXPECT_EQ("", ConvertIdentifierNameToWords("__")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsDigits) { + EXPECT_EQ("1", ConvertIdentifierNameToWords("_1")); + EXPECT_EQ("2", ConvertIdentifierNameToWords("2_")); + EXPECT_EQ("34", ConvertIdentifierNameToWords("_34_")); + EXPECT_EQ("34 56", ConvertIdentifierNameToWords("_34_56")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContainsCamelCaseWords) { + EXPECT_EQ("a big word", ConvertIdentifierNameToWords("ABigWord")); + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("FooBar")); + EXPECT_EQ("foo", ConvertIdentifierNameToWords("Foo_")); + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("_Foo_Bar_")); + EXPECT_EQ("foo and bar", ConvertIdentifierNameToWords("_Foo__And_Bar")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameContains_SeparatedWords) { + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("foo_bar")); + EXPECT_EQ("foo", ConvertIdentifierNameToWords("_foo_")); + EXPECT_EQ("foo bar", ConvertIdentifierNameToWords("_foo_bar_")); + EXPECT_EQ("foo and bar", ConvertIdentifierNameToWords("_foo__and_bar")); +} + +TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameIsMixture) { + EXPECT_EQ("foo bar 123", ConvertIdentifierNameToWords("Foo_bar123")); + EXPECT_EQ("chapter 11 section 1", + ConvertIdentifierNameToWords("_Chapter11Section_1_")); +} + // Tests that CompileAssertTypesEqual compiles when the type arguments are // equal. TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 6254809b..8ce2b739 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -152,6 +152,7 @@ using ::std::tr1::make_tuple; using ::std::tr1::tuple; using ::std::vector; using ::testing::StartsWith; +using ::testing::internal::UniversalPrint; using ::testing::internal::UniversalPrinter; using ::testing::internal::string; @@ -980,5 +981,28 @@ TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + " " + Print(sizeof(p)) + "-byte object ")); } +TEST(PrintAsStringTest, WorksForNonReference) { + EXPECT_EQ("123", UniversalPrinter::PrintAsString(123)); +} + +TEST(PrintAsStringTest, WorksForReference) { + int n = 123; + EXPECT_EQ("@" + PrintPointer(&n) + " 123", + UniversalPrinter::PrintAsString(n)); +} + +TEST(UniversalPrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalPrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalPrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + } // namespace gmock_printers_test } // namespace testing