Commit 9413f2ff by zhanyong.wan

Avoids unnecessary printing of call into to internal buffers;

Made the universal value printer safer when printing char[]; Removed duplicated code in InvokeWith; Improved gmock_doctor.py.
parent 16cf4739
...@@ -580,6 +580,41 @@ class UniversalPrinter { ...@@ -580,6 +580,41 @@ class UniversalPrinter {
#endif // _MSC_VER #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]. // Implements printing an array type T[N].
template <typename T, size_t N> template <typename T, size_t N>
class UniversalPrinter<T[N]> { class UniversalPrinter<T[N]> {
...@@ -587,41 +622,13 @@ class UniversalPrinter<T[N]> { ...@@ -587,41 +622,13 @@ class UniversalPrinter<T[N]> {
// Prints the given array, omitting some elements when there are too // Prints the given array, omitting some elements when there are too
// many. // many.
static void Print(const T (&a)[N], ::std::ostream* os) { static void Print(const T (&a)[N], ::std::ostream* os) {
// Prints a char array as a C string. Note that we compare 'const UniversalPrintArray(a, N, os);
// 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 << " }";
}
} }
// A convenient wrapper for Print() that returns the print-out as a // A convenient wrapper for Print() that returns the print-out as a
// string. // string.
static string PrintToString(const T (&a)[N]) { static string PrintToString(const T (&a)[N]) {
::std::stringstream ss; return UniversalPrintArrayToString(a, N);
Print(a, &ss);
return ss.str();
} }
}; };
......
...@@ -438,6 +438,10 @@ const char kWarningVerbosity[] = "warning"; ...@@ -438,6 +438,10 @@ const char kWarningVerbosity[] = "warning";
// No logs are printed. // No logs are printed.
const char kErrorVerbosity[] = "error"; 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 // Prints the given message to stdout iff 'severity' >= the level
// specified by the --gmock_verbose flag. If stack_frames_to_skip >= // specified by the --gmock_verbose flag. If stack_frames_to_skip >=
// 0, also prints the stack trace excluding the top // 0, also prints the stack trace excluding the top
......
...@@ -101,6 +101,22 @@ FailureReporterInterface* GetFailureReporter() { ...@@ -101,6 +101,22 @@ FailureReporterInterface* GetFailureReporter() {
// Protects global resources (stdout in particular) used by Log(). // Protects global resources (stdout in particular) used by Log().
static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); 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 // Prints the given message to stdout iff 'severity' >= the level
// specified by the --gmock_verbose flag. If stack_frames_to_skip >= // specified by the --gmock_verbose flag. If stack_frames_to_skip >=
// 0, also prints the stack trace excluding the top // 0, also prints the stack trace excluding the top
...@@ -110,17 +126,8 @@ static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); ...@@ -110,17 +126,8 @@ static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
// conservative. // conservative.
void Log(LogSeverity severity, const string& message, void Log(LogSeverity severity, const string& message,
int stack_frames_to_skip) { int stack_frames_to_skip) {
if (GMOCK_FLAG(verbose) == kErrorVerbosity) { if (!LogIsVisible(severity))
// The user is not interested in logs.
return; 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. // Ensures that logs from different threads don't interleave.
MutexLock l(&g_log_mutex); MutexLock l(&g_log_mutex);
......
...@@ -242,6 +242,11 @@ static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { ...@@ -242,6 +242,11 @@ static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
*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. // Prints the given array of wide characters to the ostream.
// The array starts at *begin, the length is len, it may include L'\0' // The array starts at *begin, the length is len, it may include L'\0'
// characters and may not be null-terminated. // characters and may not be null-terminated.
......
...@@ -139,10 +139,10 @@ ThreadLocal<Sequence*> g_gmock_implicit_sequence; ...@@ -139,10 +139,10 @@ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
void ReportUninterestingCall(CallReaction reaction, const string& msg) { void ReportUninterestingCall(CallReaction reaction, const string& msg) {
switch (reaction) { switch (reaction) {
case ALLOW: case ALLOW:
Log(INFO, msg, 4); Log(INFO, msg, 3);
break; break;
case WARN: case WARN:
Log(WARNING, msg, 4); Log(WARNING, msg, 3);
break; break;
default: // FAIL default: // FAIL
Expect(false, NULL, -1, msg); Expect(false, NULL, -1, msg);
......
...@@ -494,6 +494,34 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) { ...@@ -494,6 +494,34 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) {
}, "Expectation failed"); }, "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. // TODO(wan@google.com): find a way to re-enable these tests.
#if 0 #if 0
......
...@@ -485,75 +485,58 @@ TEST(PrintPointerTest, MemberFunctionPointer) { ...@@ -485,75 +485,58 @@ TEST(PrintPointerTest, MemberFunctionPointer) {
// Tests printing C arrays. // Tests printing C arrays.
// One-dimensional array. // The difference between this and Print() is that it ensures that the
// argument is a reference to an array.
void ArrayHelper1(int (&a)[5]) { // NOLINT template <typename T, size_t N>
EXPECT_EQ("{ 1, 2, 3, 4, 5 }", Print(a)); string PrintArrayHelper(T (&a)[N]) {
return Print(a);
} }
// One-dimensional array.
TEST(PrintArrayTest, OneDimensionalArray) { TEST(PrintArrayTest, OneDimensionalArray) {
int a[5] = { 1, 2, 3, 4, 5 }; int a[5] = { 1, 2, 3, 4, 5 };
ArrayHelper1(a); EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a));
} }
// Two-dimensional array. // 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) { TEST(PrintArrayTest, TwoDimensionalArray) {
int a[2][5] = { int a[2][5] = {
{ 1, 2, 3, 4, 5 }, { 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 0 } { 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. // Array of const elements.
void ArrayHelper3(const bool (&a)[1]) { // NOLINT
EXPECT_EQ("{ false }", Print(a));
}
TEST(PrintArrayTest, ConstArray) { TEST(PrintArrayTest, ConstArray) {
const bool a[1] = { false }; const bool a[1] = { false };
ArrayHelper3(a); EXPECT_EQ("{ false }", PrintArrayHelper(a));
} }
// Char array. // Char array.
void ArrayHelper4(char (&a)[3]) { // NOLINT
EXPECT_EQ(PrintPointer(a) + " pointing to \"Hi\"", Print(a));
}
TEST(PrintArrayTest, CharArray) { TEST(PrintArrayTest, CharArray) {
char a[3] = "Hi"; // Array a contains '\0' in the middle and doesn't end with '\0'.
ArrayHelper4(a); char a[3] = { 'H', '\0', 'i' };
EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a));
} }
// Const char array. // Const char array.
void ArrayHelper5(const char (&a)[3]) { // NOLINT
EXPECT_EQ(Print(a), PrintPointer(a) + " pointing to \"Hi\"");
}
TEST(PrintArrayTest, ConstCharArray) { TEST(PrintArrayTest, ConstCharArray) {
const char a[3] = "Hi"; const char a[4] = "\0Hi";
ArrayHelper5(a); EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a));
} }
// Array of objects. // Array of objects.
TEST(PrintArrayTest, ObjectArray) { TEST(PrintArrayTest, ObjectArray) {
string a[3] = { "Hi", "Hello", "Ni hao" }; 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. // Array with many elements.
TEST(PrintArrayTest, BigArray) { TEST(PrintArrayTest, BigArray) {
int a[100] = { 1, 2, 3 }; int a[100] = { 1, 2, 3 };
EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", 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. // Tests printing ::string and ::std::string.
...@@ -995,6 +978,11 @@ TEST(PrintToStringTest, WorksForReference) { ...@@ -995,6 +978,11 @@ TEST(PrintToStringTest, WorksForReference) {
UniversalPrinter<const int&>::PrintToString(n)); 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) { TEST(UniversalTersePrintTest, WorksForNonReference) {
::std::stringstream ss; ::std::stringstream ss;
UniversalTersePrint(123, &ss); UniversalTersePrint(123, &ss);
......
...@@ -1612,6 +1612,53 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) { ...@@ -1612,6 +1612,53 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) {
#endif // 0 #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) { TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) {
MockA* a = new MockA; MockA* a = new MockA;
Mock::AllowLeak(a); Mock::AllowLeak(a);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment